继承与多态 --- Java内功心法

目录

继承

继承的概念:

继承的好处:

父类成员的访问:

子类构造方法:

super与this:

super与this的不同点:

再谈构造方法:

Java中的多种继承方式:

final关键字:

类的组合:

多态

概念:

实现条件:

重写:

应该避免在构造函数里调用重写的方法:

向上转型:

向下转型:

多态的优缺点:


继承

继承的概念:

为什么要用到继承?

我们来看一下以下代码:

       如果我们要描述一个小猫类和一个小狗类,那么我们可以发现它们的很多属性是相同的,那么这时候代码就会比较冗余。

        那么要怎么把这些代码进行复用呢?这时候就可以用到继承了~~

这时候我们可以将Cat类和Dog类相同的部分写在Animal类里 

         我们借助了extends关键字来继承这个Animal类,Dog类和Cat类都继承这个Animal类,那么这两个类就拥有了自己类里的方法和属性以及Animal里的方法和属性。

        我们将形如Animal类称为父类(超类/基类),将形如Cat类和Dog类称为子类(派生类)

继承的好处:

        1.继承可以实现共性的抽取,代码的复用

父类成员的访问:

如果再代码中父类的变量名、方法名与子类的变量名、方法名相同,那我们会访问或者调用那个类的变量、方法呢?

class Base {
    public int a = 1;
    public int b = 2;//相同变量名

    public void menthod1() {//相同方法名
        System.out.println("Base类里的menthod1方法");
    }
}

class Derived extends Base {
    public int b = 3;//相同变量名
    public int c = 4;

    public void menthod1() {//相同方法名
        System.out.println("Derived类里的menthod1方法");
    }

    public void run() {
        menthod1();
        System.out.println("a = " + a);
        System.out.println("b = " + b);
        System.out.println("c = " + c);
    }
}

public class Main1 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        derived.run();
    }
}

那么以上的程序运行结果调用的会是子类的还是父类的呢?

 我们可以发现运行结果是调用子类的变量和方法。

那如果我们要调用父类的变量和方法呢?

这时候就要用到super关键字了。

 通过以上的例子不难发现如果在命名相同的情况下(其实命名不同也可以用)我们想要调用父类的变量或者方法,可以用使用super关键字,super关键字的作用就是再子类访问父类成员。

注意:super关键字只能在非静态方法中使用

子类构造方法:

        俗话说先有夫再有子,我们在构建子类的时候会先执行父类的构造函数

import java.util.SortedMap;

class Base {
    public  Base() {
        System.out.println("父类Base的构造函数");
    }
}

class Derived extends Base{
    public  Derived() {
        System.out.println("子类Derived的构造函数");
    }
}

public class Main2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
    }
}

 为什么会先执行父类的构造函数再执行子类的构造函数呢?原因是我们的子类是由两部分组成的,第一部分是从父类继承下来的,第二部分是自己新增的,所以在构建子类的时候肯定要先执行父类的构造函数,使自己第一部分完整,然后再调用子类自己的构造方法,是自己新增的成员初始化完整。

super与this:

super与this的相同点:

1.都只能存在于非静态方法,但是可以访问静态成员变量和方法。(但是不推荐这样做,静态变量和方法最好直接使用类名调用)

class Base {
    public static int b = 1;
    public  Base() {
        System.out.println("父类Base的构造函数");
    }
    
    public static void menthod() {
        
    }
}

class Derived extends Base{
    public static int c = 2;
    public  Derived() {
        super.b = 3;
        this.c = 4;
        
        super.menthod();
        this.menthod();
        
        System.out.println("子类Derived的构造函数");
    }

    public static void menthod() {

    }
}

super与this的不同点:

1.this关键字实际上就是对当前对象的引用,可以取到当前对象的方法和属性,super是在子类中从父类继承下来的方法和属性的引用

2.this(...)用来调用子类构造函数,super(...)用来调用父类构造函数,两个不能在同一个构造函数出现。

3.在子类的构造方法中一定会有super(...)的调用,this(...)不调用则没有

再谈构造方法:

当创建一个子类对象时,它里面构造的顺序是什么样的,我们通过代码和执行结果来看一下吧~~

import java.util.SortedMap;

class Base {
    public  Base() {//父类构造函数
        System.out.println("父类Base的构造函数");
    }

    static {
        System.out.println("父类的静态代码块");
    }

    {
        System.out.println("父类的实例代码块");
    }
}

class Derived extends Base{
    public  Derived() {//子类构造函数
        System.out.println("子类Derived的构造函数");
    }
    static {
        System.out.println("子类的静态代码块");
    }

    {
        System.out.println("子类的实例代码块");
    }
}

public class Main2 {
    public static void main(String[] args) {
        Derived derived = new Derived();
        System.out.println("----------");
        System.out.println("再实例化一个对象: ");
        Derived derived1 = new Derived();
    }
}

执行结果:

 从执行结果不难看出在创建一个子类对象的时候,它的构造执行顺序如下:

父类静态代码块->子类静态代码块->父类实例代码块->父类构造函数->子类实例代码块->子类构造函数

如果再创建一个子类,那静态代码块不再被执行,因为静态代码块只会执行一次

Java中的多种继承方式:

1.单继承

class A {
    
}

class B extends A {
    
}

2.多层继承

class A {

}

class B extends A {

}

class C extends B {
    
}

