Java 继承(扩展)

1、简单介绍

什么是继承?extends 其实是扩展的意思

继承是类与类之间的一种关系,对某一批类中共有的方法和属性进行共性抽取,抽取出来的这个类也就是被继承的类称之为:父类 / 基类 / 超类;继承的类称之为:子类 / 派生类

为什么要使用继承?(或者说使用继承解决了什么问题?)

提高代码复用率

继承是多态的前提,没有继承即没有多态。

继承设计规范

子类们相同特征(共性属性、共性方法)放在父类中定义,子类独有的属性和行为应该定义在子类自己里面。

为什么这样做?

如果子类的独有属性、行为定义在父类中,会导致其他子类也会得到这些属性和行为,这不符合面向对象逻辑。

2、特点

  • java 语言是单继承的,不是多继承,但是可以多层继承。

    • 例如:A 继承 B,B 继承 C,C 再继承 D,……,X 继承 Object 类。
  • 一个子类的直接父类是唯一的,但是一个父类可以拥有很多个子类。

    • java 中所有的类都直接或间接继承自 Object(祖宗类)。
  • 在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当作父类看待。

    • 关系:is-a。
    • 例如:父类是员工,子类是讲师,那么“讲师就是一个员工”。
  • 继承当中子类可以拥有父类的“内容”, 子类还可以拥有自己专有的内容。

  • 子类只能从被扩展的父类获得成员变量、方法和内部类(包括内部接口、枚举),不能获得构造器和初始化块。

3、语法格式

定义父类的格式和定义一个普通的类没有区别

  • 定义子类的格式:
public class 子类名称 extends 父类名称{
      // ...
}

4、成员的访问特点

子类和父类中成员变量重名的访问特点

在父子类的继承关系中,如果成员变量重名,则创建子类对象时,访问的规则是:

等号左边是谁,就优先用谁,没有则向上找。

子类和父类中成员方法重名的访问特点(对于非静态方法)

创建的对象是谁,就优先用谁,没有则向上找。

该方法属于谁时,先看子类中有没有,没有则向上找,不能去其他子类中找。

子类是否可以继承父类的私有成员变量?

  • 可以的,只是不能直接访问,可以在父类中设置相应的方法,在子类中进行访问。

子类是否可以继承父类的静态成员?

  • 有争议的知识点。
  • 子类可以直接使用父类的静态成员(共享)。
  • 但个人认为:子类不能继承父类的静态成员。(共享并非继承)。

对静态和非静态方法的测试:

// 父类
public class Fu {

	public static void print() {
		System.out.println("Fu==>print()");
	}

	public void show() {
		System.out.println("Fu==>show()");
	}
}
// 子类
public class Zi extends Fu {

	public static void print() {
		System.out.println("Zi==>print()");
	}

	public void show() {
		System.out.println("Zi==>show()");
	}
}
// 测试类
public class Demo01 {
	public static void main(String[] args) {
		Zi zi = new Zi();
		zi.print(); // 静态方法
		zi.show();  // 非静态方法

		Fu fu = new Zi();
		fu.print(); // 静态方法
		zi.show();  // 非静态方法
		  /*
       结果:
			Zi==>print()
			Zi==>show()
			Fu==>print()
			Zi==>show()
	   说明:
			静态方法是类的方法,非静态方法是对象的方法
			有 static 时,fu 调用了 Fu 类中的方法
			没有 static 时,fu 调用了 new 的对象 Zi 的方法
       */
	}
}

对实例变量的测试

如果子类定义了和父类同名的实例变量,则会发生子类实例变量隐藏父类实例变量的情况。

public class BaseClass {

   public  String name = "基类";
}
public class SubClass extends BaseClass {

   private  String name = "派生类";
}
public class Demo02 {
   public static void main(String[] args) {
      SubClass subClass = new SubClass();
      // 报错:因为派生类中 name 是 private 修饰的无法直接访问
      // System.out.println(subClass.name);
      // 向上强制类型转换 基类中 name 是 public 修饰的可以直接访问
      System.out.println(((BaseClass) subClass).name); // 基类

   }
}

