0
点赞
收藏
分享

微信扫一扫

第三篇:继承

mm_tang 2022-02-15 阅读 46

继承

继承

概述

继承:子类继承了父类的属性及行为,使得子类的对象具有父类相同的属性及行为
	 子类的对象是可以直接访问父类中的非私有的属性及行为

extends 表示继承
	可以申明一个类是从另一个类继承而来

继承的格式:
	class 父类 { }
	class 子类 extends 父类 { }

继承的关系式:is-a的关系,例 class 食肉动物 extends 动物 { }
	解析:食肉动物 是 动物 

补充:父类也称之为基类、超类

优缺点

优点

代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性
提高代码的可重用性及可维护性
提高代码的可扩展性,实现父类的方法就可以“为所欲为” (方法的重写)

缺点

继承是侵入性的。只要实现继承,就必须拥有父类的所有属性和方法
降低代码的灵活性。子类必须拥有父类的属性和方法,让子类自由的世界中多了些约束
增强代码的耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能带来非常糟糕的结果——大段的代码需要重构

代码演示:extends关键字基本使用

public class Test extends Person{
        //   子类   继承    父类
    public static void main(String[] args) {
        Test test = new Test();
        test.name = "ha";
        test.age = 30;
        // 虽然子类没有定义属性及行为,但可以直接给对象进行赋值,说明子类继承父类

        test.eat(test.name);
        System.out.println("个人信息是" + test.name + ",今年:" + test.age + "岁!");
    }
}
class Person {
    // 父类
    String name;
    int age;

    public void eat (String name) {
        System.out.println(name + "吃饭");
    }
}

继承关系中成员变量的访问特点

代码演示:继承关系中成员变量的访问特点

public class Test {
    public static void main(String[] args) {
        Fu fu = new Fu();
        System.out.println("父类的访问成员变量");
        System.out.println(fu.aFu); // 10
        System.out.println(fu.b);   // 20

        Zi zi = new Zi();
        System.out.println("子类的访问成员变量");
        System.out.println(zi.aFu);     // 10
        System.out.println(zi.aZi);     // 30
        System.out.println(zi.b);       // 40
        System.out.println(zi.getB());  //20
    }
}
class Fu {
    int aFu = 10;
    int b = 20;
    public int getB() {
        return b;
    }
}
class Zi extends Fu {
    int aZi = 30;
    int b = 40;
}

总结

父类的对象只能访问自己的成员变量
继承关系中:
子类可访问本类的成员变量及成员方法,父类的非私有化的成员变量及成员方法
若父子类中存在相同的成员变量,访问父类的成员变量,可通过间接的方式调用(getXxx方法)
若父子类中存在相同的成员方法,访问父类的成员方法,可通过间接的方式调用(将相同名的成员方法放置在另一个方法中)

方法重写

概述

方法重写:子类中的方法与父类中的某一方法具有相同的方法名、返回类型和参数表,则新方法将覆盖原有的方法

创建对象格式:父类  对象名  =  new 子类(); 	// 父类的引用指向子类的对象

