继承、super、this、抽象类

1.1继承定义

  • 继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。子类可以直接
    访问父类中的非私有的属性和行为。

1.2 继承的好处

  1.  提高代码的复用性。
  2. 类与类之间产生了关系,是多态的前提。

1.3 继承的格式

 class 父类 {
...
}
class 子类 extends 父类 {
...
}


 1.4 父类不可被继承的内容

  • 构造方法子类不会继承
  1. 因为构造方法名和类名一致,父类和字节类名肯定不一样,所以父类的构造方法复制到子类中肯定用不了了
  • 父类的私有内容子类不能使用(私有只有本类能用)
  1. 父类中的私有成员变量,要提供get/set给子类用
public class Demo {
    public static void main(String[] args) {
        // 创建子类
        Zi z = new Zi();
        z.num1 = 10;
        // z.num2 = 20; // 父类的私有成员变量子类不能使用
        z.setNum2(20);
        z.getNum2();
        z.test01();
        // z.test02(); // 父类的私有成员方法子类不能使用
    }
}

class Fu {
    public Fu() {
    }
    int num1;
    private int num2;

    public int getNum2() {
        return num2;
    }

    public void setNum2(int num2) {
        this.num2 = num2;
    }

    public void test01() {
        System.out.println("test01");
    }
    private void test02() {
        System.out.println("test02");
    }
}
class Zi extends Fu {
    /*public Fu() {
    }*/
}

1.5 继承后的特点-成员变量

  • 成员变量重名(0.01%实际开发中一般不重名)
  1. 自己有用自己的,自己没有用父类的(就近原则):局部变量->本类成员变量->父类成员变量
  2. super表示父类的内容
  • 成员变量不重名(99.99%实际开发中一般不重名)
  1. 自己有用自己的,自己没有用父类的(就近原则)
public class Demo {
    public static void main(String[] args) {
       /* Zi1 z1 = new Zi1();
        System.out.println(z1.num2); // 200
        System.out.println(z1.num1); // 10*/

        Zi2 z2 = new Zi2();
        z2.test();
    }
}

// ------------------成员变量重名(0.01%)----------------------
// 自己有用自己的,自己没有用父类的(就近原则) : 局部变量 -> 本类成员变量 -> 父类成员变量
// super表示父类的内容
class Fu2 {
    int num3 = 30;
}

class Zi2 extends Fu2 {
    int num3 = 400;

    public void test() {
        int num3 = 5000;
        System.out.println(num3); // 5000
        System.out.println(this.num3); // 400
        System.out.println(super.num3); // 30
    }
}


// ------------成员变量不重名(99.99%)----------
// 自己有用自己的,自己没有用父类的(就近原则)
class Fu1 {
    int num1 = 10;
}

class Zi1 extends Fu1 {
    int num2 = 200;
}

 1.6 继承后的特点-成员方法

  • 当有了继承后,不管是成员变量还是成员方法,都是就近原则(自己有的用自己的,自己没有用父类的)
public class Demo{
    public static void main(String[] args) {
//        Zi1 z1 = new Zi1();
//        z1.test01(); // Fu1 test01
//        z1.test02(); // Zi1 test02

        Zi2 z2 = new Zi2();
        z2.test03(); // Zi2 test03
    }
}

// ----------------成员方法重名(很少数)----------------------
// 自己有就用自己的,自己没有就用父类的(就近原则)
class Fu2 {
    public void test03() {
        System.out.println("Fu2 test03");
    }
}

class Zi2 extends Fu2 {
    public void test03() {
        System.out.println("Zi2 test03");
    }
}


// ----------------成员方法不重名(大多数)----------------------
// 自己有就用自己的,自己没有就用父类的(就近原则)
class Fu1 {
    public void test01() {
        System.out.println("Fu1 test01");
    }
}

class Zi1 extends Fu1 {
    public void test02() {
        System.out.println("Zi1 test02");
    }
}

2.1方法重写

  • 回顾方法重载(overload):同一个类中,方法名相同,参数列表不同
  • 方法重写(override):子类中的方法和父类的方法重名
  • 什么时候使用方法重写:子类和父类具有相同的功能,但是子类的功能比父类的功能更加强大,就使用方法的重写。
  • 方法重写注意事项:
  1. 是子类和父类之间的事情
  2. 方法名要相同
  3. 参数列表要相同
  4. 返回值类型要相同
  5. 子类方法的权限要大于等于父类方法的权限
  • 四个权限:public  > protected > 默认的  >private
