Java — 继承与多态

目录

Java — 继承

一.为什么要用继承?

二.继承的详细概念

三.继承的使用

四.父类成员访问

1.子类访问父类的成员变量

 2.子类访问父类的成员方法

 3.super关键字

五.子类的构造方法

子类如何使用构造方法

六.子类与父类中代码的执行顺序

Java —多态

一.多态的概念

二.多态的使用

1.实现多态需要的条件

2.向上转型和向下转型

3.重写

 4.重写和重载的区别


Java — 继承

一.为什么要用继承?

这里我们举一个例子:猫和狗,他们都是动物 

首先定义一个小狗类和一个小猫类

//小狗
class Dog {
    public String name;
    public int age;

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

    public void wangwnag() {
        System.out.println(name + "正在汪汪叫");
    }
}

//猫猫
class Cat {
    public String name;
    public int age;

    public void eat() {
        System.out.println(name+"正在吃饭!");
    }
    public void miaomaio() {
        System.out.println(name + "正在喵喵叫");
    }
}


//实例化对象
public class Test {
    public static void main(String[] args) {
       //实例化一个狗的对象 
        Dog dog = new Dog();
        dog.name = "坦克";
        dog.eat();
        dog.wangwnag();
       
      //实例化一个猫的对象
        Cat cat = new Cat();
        cat.name = "咪咪";
        cat.eat();
        cat.miaomaio();
    }
}

 写到这里,我们会发现这个代码会有很多相似重复的属性,比如小狗和小猫有 name,age,eat(),写起来很繁琐,这时我们就可以将这些共性给抽取出来,放在同一个类当中,即用继承的思想进行共性抽取,实现代码复用。

二.继承的详细概念

继承是一个对象获取父对象的所有属性和行为的机制。

继承作用:共性的抽取,实现代码复用

 我们将抽取的共性放到一个类中,即父类,一脚基类或者超类,然后由它的子类,也叫派生类,来继承父类的成员变量和方法,如下图:

Java — 继承与多态_第1张图片

继承以后子类会复用父类中的成员,从逻辑和业务上来说子类必须在自己的类中可以新加成员,体现出与父类的不同,虽然代码不会报错,但是体现不出写继承的意义。

三.继承的使用

首先我们将这些共性放在Animal中,定义一个Animal类

class Animal {
    public String name;
    public int age;

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

 这里小狗和小猫要继承Animal类中的变量和方法,我们需要采用以下的格式:

修饰符  子类类名  extends  父类 {

}

class Dog extends Animal {
    public void wangwnag() {//子类中新加的成员
        System.out.println(name + "正在汪汪叫");
    }
}

class Cat extends Animal {
    public void miaomaio() {//子类中新加的成员
        System.out.println(name + "正在喵喵叫");
    }
}

public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog();
        dog.name = "坦克";
        dog.eat();
        dog.wangwang();

        Cat cat = new Cat();
        cat.name = "咪咪";
        cat.eat();
        cat.miaomaio();
    }

}

注意:子类下面也可以有子类继承,也就是孙子类,比如中华田园犬可以继承狗类,但是我们希望继承一般不会超过三层

四.父类成员访问

1.子类访问父类的成员变量

1).当子类与父类的成员变量不同时,子类继承父类的成员变量

class Base {
    public int a;
    public int b;
}
class Derived extends Base {
    public int c = 9;

    public void func() {
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
    }
}
public class Test2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
    }

Java — 继承与多态_第2张图片

2).当子类与父类的成员变量相同时,优先访问子类,就近原则

class Base {
    public int c = 199;
}
class Derived extends Base {
    public int c = 9;

  public void func() {
     System.out.println(c);
    }
}
public class Test2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
    }

Java — 继承与多态_第3张图片

  

 2.子类访问父类的成员方法

1).当 子类的方法名与父类的方法名相同时,同成员变量,子类可以使用父类的成员方法。

class Base {
public void methodBase() {
        System.out.println("base");
    }
}
class Derived extends Base {
    public void methodDerived() {
        System.out.println("Derived");
    }
public void func() {
        //子类有拿子类的,子类没有拿父类
        methodDerived();
        methodBase();
}
}
public class Test2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
    }
}

2).当子类与父类的成员方法同名时,这时候和成员变量一样,都是用就近原则

class Base {
public void methodBase() {
        System.out.println("base");
    }
}
class Derived extends Base {
    public void methodBase() {
        System.out.println("Derived");
    }
public void func() {
        //子类有拿子类的,子类没有拿父类
        methodBase();
}
}
public class Test2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.func();
    }
}

Java — 继承与多态_第4张图片

 3.super关键字

如果方法名和变量名相同,子类会默认放任自己的成员变量和成员方法。

那么,如果我们想要访问父类中同名的成员方法和成员变量,这是只要我们加上super关键字。