class D extends C {
    
}

3.不同类继承同一个类

class A {

}

class B extends A {

}

class C extends A {

}

class D extends A {

}

注意:Java不支持一个类继承多个类!!!

final关键字:

1.final关键字修饰的字段表示常量,不得修改

 2.final修饰类表示不能被继承

 3.final修饰的方法不得被重写,被final修饰的方法也叫密封方法(稍后介绍)

类的组合:

现在我们要组装一台汽车,那我们就可以定义多个类来组装这台汽车:

// 轮胎类
class Tire{
}
// 发动机类
class Engine{
}
// 车载系统类
class VehicleSystem{
}
class Car{
    private Tire tire; // 可以复用轮胎中的属性和方法
    private Engine engine; // 可以复用发动机中的属性和方法
    private VehicleSystem vs; // 可以复用车载系统中的属性和方法
}

类的组合和继承都可以提高代码的复用性,具体选择要根据实际情况~~

多态

概念:

多态通俗来讲就是多种状态,就是去完成某个任务时,不同对象实现时会产生不同的状态。

就拿吃东西这个任务来讲,如果是猫猫来执行就是吃小鱼,如果是狗狗来执行就是吃骨头~~

实现条件:

多态的三个实现条件(缺一不可!!!)

1.必须是在继承体系之下

2.子类必须对父类的方法进行重写

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

多态的体现:在传递不同类的对象时,会调用该对应类的方法。

class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public void eat() {
        System.out.println("小动物吃东西");
    }
}

class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(this.name + "吃小鱼");
    }
}

class Dog extends Animal {
    public Dog(String name, int age) {
        super(name, age);
    }

    @Override
    public void eat() {
        System.out.println(this.name + "吃骨头");
    }
}

public class Main7 {
    public static void testEat(Animal animal) {
        animal.eat()//在编译阶段并不知道调用的是Cat类还是Dog类,
                    //要等程序运行起来了才能知道传的是什么类~~
    }

    public static void main(String[] args) {
        Cat cat  = new Cat("猫猫", 5);
        Dog dog = new Dog("狗狗", 6);
        testEat(cat);//Cat类执行eat
        testEat(dog);//Dog类执行eat
    }
}

执行结果:

重写:

重写也称为覆盖,是对父类无private修饰、无final修饰的方法的重新编写。

重写的规则:

1.类名要相同。

2.返回类型相同(除非具有父子关系)。

3.参数完全相同。

4.访问权限必须要大于等于父类(比如父类的某个方法用protect修饰,那子类要用protect或者public修饰~~)

5.被static、private、final修饰的方法都不能被重写

6.在重写的时候最好加@Override修饰,可以帮助我们检查重写的合理性。

应该避免在构造函数里调用重写的方法:

class Animal {
    public String name;
    public int age;

    public Animal(String name, int age) {
        this.name = name;
        this.age = age;
        eat();//在父类构造函数中调用被Cat重写的方法
    }

    public void method() {
        eat();//在父类普通函数中调用被Cat重写的方法
    }

    public void eat() {
        System.out.println("小动物吃东西");
    }
}

class Cat extends Animal {
    int weight = 20;//初始化weight的值

    public Cat(String name, int age) {
        super(name, age);
        eat();//在子类构造函数中调用重写的方法
    }

    @Override
    public void eat() {
        System.out.println(this.name + "吃小鱼" + ", 它" + weight + "斤重~~");
    }
}

public class Main7 {
    public static void main(String[] args) {
        Animal cat = new Cat("猫猫", 5);
        System.out.println("我是分割线:----------");
        System.out.println("调用Animal类里的普通函数");
        cat.method();
    }
}

上述代码执行结果:

 分割线前:

 所以我们尽量不要在构造方法中调用方法(如果这个方法被子类重写, 就会触发动态绑定, 但是此时子类对象还没构造完成), 可能会出现一些隐藏的但是又极难发现的问题~~

分割线后:

 我们在如果父类的普通函数里调用有子类重写的eat方法,那么在调用父类对象的这个普通函数执行的会是子类重写的eat方法,而不是父类的eat方法。

一个小例题:

答案为D

大家课后好好思考以下哦~~ 

向上转型:

向上转型就是创建一个子类对象,把它当作父类对象来引用:

应用场景:

1.直接赋值:子类对象赋给父类对象

2.方法传参:形参为父类对象引用,可以接收任意子类对象

3.返回值:返回任意子类参数

向上转型的优点:使代码实现更加灵活

向上转型的缺点:不得使用子类特有的方法

 

向下转型:

向上转型就是创建一个父类对象,把它当作子类对象来引用。

向下转型可以解决向上转型无法使用子类特有的方法的缺陷:

 

 这样就可以执行子类特有的方法了~~

向下转型用得比较少,且不安全,如果强转失败就会抛异常

 那么在Java中为了提高转换的正确性,提供了instanceof,如果表达式为true,则可以安全转换:

多态的优缺点:

多态的优点

1.能够降低代码的“圈复杂度”,避免大量执行if-else语句

2.可扩展能力强

多态的缺点

 1.代码的运行效率低

小总结:继承与多态是Java非常重要的特性,大家一定要写代码,多领悟~~

“你选择如何面对失败呢?其实遗憾才是常态呀” NBA群星闪耀时【高燃励志】_哔哩哔哩_bilibili

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值