四、继承 讲解

四、继承 讲解,第1张

文章目录
  • 🚀 一、继承
    • 🌟 1.1 为什么需要继承?
    • 🌟 1.2 继承的概念
    • 🌟 1.3 继承的语法
  • 🚀 二、 父类成员访问
    • 🌟 2.1 子类访问父类成员变量
    • 🌟 2.2 子类访问父类成员方法
    • 🌟 2.3 super 关键字
    • 🌟 2.4 子类构造方法
    • 🌟 2.5 super 和 this
    • 🌟 2.6 回顾代码块
  • 🚀 三、final 关键字
  • 🚀 四、继承和组合

🚀 一、继承 🌟 1.1 为什么需要继承?

Java 中使用类对现实世界中实体来进行描述,类经过实例化之后产生对象,可以用来表示现实中的实体,但是事物之间可能存在关联,那就要考虑继承。

看下面这两个类:

class Dog{
	String name;
	int age;
	float weight;

	public void eat(){
		System.out.println("狗吃骨头");
	}
}

class Cat{
	String name;
	int age;
	float weight;
	
	public void eat(){
		System.out.println("猫吃鱼");
	}
}

可以看到上面的代码中的两个类中存在着大量的重复。
那么如何将这些相同的代码抽取呢?
面向对象思想中提出了继承的概念,专门来进行共性抽取,实现代码复用。

🌟 1.2 继承的概念

继承机制:是面向对象程序设计中使代码可以复用的最重要的手段,它允许在保持原有类特性的基础上进行扩展,增加新功能,这样产生的类称为派生类。继承呈现了面向对象程序设计的层次结构,体现了由简单到复杂的认知过程。
主要解决的问题:共性的抽取,实现代码复用。

下面用继承重写上面的代码:

class Animal{
	String name;
	int gae;
	float weight;
}

class Dog extends Animal{
	public void eat(){
		System.out.println("狗吃骨头");
	}
}

class Cat extends Animal{
	public void eat(){
		System.out.println("猫吃鱼");
	}
}

上面的代码中,Dog 和 Cat 都继承 Animal 类,其中 Animal 类称为基类或父类,Dog 和 Cat 都是子类。

子类可以使用父类中的成员,子类在实现时只需关心自己新添加的成员。

🌟 1.3 继承的语法

JAVA 中表示类之间的继承关系,要使用到 extends 关键字

修饰符 class 子类名 extends 父类名{
	// ....
}

❗ 注意:

  1. 子类会将父类的成员变量或者成员方法继承。
  2. 子类继承父类之后,必须新添加自己特有的成员,体现与父类的不同,否则就没必要继承了。
  3. JAVA 中一个子类只能继承一个父类。
  4. 父类的 private 属性成员,子类无法访问。
  5. 子类实例中包含父类的实例,使用 super 关键字访问父类实例。
🚀 二、 父类成员访问 🌟 2.1 子类访问父类成员变量
  • 如果访问的成员子类中有,优先访问自己的成员变量。
  • 如果访问的成员子类中无,访问从父类继承下来的,如果父类无定义,则报错。
  • 如果访问的成员变量与父类中的成员变量同名,则优先访问自己的。
    成员变量的访问遵循优先原则,自己有就优先访问,没有就父类中找。
🌟 2.2 子类访问父类成员方法
  • 通过子类对象访问父类与子类不同名方法时,优先在子类中找,找到则访问。否则在父类中找,找到就访问,否则报错。
  • 通过子类对象访问父类与子类不同名方法时,如果父类与子类的同名方法构成重载,根据调用方法传递的参数选择合适的访问,没有则报错。

如果子类存在与父类相同的成员,如何在子类对象中访问父类相同名称的成员呢?

🌟 2.3 super 关键字

super 关键字作用:在子类方法中访问父类的成员。

class Base{
    int a;
    int b;

    public void methodA(){
        System.out.println("Base的方法1");
    }

    public void methodB(){
        System.out.println("Base的方法2");
    }
}

class child extends Base{
    int a;  // 与父类变量名相同且类型相同
    char b; // 与父类变量名相同但类型不同

    // 与父类中的 methodA 构成重载
    public void methodA(int a) {
        System.out.println("child的方法1");
    }

    @Override
    // 重写父类 methodB
    public void methodB(){
        System.out.println("child的方法2");
    }