我们将前面代码中提到过的同名的成员变量c和成员方法methodBase()前面加上super关键字, 

public void func() {
        super.methodBase();
        System.out.println(super.c);
}

这时输出访问的是父类的成员,结果如下:

Java — 继承与多态_第5张图片

注意:super/不能再静态方法当中使用。 

五.子类的构造方法

子类如何使用构造方法

子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        System.out.println("带有两个参数的构造方法");
    }
}
class Dog extends Animal {
    public Dog(String name, int age) {
        //显示调用父类的构造方法,帮助父类的成员变量初始化
        super(name,age);
    }
    public void wangwang() {
        System.out.println(name + "正在汪汪叫");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog = new Dog("小名",1);
        dog.wangwang();
}
}

Java — 继承与多态_第6张图片

注意:

1)因为先有父再有子,所以我们要先,造父类,在狗早子类对象的时候,我们要先调用基类的构造方法,将从基类继承下来的成员构造完整 ,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整 。

2)若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构造方法

3) 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的父类构造方法调用,否则编译失败。

5)在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。

5) super(...)只能在子类构造方法中出现一次,并且不能和this同时出现

六.子类与父类中代码的执行顺序

我们先编写几个代码块

class Animal {
     static {//父类静态方法
        System.out.println("Animal static{}");
     }

     {
        System.out.println("Animal{}");
     }

    public Animal() {父类的构造方法
        System.out.println("Animal()");
    }
}

class Dog extends Animal {
    static {//子类的静态方法
        System.out.println("Dog static()");
    }

    {
        System.out.println("Dog{}");
    }

    public Dog() {//子类的构造方法
        System.out.println("Dog()");
    }
}
public class Test {
    public static void main(String[] args) {
        Dog dog1 = new Dog();
    }
}

执行结果:

Java — 继承与多态_第7张图片

由此可见,代码的优先级:父类 > 子类,静态 >实例代码 > 构造 ,当时静态的只执行一次,如果实例化一个dog2,那么静态方法就不会再执行

Java —多态

一.多态的概念

通俗来说,就是多种形态,具体点就是去完成某个行为,当不同的对象去完成时会产生出不同 的状态,也就是,当父类引用 引用的对象不一样的时候,表现出的行为是不一样的

Java — 继承与多态_第8张图片

 

二.多态的使用

1.实现多态需要的条件

1)必须在继承体系下;

2)子类必须要对父类的方法进行重写;

3)通过父类的引用调用重写的方法。

2.向上转型和向下转型

向上转型:创建一个子类对象,将其当成父类对象来使用。

书写格式1.

父类类型 对象名 = new 子类类型()

//示例 
public static void main(String[] args) {  
        Animal animal1 = new Dog();
}

书写格式2

public static void 方法名(父类类型 对象名){} //方法的传参

//示例
public static void func(Animal animal){

    }

public static 父类类型 方法名(){ return new 子类类型()} //方法返回

//示例
public  static Animal func2() { 
        return new Dog();
    }

优点:让代码实现更简单灵活

缺点:不能调用到子类特有的方法


3.重写

重写是指子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写,子类可以根据需求重写父类中有的方法,比如狗和猫吃东西,狗吃狗粮,猫吃猫粮,我们就可以在继承中重写父类中的eat()方法,返回值和形参都不能改变。即外壳不变,核心重写。

在运行时main方法中会自动调用子类重写的方法,这种称为动态绑定。

class Animal {
    public String name;
    public int age;

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

class Dog extends Animal {
    public void wangawang(){
        System.out.println(name + "正在汪汪叫");
    }
    @override //重写方法的注释
    public void eat() { //重写
        System.out.println(name + "正在吃狗粮!");
    }
}
class Cat extends Animal {
    public void mew() {
        System.out.println(name + "喵喵叫");
    }
    @override  //重写方法的注释
    public void eat() {
        System.out.println(name + "正在吃猫粮");
    }
}
public class Test2 {
    public static void main(String[] args) {
        //向上转型
        Animal animal1 = new Dog();
        animal1.name = "旺财";
        animal1.eat();

        Animal animal2 = new Cat();
        animal2.name = "咪咪";
        animal2.eat();
    }
}

Java — 继承与多态_第9张图片

在这里我们用快捷方法生成重写:

Java — 继承与多态_第10张图片

 

Java — 继承与多态_第11张图片

 

Java — 继承与多态_第12张图片

 注意:

1)private修饰的方法不能被重写

2)static修饰的方法是不能重写的

3)子类的访问修饰限定权限要大于等于父类的权限(如果父类是private封装除外)

      默认 < protected < public 

4)被final修饰的方法是不能被重写的,这个方法是一个,密封方法,故而不能被重写        

 4.重写和重载的区别

Java — 继承与多态_第13张图片

你可能感兴趣的:(java,开发语言,jvm)