龙空技术网

Java基础知识总结:继承

TOTORO 181

前言:

而今同学们对“java的继承实例”都比较着重,姐妹们都想要剖析一些“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),也被称为方法的覆盖。可以说子类重写了父类的方法,也可以说父类的方法被子类覆盖了。

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

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

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类的构造器。

标签: #java的继承实例