同样

public class BaseClass {
   public  String name = "基类";
}
public class SubClass extends BaseClass {
   public  String name = "派生类";

}
public class Demo02 {
   public static void main(String[] args) {
      SubClass subClass = new SubClass();
      System.out.println(subClass.name); // 派生类
      System.out.println(((BaseClass) subClass).name); // 基类

   }
}

5、构造器的访问特点

子类继承父类后构造器的特点:

子类中所有的构造器默认都会先访问父类中无参的构造器,再执行自己的。

为什么?

1、子类在初始化的时候,有可能会使用到父类中的数据,如果父类没有完成初始化,子类将无法使

用父类的数据。

2、子类初始化之前,一定要调用父类构造器先完成父类数据空间的初始化。

怎么调用父类构造器的?

子类构造器的第一行语句默认都是:super();,不写也存在。

继承后子类构造器如何访问父类有参构造器?

通过 super 关键字调用父类有参构造器的作用来初始化继承自父类的数据。

如果父类中没有无参构造器,只有有参构造器,会出现什么现象?

会报错,因为子类默认是调用父类无参构造器的。

如何解决?

子类构造器中可以通过书写 super(参数),手动调用父类的有参构造器。

注:

子类必须调用父类的构造方法,不写则赠送 super();,写了则用指定的。

在子类构造器中,super() / super(参数) 只能有一个,还必须是构造器语句中的第一句。

super() / super(参数) 不能出现在非构造器方法中

6、方法的覆盖重写

为什么要对基类中的方法进行重写?

因为基类中的方法不满足我们的需求,需要对其进行扩展,让派生类来满足我们需求。

注意:重写和重载是针对方法而言的,不针对属性

重写(override):子父类中,方法名称一样,参数列表也一样。

重载(overload):同一个类中,方法名称一样,参数列表不一样。

重写的条件:“两同两小一大”

  • “两同”:方法名称和形参列表要相同

  • “两小”:

    • 子类方法的返回值类型和父类方法的返回值类型相同,或者是父类返回值类型的子类;
    • 子类方法声明抛出的异常类和父类方法声明抛出的异常类相同,或者是父类抛出的异常类的子类;
  • “一大”:子类方法的访问权限和父类方法的访问权相同,或者更大;

覆盖重写注意事项:

  1. 不能重写被 final、static、private 修饰的方法
  2. 构造器不能被继承,更不能被覆盖
  3. 覆盖方法和被覆盖方法(这里指的是方法名称和参数列表要相同的)要么都是类方法,要么都是实例方法,不能一个是类方法,一个是实例方法。

父类的私有成员方法对子类是隐藏的,无法直接在子类中访问,更不能重写。如果子类中定义了一个与父类 private 方法相同方法名称、参数列表、返回值类型的方法,也无法构成重写,只是在子类中重写定义了一个新方法。

代码示例:

public class BaseClass {

	// test()方法是private修饰的,子类不可访问该方法
	private  void test() {
	}
}
public class SubClass extends BaseClass {

	// 此处并不是方法重写,所以可以增加static关键字
	public static void test() {
	}
}

7、this 和 super 关键字

this:代表本类对象的引用

  1. 在本类的成员方法中,访问本类的成员变量。
  2. 在本类的成员方法中,访问本类的另一个成员方法。
  3. 在本类的构造方法中,访问本类的另一个构造方法。

super:代表父类对象存储空间的标识

  1. 在子类的成员方法中,访问父类的成员变量。
  2. 在子类的成员方法中,访问父类的成员方法。
  3. 在子类的构造方法中,访问父类的构造方法。

注:

  • this(参数) 调用也必须是构造方法的第一个语句,唯一一个。
  • super 和 this 两种构造调用,不能同时使用。
  • this 和 super 都不能出现在 static 修饰的类方法中。

posted on   demo-arch  阅读(111)  评论(0编辑  收藏  举报

相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用

统计

点击右上角即可分享
微信分享提示