Java基础进阶_day02_(类的组合,继承,this与super关键字)

内容摘要:

  • 类的组合关系
  • 类的继承(重点)
  • 子父类间成员关系(重点)
  • 方法的重写(重点)
  • this与super关键字(重点)

1. 类的组合关系

类与类间存在三种关系:

组合:如果自定义类型A中的属性值的类型是另一个自定义类型B时,A与B之间就是组合关系.
继承:暂未学习
代理:暂未学习
案例:

// Person和Pet是组合关系
public class Person {
     String name;
Pet pet;
}
public class Pet {
     String name;
String color;
}

2. 类的继承

概念:

把多个类中相同的成员提取出来定义到一个独立的类中,然后让这些类和独立的类产生一个关系后,都能直接使用独立类中的成员,这个关系就是继承.

格式:

class 子类名 extends 父类名 {}
extends:代表继承的关键字

好处:

提高代码的复用性;
提高了代码的维护性(修改父类中方法,所有的子类均不用修改);
继承是多态的前提.

坏处:

增强了类与类间的耦合性(开发时遵循原则:低耦合,高内聚).

特点:

Java语言只支持单继承,不支持多继承;
Java语言支持多层继承,不支持循环继承.

何时使用继承:

采用假设法,继承遵循”is a”的原则(A类是B类的一种,才能使用继承).

注意事项:

子类只能访问父类中的非私有的成员(成员变量和成员方法);
不能为获取某一个功能而去继承一个类;
子类没有继承父类的构造方法,当可以通过super()调用父类的无参构造,super(参数)调用父类的有参构造.

案例:

package com.itheima.extendsreview;
/*
 * 继承案例
 */
public class ExtendsDemo {
    public static void main(String[] args) {
        // 创建子类对象,子类可以访问父类的非私有的成员
        Teacher t = new Teacher("张三", 16);
        t.age = 20;     // 可以访问父类非私有的成员变量
        //t.name = "李四";    // 子类不能访问父类的私有的成员变量
        t.setName("李四");    // 子类可以通过成员变量的公共的访问方法访问父类的私有成员变量
        t.showInfo();   // 子类可以访问父类的非私有的成员方法
        //t.work();     // 子类不能访问父类的非私有的成员方法
    }
}