    public void methodC(){
        // 对于同名的成员变量,直接访问,访问的都是子类的
        a = 100;
        b = 101;

        // 访问父类的成员变量时,借助 super 关键字
        super.a = 200;
        super.b = 201;

        // 父类和子类重载的方法,可以直接通过参数列表区分访问父类还是子类
        methodA();      // 无参,访问父类 methodA
        methodA(20); // 传递 int 参数,访问子类 methodA。

        // 在子类访问重写的父类方法,借助 super 关键字
        methodB();       // 访问子类
        super.methodB(); // 访问父类
    }
}

子类方法中,要明确访问父类中成员,借助 super 关键字即可。
❗ 【注意事项】:

  1. super 只能在非静态方法中使用。
  2. 在子类方法中,访问父类的成员变量和方法。
🌟 2.4 子类构造方法

子类对象构造时,要先调用父类的构造方法,再执行子类构造方法。

public class Base {
    // 父类构造方法
    public Base(){
        System.out.println("父类构造了");
    }
}

class Child extends Base{
    // 子类构造方法
    public Child() {
        // super();	 // 子类构造方法中会默认调用父类的无参构造方法。
        // 用户没有写时,编译器会自动添加,super() 必须是构造方法中第一条语句。
        // 并且只能出现一次
        System.out.println("子类构造了");
    }
}
/*	输出:
*	父类构造了	
*	子类构造了
/
// super(a,b); 调用父类两个参数的构造方法

子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分,在构造子类对象时,要先调用父类的构造方法,将从父类继承下来的成员构造完整,然后再调用子类自己的构造方法,将子类自己的成员初始化完整。

🌟 2.5 super 和 this

super 和 this 都可以在成员方法中来访问其他成员,他们之间有什么区别呢?

⛅相同点:

  1. 都是Java中的关键字。
  2. 只能在类的非静态方法中使用,访问非静态成员变量和方法
  3. 在构造方法中调用时,必须是构造方法中第一条语句。

⛅不同点:

  1. this 是当前对象的引用,是调用实例方法的对象。super 是子类对象从父类继承下来部分成员的引用。
  2. 非静态方法中, this 用来访问本类的方法和属性。super 访问父类继承下来的方法和属性。
  3. 构造方法中,this(…) 调用本类的构造方法,super(…) 调用父类的构造方法,两种调用方法不能同时存在。
🌟 2.6 回顾代码块
class A{
   static{
       System.out.println("A的静态代码块被执行了");
   }
   
   {
       System.out.println("A的实例代码块被执行了");
   }
   
   public A(){
       System.out.println("A的构造方法被执行了");
   }
}

class B extends A{
   static{
       System.out.println("B的静态代码块被执行了");
   }
   
   {
       System.out.println("B的实例代码块被执行了");
   }
   
   public B(){
       System.out.println("B的构造方法被执行了");
   }
}
public class t3 {
   public static void main(String[] args) {
       B b = new B();
   }
}

/*	输出:
   A的静态代码块被执行了
   B的静态代码块被执行了
   A的实例代码块被执行了
   A的构造方法被执行了
   B的实例代码块被执行了
   B的构造方法被执行了
/

⛅继承关系上的代码块执行顺序:

  1. 父类静态代码块先于子类静态代码块执行,且最早执行。
  2. 父类实例代码块和父类构造方法紧接着执行。
  3. 子类实例代码块和子类构造方法紧接着再执行。
  4. 第二次实例化子类对象时,静态代码块都不会执行。
🚀 三、final 关键字

final 关键字修饰变量,成员方法以及类

  1. 修饰变量,表示为一个常量(即不能被修改)
final int a = 10;
a = 20;		// 编译出错
  1. 修饰类:表示该类不能被继承
final class Animal{
	...
}

class Bird extends Animal{
	...
}
// 编译出错,无法从 Animal 继承。

String 类就是 final 修饰的,不能被继承
3. 修饰方法:表示该方法不能被重写。

🚀 四、继承和组合

和继承类似,组合也是一种表达类之间关系的方式。同样可以实现代码复用,但是没有用到 extends 关键字,将一个类的实例作为另一个类的成员。

class Tire{
	...
}

class Engine{
	...
}

class VehicleSystem{
	...
}

class Car{
	private Tire tire;			// 可以复用 Tire 类的属性和方法
	private Engine engine;		// 可以复用 Engine 类的属性和方法
	private VehicleSyetem vs;	// 可以复用 Vs 类的属性和方法
}

继承和组合都可以实现代码的复用,一般来说:能用组合尽量用组合。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/799726.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-06
下一篇 2022-05-06

发表评论

登录后才能评论

评论列表(0条)

保存