public class Demo{
    public static void main(String[] args) {
        NewPhone np = new NewPhone();
        np.sendMessage();
        np.call();
        np.callDispaly();
    }
}

/*
1. 老手机:
    发短信
    打电话
    来电显示(显示来电号码)

2. 智能手机:
    发短信
    打电话
    来电显示(显示来电号码,显示来电姓名,显示头像)
 */
class OldPhone {
    public void sendMessage() {
        System.out.println("发短信");
    }
    public void call() {
        System.out.println("打电话");
    }

    // 来电显示(显示来电号码)
    public void callDispaly() {
        System.out.println("显示来电号码");
    }
}

// 智能手机是由老手机发展过来的,发短信和打电话还是以前的功能,只不过来电显示功能更加强大了,所以我们用智能手机去继承老手机
class NewPhone extends OldPhone {
    // 新手机的来电显示比老手机的来电显示要强大,我们重新写过来电显示的方法
    @Override // 检测方法是不是重写方法
    public void callDispaly() {
        // 来电显示(显示来电号码,显示来电姓名,显示头像)
        super.callDispaly(); // 调用父类的方法
        System.out.println("显示来电姓名");
        System.out.println("显示头像");
    }
}

2.2 继承后的特点-构造方法

  • 回顾:一个类不写构造方法,默认赠送有一个无参构造
  • 当有了继承关系后:
  1. 子类所有的构造方法都会先调用到父类的无参构造
  • 为什么要走父类构造方法:
  1. 因为父类中可能有成员变量需要通过构造方法来赋值,所以先走父类的构造方法。
  • 为什么走父类无参构造:
  1. java在95年就设计好了,它不知道我们今天会有什么样的构造方法,但是默认有一个无参构造,所以就走无参构造
  • 子类的构造方法是如何去调用父类的无参构造:
  1. 在子类构造方法的第一行,默认有一个super();
  2. super():表示调用父类构造方法
  • 继承后标准构造方法写法:
  1. 子类的无参调用父类的无参构造。
  2. 子类的有参构造调用父类的有参构造,自己的成员变量自己赋值。

public class Person {
    private String name;
    private int age;

    public Person() {
        System.out.println("父类 Person无参构造");
    }

    public Person(String name, int age) {
        System.out.println("父类 Person有2个参数构造");
        this.name = name;
        this.age = age;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}




public class Demo {
    public static void main(String[] args) {
        /*
            父类 Person无参构造
            子类 无参构造
         */
        // Student s1 = new Student();

        /*
            父类 Person无参构造
            子类 有3个参数构造
         */
        Student s2 = new Student("lily", 18, 100);
    }
}




public class Student extends Person {
    private double score;
    // 1. 子类的无参调用父类的无参构造
    public Student() {
        super();
        System.out.println("子类 无参构造");
    }

    // 2. 子类的有参构造调用父类的有参构造,自己的成员变量自己赋值
    public Student(String name, int age, double score) {
        super(name, age); // 子类有参调用父类有参
        this.score = score; // 自己的成员变量自己赋值
        System.out.println("子类 有3个参数构造");
    }

    public double getScore() {
        return score;
    }

    public void setScore(double score) {
        this.score = score;
    }
}


2.3 this和super总结

  • this代表本类内容,super代表父类内容:
  •  this.num1       本类的成员变量
     super.num1      父类的成员变量

     this.eat();     本类的方法
     super.eat();    父类的方法

     this();         调用本类构造方法
     super();        调用父类的构造方法

     this();      只能放在构造方法第一行
     super();   只能放在构造方法第一行

  • super()和this()都只能放在构造方法第一行,构造方法第一行到底放什么?

  1. 默认是super();

  2. 子类的构造方法能够直接或间接调用到父类的构造方法即可。

2.4 继承的特点: 