class Person {
    private String name;
    public int age;
    public Person() {}
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
    // 公共的方法
    public void showInfo() {
        System.out.println(this.name + "..." + this.age);
    }
    // 私有的方法
    private void work() {
        System.out.println("我学习");
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}
class Teacher extends Person {
    // 子类不能继承父类的构造方法,构造方法是父类进行数据初始化的,
    // 如果子类继承后,子类没有对象的属性值,则有参构造会报错
    public Teacher() {}
    // 子类可以通过super关键字调用父类的构造方法,通过父类初始化属性值
    public Teacher(String name, int age) {
        super(name, age);
    }
}

3. 子父类间成员关系

类的组成:

成员变量
构造方法
成员变量

继承中成员变量关系:

1: 当子类的成员方法调用变量遵循就近原则(查询变量遵循的顺序):
本方法中局部变量–>本类中的成员变量–>父类的成员变量
2: 当子类的成员方法中局部变量,子类的成员变量,父类的成员变量三者同名时:
  该成员方法调用变量时:
  (1) 变量名:调用本方法中的局部变量;
  (2) this.变量名:调用本类中成员变量(this代表当前对象的引用);
  (3) super.变量名:调用父类中的成员变量(super代表父类存储空间的标识).

继承中构造方法的关系:

遵循规则:子类创建对象时,必须先将父类进行加载并进行初始化.
1:子类的每个构造方法的都默认调用父类的无参构造方法,即隐含super()语句,原因如下:
创建子类对象时需要先将父类进行初始化,子类才能获取父类的成员;
2:子类的构造方法可以同通过this(…)调用其他的构造方法,但至少有一个构造方法要调用父类的构造方法(父类需要进行初始化);
3:子父类构造方法执行顺序:可以看作是创建子类对象时调用子类的构造方法,子类构造方法执行过程中调用父类的构造方法(子类完成初始化前将父类进行初始化);
4:子类的构造方法的第一条有效语句必须是this(…)调用其他构造方法的语句,或者是super(…)调用父类构造方法的语句,二者只能出现一个;
5:当父类中没有空参构造时,需要通过调用父类的有参构造进行父类的初始化.

继承中成员方法的关系:

1:子类只能访问父类非私有的成员方法;
2:子类成员方法和父类非私有成员方法不同名时,这两个方法是不同的方法,子类均可访问;
3:子类成员方法和父类非私有成员方法同名时:
  (1):方法声明完全相同(返回值,参数列表):这两个方法是重写关系,子类方法将父类方法覆盖;
  (2):方法声明不完全相同[返回值不同,参数列表不同(参数个数,参数类型,类型对应的顺序)]:这两个方法是重载,子类均可访问;
4:子类成员方法和父类私有的成员方法同名时:这两个方法时各自类所独有,没有关系,子类不能访问父类的该成员方法.

案例:

package com.itheima.extendsreview;
/*
 * 继承体系中子父类的成员关系
 */
public class ExtendsDemo2 {
    public static void main(String[] args) {
        /*
         * 成员变量的关系
         */
        Son s = new Son();
        // A:子类的成员方法调用变量遵循就近原则
        // (查询变量定义的顺序):子类局部方法-->子类成员变量-->父类非私有成员变量
        s.show();   // 输出:age:1,age:10,age:20
        // B:当子类的成员方法中局部变量,子类的成员变量,父类的成员变量三者同名时:
        // 变量名:调用本方法中的局部变量
        // this.变量名:调用本类中成员变量(this代表当前对象的引用)
        // super.变量名:调用父类中的成员变量(super代表父类对象存储空间的标识)
        s.show2();  // 输出:age:1,age:11,age:22
        /*
         * 构造方法的关系
         * 遵循规则:子类创建对象时,必须先将父类进行加载并进行初始化.
         */
        // A:子类不能继承父类的构造方法
        // 子类不能继承父类的构造方法,构造方法是父类进行数据初始化的,
        // 如果子类继承后,子类没有对象的属性值,则有参构造会报错
        // B:子类的每一个构造方法都会默认的调用父类的无参构造方法
        Son ss = new Son(); // 输出:我是父类的空参构造,我是子类的空参构造
        // C:子类的构造方法可以同通过this(...)调用子类其他的构造方法,
        // 但至少有一个构造方法要调用父类的构造方法(父类需要进行初始化);
        // D:子类的构造方法的第一条有效语句必须是this(...)调用其他构造方法的语句,
        // 或者是super(...)调用父类构造方法的语句,二者只能出现一个;
        // E:当父类中没有空参构造时,子类需要显示的调用父类的有参构造进行父类的初始化.
        /*
         * 成员方法的关系:
         */
        // A:子类只能访问父类非私有的成员方法;
        // B:子类成员方法和父类非私有成员方法不同名时,这两个方法是不同的方法,子类均可访问;
        // C:子类成员方法和父类非私有成员方法同名时:
        // 方法声明完全相同(返回值,参数列表):这两个方法是重写关系,子类方法将父类方法覆盖;
        ss.show(); // 输出:age:1,age:10,age:20
        // 方法声明不完全相同[返回值不同,参数列表不同(参数个数,参数类型,类型对应的顺序)]:这两个方法是重载,子类均可访问;
        ss.show3(); // 输出:你好
        ss.show3("张三"); // 输出:name:张三
        // D:子类成员方法和父类私有的成员方法同名时:这两个方法时各自类所独有,没有关系,子类不能访问父类的该成员方法.
        // ss.work(); // 不能访问,私有的成员方法只能在本类中访问,测试类中不能访问
    }
}
class Father {
    private String name;
    public int age = 22;
    public int age2 = 20;
    public Father() {
        System.out.println("我是父类的空参构造");
    }
    public Father(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("我是父类的有参构造");
    }
    // 公共的方法
    public void showInfo() {
        System.out.println(this.name + "..." + this.age);
    }
    public void show() {
        System.out.println(this.name + "..." + this.age);
    }
    public void show3() {
        System.out.println("你好");
    }
    // 私有的方法
    private void work() {
        System.out.println("Father学习");
    }
}
class Son extends Father {
    public int age = 11;
    public int age1 = 10;
    public Son() {
        System.out.println("我是子类的空参构造");
    }
    public Son(int age) {
        this.age = age;
        System.out.println("我是子类的空参构造");
    }

