专业编程基础技术教程

网站首页 > 基础教程 正文

Java基础知识总结:继承(java 继承)

ccvgpt 2024-07-28 12:22:45 基础教程 6 ℃

什么是继承


继承是面向对象的三大特征之一,是实现代码复用的重要手段。

Java基础知识总结:继承(java 继承)

Java的继承通过extends关键字实现,实现继承的类称为子类,被继承的类称为父类(或者基类、父类)。

继承的语法如下:

 访问修饰符 class SubClass extends SuperClass{
 //类定义部分
 }

子类继承了父类,将获得父类的全部成员变量和方法,但是不能获得父类的构造器。

下面程序演示子类继承父类。

先定义一个父类:

 /**
 * Person类,作为父类
 */
 public class Person {
 ?
 String name;
 ?
 int age;
 ?
 public void eat() {
 System.out.println("吃饭");
 }
 ?
 }

再定义一个子类,继承自上面已经定义好的父类:

 /**
 * Man子类,继承Person父类
 */
 public class Man extends Person {
 
 }

再定义一个测试类:

 public class Test {
 ?
 public static void main(String[] args) {
 Man man = new Man();
 ?
 // Man类本身并未定义name和age属性,但可以访问,说明Man继承了来自其父类的man和age属性
 man.name = "Java";
 man.age = 18;
 ?
 // eat方法也继承自其父类
 man.eat();
 }
 ?
 }

上面代码说明:当一个子类继承了一个父类,将获得父类的全部成员变量和方法。

做为子类,也可以有自己单独的成员变量和方法,其和父类构成了一般和特殊的关系。如,可以在上面的Man类添加自己的属性和方法:

 /**
 * Man子类,继承Person父类
 * 添加自己的属性和方法,这样一样,这个类的对象就拥有了父类的成员变量、方法和自己类中的成员变量、方法
 */
 public class Man extends Person {
 boolean isRich;
 ?
 public void earnMoney() {
 System.out.printf("男人要赚钱");
 }
 }

Java的继承特点


在Java语言中,每个类只有一个直接父类,是单继承的。例如下面代码编译会报错:

 class SubClass extends SuperClass1, SuperClass2,SuperClass3...

但是,可以有多个间接父类,如:

 public class Man extends Person{...}
 public class Person extends Creature{...}

上面代码中,Creature是Person的直接父类,是Man的间接父类。

如果定义一个类时,没有显式地声明其直接父类,则这个类默认继承自java.lang,Object类。Object类是所有类的父类,要么是直接父类,要么是间接父类。

方法的重写


子类扩展了父类,是父类的一个特殊实现。当从父类继承来的方法不满足子类时,可以重写父类的方法。

下面程序先定义了一个Bird父类如下:

 /**
 * Person类,作为父类
 */
 public class Person {
 
 public void eat() {
 System.out.println("人吃饭");
 }
 ?
 }

下面再定义一个Man类,这个类扩展了Person类,重写了Person类的eat()方法。

 /**
 * Man子类,继承Person父类
 */
 public class Man extends Person {
 
 // 子类重写了父类的eat()方法
 @Override
 public void eat() {
 System.out.println("男人要吃很多饭");
 }
 ?
 }

再写一个测试类:

 public class Test {
 ?
 public static void main(String[] args) {
 Man man = new Man();
 // 输出为:男人要吃很多饭
 man.eat();
 }
 ?
 }

可以看到,程序执行的是Man类中的eat()方法,而不是Person类的eat()方法。

像上面这种子类和父类包含有相同名称、相同参数列表的现象被称为方法的重写(Override),也被称为方法的覆盖。可以说子类重写了父类的方法,也可以说父类的方法被子类覆盖了。

方法的重写要遵循”两同两小一大“规则,即:

  1. ”两同“:方法名相同,参数列表相同
  2. “两小”:子类方法返回值类型应比父类方法返回值类型小或相等,子类方法声明抛出的异常应比父类小或相等
  3. ”一大“:子类方法的访问权限应比父类的大或相等。

super关键字

前文提到,子类可以重写父类的方法。当子类覆盖了父类方法后,子类对象将无法访问父类被重写的方法,但可以通过super关键字在子类对象的方法中访问父类被重写的方法。

代码是这样的:

 /**
 * Man子类,继承Person父类
 */
 public class Man extends Person {
 ?
 @Override
 public void eat() {
 // 可以在子类的方法中调用父类被覆盖的方法
 super.eat();
 System.out.println("男人要吃很多饭");
 }
 ?
 }
 ?

如果子类定义了和父类同名的实例变量,则在子类实例方法中将无法访问父类的该变量,这是因为被子类实例同名的实例变量隐藏了,这时候可以通过super关键字来访问。如下代码所示。

 class BaseClass{
 public int a = 5;
 }
 ?
 public class SubClasss extends BaseClass{
 public int a = 7;
 
 public void accessSubVar() {
 System.out.println(a);
 }
 
 public void accessBaseVar() {
 System.out.print(super.a);
 }
 
 public static void main(String[] args) {
 SubClasss s = new SubClasss();
 s.accessSubVar(); // 输出7
 s.accessBaseVar(); // 输出5
 }
 
 }

当程序创建一个子类对象时,系统不仅会为该类中定义的实例变量分配内存,也会为它从父类继承来的所有实例变量分配内存,即使子类定义了和父类同名的实例变量。也就是说,当系统创建一个Java对象时,如果该Java类有两个父类(一个直接父类A,一个间接父类B),假设A类中定义了2个实例变量,B类中定义了3个实例变量,自己子类中定义了2个实例变量,那么这个Java对象共有2+3+2个实例变量。

此外,super关键字还可以用来调用父类构造器。

 class Base {
 public double size;
 public String name;
 public Base(double size, String name) {
 this.size = size;
 this.name = name;
 }
 }
 ?
 public class Sub extends Base {
 public String color;
 
 public Sub(double size, String name, String color) {
 // 使用super关键字显式调用父类构造器
 super(size, name);
 this.color = color;
 }
 }

如果我们在子类构造器中未显式调用父类构造器,则会隐式调用父类无参数的构造器。

 class Person {
 ?
 public Person() {
 System.out.println("父类构造器执行。。。");
 }
 ?
 }
 ?
 public class Man extends Person {
 ?
 public Man() {
 System.out.println("子类构造器执行。。。");
 }
 
 public static void main(String[] args) {
 // 执行Man类的构造器时,会先执行其父类的构造器
 // 所以输出结果为:父类构造器执行。。。子类构造器执行。。。
 Man man = new Man();
 }
 ?
 }

所以,调用子类构造器时,总是会先调用其父类的构造器,如果父类还继承自别的间接父类,则会依次往上追溯执行构造器。Object是所有类的父类,所以,构造任何Java对象时,总会先执行Object类的构造器。

Tags:

最近发表
标签列表