  • 继承的特点:
  1. java中类只能单继承,一个类只有一个父类
  2. 一个类可以有多个子类
  3. 支持多层继承
  • 注意:
  1. 子类和父类是相对的概念
  2. 一个类没有继承父类,其实是继承Object类(超类)
//class Fu1 extends Object{}
class Fu1 {}
class Fu2 {}

class Zi1 extends Fu1 {}
// 1. Java中类只能单继承,一个类只有一个父类
// class Zi2 extends Fu1, Fu2 {}

// 2. 一个类可以有多个子类
class Zi2 extends Fu1 {}
class Zi3 extends Fu1 {}

// 3. 支持多层继承
class Sun extends Zi1 {}

public class Demo09 {
    public static void main(String[] args) {
        Fu1 f = new Fu1();
//        f.
    }
}

3.1 抽象方法和抽象类的定义

  • 普通方法格式:
    修饰符  返回值类型  方法名(参数列表){
        
    }  
  • abstract关键字:表示抽象
  • 抽象方法格式:修饰符   abstract  返回值类型    方法名(参数列表);
  • 和普通方法对比:
  1. 在返回值类型前面添加abstract
  2. 把方法体的{}换成分号;
  • 抽象方法需要放在抽象类中
  • 抽象类的格式:
    abstract class 类名{
        
    }
  • 抽象类就是在以前的标准类基础上增加了抽象方法。
  • 抽象方法没有方法体,是无法执行的。
  • 抽象类的使用步骤:
  1. 定义一个类继承抽象类。
  2. 重写抽象方法。
  3. 创建子类。
  • 父类中抽象的work方法是有必要存在的
  1. 如果父类不写抽象方法,子类也可以不写work方法,子类功能就缺失了
  2. 如果父类添加了抽象方法 ,强制子类要去重写这个方法,保存功能完整
public abstract class Employee {
    private String id;
    private String name;
    private double salary;

    public Employee() {
    }

    public Employee(String id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    // 抽象方法需要放在抽象类中
    // 抽象方法(工作)
    public abstract void work();

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}
//定义一个类继承抽象类
public class Cook extends Employee {
	//继承后标准构造方法写法:
     //1.子类的无参调用父类的无参构造。
    public Cook() {
    }
	//2.子类的有参构造调用父类的有参构造,自己的成员变量自己赋值。
    public Cook(String id, String name, double salary) {
        super(id, name, salary);
    }

    // 2. 重写抽象方法
    public void work() {
        System.out.println(getName() + "厨师炒菜多加点盐...");
    }
}
public class Waiter extends Employee {
    @Override
    public void work() {
        System.out.println("服务客人...");
    }
}
// 1. 定义一个类继承抽象类
public class Manager extends Employee {
    public Manager() {
        super();
    }

    public Manager(String id, String name, double salary) {
        super(id, name, salary);
    }

    // 2. 重写抽象方法
    public void work() {
        System.out.println(getName() + "经理管理其他人");
    }
}
public class Demo {
    public static void main(String[] args) {
        // 因为抽象方法没有代码,即使创建出了对象也无法调用抽象方法,所以不能创建对象
        /*Employee e = new Employee();
        e.work();*/

        // 3. 创建子类
        Manager m = new Manager("jl001", "Tony", 10000);
        m.work();

        Cook c = new Cook("cs002", "库克", 1);
        c.work();

        Waiter w = new Waiter();
        // w.work();
    }
}

4.1抽象类的特点总结

import java.awt.*;

/*
    了解
        1. 抽象类不能创建对象
        2. 抽象类中有构造方法,给抽象类中的成员变量赋值
        3. 抽象方法需要放在抽象类中,但是抽象类中可以没有抽象方法
        4. 子类需要重写抽象类中的所有方法, 如果只重写一部分还是抽象类
 */
// 抽象方法需要放在抽象类中
abstract class Fu {
    public abstract void work();
}

// 但是抽象类中可以没有抽象方法.让我们用子类
abstract class Zi {

}

// 4. 子类需要重写抽象类中的所有方法, 如果只重写一部分还是抽象类
abstract class Fu2 {
    public abstract void test01();
    public abstract void test02();
}
// 子类需要重写抽象类中的所有方法
class Zi2 extends Fu2 {
    public void test01() {

    }
    public void test02() {

    }
}

// 如果只重写一部分还是抽象类
abstract class Zi3 extends Fu2 {
    public void test01() {
        System.out.println("重写");
    }
    // 如果只重写部分抽象方法.另外的抽象方法还在, 需要放在抽象类中
}

public class Demo11 {
    public static void main(String[] args) {
//        Component
    }
}

猜你喜欢

转载自blog.csdn.net/Huangyuhua068/article/details/81708178