    public void show() {
        int age = 1;
        System.out.println("age:"+age);
        System.out.println("age:"+age1);
        System.out.println("age:"+age2);
    }
    public void show2() {
        int age = 1;
        System.out.println("age:"+age);
        System.out.println("age:"+this.age);
        System.out.println("age:"+super.age);
    }
    public void show3(String name) {
        System.out.println("name:"+name);
    }
    // 私有的方法
    private void work() {
        System.out.println("Son学习");
    }
}

4. 方法的重写

概念:

子父类中出现了声明完全相同(方法名,返回值,参数列表)的方法,则称为子类成员方法重写(覆盖)了父类成员的方法.

特点:

1:方法重写的前提是存在继承关系的类;
2:子类重写父类的方法的修饰权限不能小于父类该方法的权限(public > 默认);
3:父类中私有成员方法不能被重写;
4:重写的方法一般加上@Override注解,该注解表示该方法必须是重写父类的方法,否则会报错.

作用:

1:可以在父类成员方法的功能基础上,增加自身的处理逻辑,增强父类该方法的功能(需要子类在重写该方法时首先调用父类的该方法);
2:覆盖父类该方法的所有逻辑,重新定义子类的处理逻辑,将父类的功能全部舍弃.

方法的重写与重载的区别:

1:重写(override):在两个存在继承关系的类中,方法声明完全相同;
2:重载(overload):在同一个类中,方法名相同,参数列表不同(参数个数,参数类型,类型对应的顺序),与返回值无关.

案例:

package com.itheima.extendsreview;
/*
 * 方法重写案例
 */
public class MethodOverrideDemo {
    public static void main(String[] args) {
        // A:可以在父类成员方法的功能基础上,增加自身的处理逻辑,增强父类该方法的功能(需要子类在重写该方法时首先调用父类的该方法);
        Cat c = new Cat();
        c.show1();  // 输出:Animal show1,Cat show1
        // B:覆盖父类该方法的所有逻辑,重新定义子类的处理逻辑,将父类的功能全部舍弃.
        c.show2();  // 输出:Cat show2
    }
}
class Animal {
    public void show1() {
        System.out.println("Animal show1");
    }
    public void show2() {
        System.out.println("Animal show2");
    }
    public final void show3() {
        System.out.println("Animal show3");
    }
}
class Cat extends Animal {
    // 报错,子类重写父类的方法的修饰权限不能小于父类该方法的权限(public > 默认);
    /*void show1() {
        System.out.println("Cat show1");
    }*/
    public void show1() {
        super.show1();
        System.out.println("Cat show1");
    }
    public void show2() {
        System.out.println("Cat show2");
    }
    // 报错,因为父类的show3()方法是final修饰,不能被重写
    /*public final void show3() {
        System.out.println("Cat show3");
    }*/
}

5. this与super关键字

this关键字:

是代表当前对象的引用;

super关键字:

代表父类存储空间在子类对象中标识,相当于对象的引用,但不是对象的引用;

注意事项:

子类构造方法中通过super调用父类的构造方法,只是表示子类创建对象完成前需要对父类进行初始化(表象),本质是在加载子类.class文件前先加载父类的.class文件,并且只是在子类对象空间(使用this标识)中为父类开辟了一块存储空间,这块空间使用super进行标识.

this与super的区别:

1: this是当前对象的引用,super只是父类存储空间的标识,在子类中调用super只是为父类初始化,不会创建父类对象,父类初始化的空间是在子类对象存储空间内;
2:访问成员变量:
  this.成员变量–>代表访问本类的成员变量
  super.成员变量–>代表访问父类非私有的成员变量
3:访问构造方法:
  this(…)–>代表访问本类的其他的构造方法
  super(…)–>代表访问父类的构造方法
4:访问成员方法:
  this.成员方法–>代表访问本类的成员方法
  super.成员方法–>代表访问父类非私有的成员方法

案例:

package com.itheima.extendsreview;
/*
 * this和super关键字的案例
 */
public class Z extends X {
    Y y = new Y();
    public Z() {
        super();
        System.out.print("Z");
    }
    // 主方法
    public static void main(String[] args) {
        new Z(); // 输出结果为:YXYZ
        // 结果分析:类的初始化是分层初始化的
        // 1.new Z()是创建Z的对象,创建Z对象前先加载父类X
        // 2.X类中定义了Y b = new Y(),则在加载X前,先加载类Y
        // 3.Y类中初始化时,调用无参构造方法,打印了"Y",Y类初始化完后返回到X类中
        // 4.X中的构造方法执行,打印了"X",X类初始化完后返回到Z类中
        // 5.Z类中定义Y y = new Y(),则进行Y类的初始化,打印"Y",然后执行Z类的构造,打印"Z"
    }
}
class X {
    Y b = new Y();
    public X() {
        System.out.print("X");
    }
}

class Y {
    public Y() {
        System.out.print("Y");
    }
}

你可能感兴趣的:(Java进阶)