方法重写的规则
	    1. 方法名、参数的类型和个数相同
	    2. 不能发生在同类中,只能发生在子类中
	    3. 子类的成员方法上面存在 @Override,表示方法重写
	    4. 返回值类型
	    		void/8种基本数据类型,父类的返回值类型保持一致
	    		当父类的成员方法的类型是父类引用类型时,返回值类型可以是父类,也可以是子类
				当父类的1成员方法的类型是子类引用类型时,返回值类型只能是子类
	    5.  修饰词
	    		 方法上不写修饰词,说明是默认的权限,只是将default修饰词隐藏罢了
	    		 子类的成员方法权限一定要大于等于父类的成员方法权限,但是“特殊情况除外”
	    		 	特殊情况:当父类的成员方法权限是public时,子类的成员方法权限也一定是public
	    		 			 当父类的成员方法权限是private时,子类无法进行重写
	    		 权限从大到小排序:
	    		 	public(公开的)> protected(受保护的)> 默认的(default> private(私有的)	    		 

代码演示:方法重写的注意事项

public class Test {
    public static void main(String[] args) {
        // Fu fu = new Fu();
        // Zi zi = new Zi();
        // 以上两种方式只能在本类中进行调用,无法通过父类调用子类的方法
        
        Fu t = new Zi();
        // 为了解决,父类调用子类的方法。通过继承关系,父类的对象调用子类的成员方法
        
        System.out.println(t.b);        // 20
        System.out.println(t.getB());   // 30
        // t.getB() 此处父类优先调用自己类的方法,但是又发现子类中有同名的方法,这时子类对父类的方法发生了覆盖(重写)
    }
}
class Fu {
    int b = 20;
    public int getB() {
        return b;
    }
}
class Zi extends Fu {
    int b = 30;
    public int getB() {
        return b;
    }
}

总结

特殊情况下,如果子类中没有重写方法,那么只能获取到父类的成员方法

代码演示:不同对象访问成员方法的运行结果

public class Demo {
    public static void main(String[] args) {
        Phone phone = new Phone();
        phone.call();
        phone.show();
        System.out.println("=========");

        NewPhone newPhone = new NewPhone();
        newPhone.call();
        newPhone.show();
        System.out.println("=========");

        Phone p = new NewPhone();   // 父类的引用指向子类的对象
        p.call();	// 当子类中没有重写方法,访问的父类中的成员方法
        p.show();	// 当子类中发生重写方法,访问的子类中的成员方法
    }
}
class NewPhone extends Phone {
    @Override   // 表示方法重写
    public void show() { 
        super.show();   // super 表示父类
        // 若出现上行代码,不仅调用了父类的show方法,说明在原先的方法中添加了其他方法体
        System.out.println("显示姓名");
        System.out.println("显示照片");
    }
}
class Phone {
    public void call() {
        System.out.println("打电话");
    }
    public void show() {
        System.out.println("显示电话号码");
    }
}

代码演示:成员方法返回值

public class Demo {
    public static void main(String[] args) {
        Phone p = new NewPhone();   // 父类的引用指向子类的对象
        p.show();
    }
}
class NewPhone extends Phone {
    @Override  
    public Phone show() {
        super.show();
        System.out.println("显示姓名");
        return new Phone();
    }
}
class Phone {
    public Phone show() {
        System.out.println("显示电话号码");
        return new NewPhone();
    }
}

总结

当父类的成员方法类型是父类时,那么子类重写方法的返回值类型可以是父类,也可以是子类
当父类的成员方法类型是子类时,那么子类重写方法的返回值类型只能是子类

小结:重写与重载的区别

程序先编译再运行
重写:遵循“运行期绑定”。重写考虑签名、修饰词,只有在程序运行,才能发现程序是否异常。
重载:遵循“编译期绑定”。在编译时,编译器就可以判断方法名是否相同,若方法名相同,参数列表是否不同,若参数列表不同,则重载成立。

父子类构造方法的访问

代码演示:子类构造方法访问无参父类构造方法

public class Demo {
    public static void main(String[] args) {
        Student student = new Student();
        // 编译结果:先执行父类的构造方法的内容,再执行子类的构造方法的内容
    }
}
class Person {
    Person() {
        System.out.println("父类构造方法开始运行!");
    }
}
class Student extends Person {
    Student() {
    	super();	// 子类的构造方法中默认有一个父类的无参构造方法【super()】。可以可不写,但都会被执行
    				// (上行解析通俗的说:在构造子类的时候,优先构造父类)
    				// super调用构造方法,必须位于子类构造方法第一行
    				// 一个子类构造方法中,只能出现一个super
        System.out.println("子类构造方法开始运行!");
    }
}

代码演示:子类构造方法访问有参父类构造方法

public class Demo {
    public static void main(String[] args) {
        Student student = new Student();
    }
}
class Person {
    Person(int a) {
        System.out.println("父类构造方法开始运行!");
    }
}
class Student extends Person {
    Student() {
        super(20);	// 父类是有参构造方法,子类构造方法不能隐藏【super()】。必须要写
        System.out.println("子类构造方法开始运行!");
    }
}

Super 与 this 的三种用法

Super的三种用法

1. 在子类的构造方法中,访问父类的构造方法
2. 在子类的成员方法中,访问父类的成员变量
3. 在子类的成员方法中,访问父类的成员方法

代码演示:Super的三种用法

public class Demo {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method1();
        zi.run();
    }
}
class Fu {
    int i = 10;
    public Fu() {
        System.out.println("父类构造方法优先运行!");
    }
    void run() {
        System.out.println("爸爸做运动!!");
    }
}
class Zi extends Fu {
    int i = 20;
    // 1. 访问父类的构造方法
    public Zi() {
        super();
    }

    // 2. 访问父类的成员变量
    void method1() {
        System.out.println("访问父类成员变量i是" + super.i);
    }

    // 3. 访问父类的成员方法
    @Override
    void run() {
        System.out.println("这是子类的方法!");
        super.run();
    }
}

this的三种用法

1. 在本类的构造方法中,访问本类的构造方法【注意:多个构造方法间调用避免死循环现象】
2. 在本类的成员方法中,访问本类的成员变量
3. 在本类的成员方法中,访问本类其他的成员方法

代码演示:this的三种用法

public class Demo {
    public static void main(String[] args) {
        Zi zi = new Zi();
        zi.method2();
    }
}
class Fu {
    int i = 10;
    public Fu() {
        System.out.println("无参构造");
    }
    public Fu(int a) {
        this();     // 在本类的构造方法中,访问本类的构造方法
        // 错误的调用构造方法,Fu();
        System.out.println("有参构造");
    }
}
class Zi extends Fu {
    int i = 20;
    public void method1() {
        System.out.println("这是子类的成员方法!!");
    }
    public void method2() {
        System.out.println("本类的成员变量是" + this.i);    // 在本类的成员方法中,访问本类的成员变量
        this.method1(); // 在本类的成员方法中,访问本类其他的成员方法
    }
}

继承的三种特性

一个类只能有一个父类

【正确方式】
class A {}
class B extends A {}

【错误方式】
class A{}
class B extends A,C {}

一个父类有多个子类

【正确方式】
class A {}
class B extends A {}
class C extends A {}

多级继承

【正确方式】
class A {}		
class B extends A {}
class C extends B {}
举报

相关推荐

0 条评论