[修饰符] class SubClass extends SuperClass 按照这种关系,我们把SuperClass类称为父类或基类,把SubClass称为子类或派生类或拓展类。extends在英语中是扩展的意思,而不是继承。这
个关键字很好的体现了子类和父类的关系:子类是对父类的扩展,子类是一种特殊的父类。子类扩展了父类,将可以获得父类中所有的属性和方法,但是特别注意的是:java中的子类不能获得父类的构造
器。java.lang.Object是所有类的父类,Object要么是直接父类要么是间接父类。Object是默认父类,当你继承了一个父类时,Object就被取消继承了,好比构造方法一样。
继承是一种从一般到特殊的关系;提高了代码的复用性,提高软件开发效率;让类与类之间产生关系,多态的前提。
- 子类与父类:
多继承虽然能使子类同时拥有多个父类的特征,但是其缺点也是很显著的,主要有两方面:
(1)如果在一个子类继承的多个父类中拥有相同名字的实例变量,子类在引用该变量时将产生歧义,无法判断应该使用哪个父类的变量
(2)如果在一个子类继承的多个父类中拥有相同方法,子类中有没有覆盖该方法,那么调用该方法时将产生歧义,无法判断应该调用哪个父类的方法。
- 子类对象实例化过程:
在继承操作中,对于子类对象的实例化:子类对象在实例化之前必须首先调用父类中的构造方法之后再调用自身的构造方法。
2个问题:若一个类的所有的构造方法使用private修饰,该类能不能有子类? 不可以
若一个类的所有的构造方法使用protected修饰,该类能不能有子类? 可以的
子类不能直接访问父类的私有成员;但是子类可以调用父类中的非私有方法来间接访问父类的私有成员。Person类中有私有字段name,Student继承Person
new Sudent().name; ×
new Student().getName(); √ 代码如下:
public class Linkin extends Person { public static void main(String[] args) { Linkin linkin = new Linkin(); System.out.println(linkin.name); System.out.println(linkin.getAge()); } } // 定义一个父类 class Person { public String name = "LinkinPark"; private int age = 25; public Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public void test() { System.out.println("这是完成不了的爱,,,"); } }
- 覆写父类方法
鸟和鸵鸟的例子,鸵鸟是鸟类中的一个特殊品种,所以鸵鸟类是鸟类的一个子类;但是鸟类有飞翔的功能,但是鸵鸟呢?飞翔的行为显然不适合于鸵鸟,此时怎么办?
子类拓展父类(子类是父类的一种特殊情况),主要是以父类为基础,然后添加属于自己的字段和方法。
当父类的某个方法不适合于子类本身的特征行为时就当覆写父类中应当改变的方法。
- 方法的覆写
调用被覆盖的父类方法:使用super.方法名(实参);
方法覆写时应遵循的原则(一同两小一大):(一同):方法签名必须相同;
(两小):子类方法的返回值类型比父类方法的返回值类型更小或相等,子类方法声明抛出的异常应比父类方法申明抛出的异常更小或相等;
(一大):子类方法的访问权限应比父类方法更大或相等。代码如下:
/** * * @version 1L * @author LinkinPark * @since 2014-10-28 * @motto 梦似烟花心似水,同学少年不言情 * @desc ^重写父类的方法 */ public class Ostrich extends Bird{ @Override //子类方法前加上@Override能编译通过,表明是方法的覆写。 public void fly() { System.out.println("可怜的鸵鸟,只能在地上跑,,,"); } //如果需要在子类方法中调用父类被覆盖的实例方法,可以使用super来调用 public void birdFly() { super.fly(); } public static void main(String[] args) { Ostrich bird = new Ostrich(); bird.fly(); bird.birdFly(); } } //定义一个普通的父类,其实中在这样子用来被继承的类设计中,方法的访问修饰符一般都使用protected class Bird{ public void fly(){ System.out.println("一般的鸟儿都会在天上飞的,,,"); } }
如果子类中包含了和父类同名的属性,那么在子类的实例方法中访问这个属性的时候,默认使用子类中的属性,也就是说子类的属性覆盖了父类的属性。注意:不是完全覆盖,系统在创建子类对象时,依然会为父类中定义的,被隐藏的变量分配内存空间。
要是子类中没有包含和父类同名的属性,在子类的实例方法中访问该属性的时候,则无须显式使用super或者父类名作为调用者。
如果在某个方法中访问名为a的属性,但是没有显式指定调用者,则系统查找a的顺序为:
1,查找该方法中是否有名为a的局部变量
2,查找当前类中是否包含了名为a的属性
3,查找a的直接父类中是否包含了a的属性,依次上溯a的所有父类,直到object
如果被覆盖的类的属性,在子类中可以通过父类名作为调用者来访问被覆盖的类的属性。
不管我们是否使用super调用来执行父类构造器中的初始化代码,子类构造器总会调用父类构造器一次。有this的话,就调用本类中的另外一个构造器,有super的话就调用父类中对应的构造器,要是2个都没有的话,就隐身调用父类的无参数构造器。代码如下:
public class Wolf extends Animal{ public Wolf(){ super("狼人",3); System.out.println("Wolf无参数构造器。。。"); } public static void main(String[] args) { new Wolf(); } } class Creature{ public Creature(){ System.out.println("Creature无参数构造器 。。。"); } } class Animal extends Creature{ public Animal(){ } public Animal(String name){ System.out.println("Animal带一个参数的构造器。。。"); } public Animal(String name,int age){ this(name); System.out.println("Animal带两个参数的构造器。。。"); } }
最后以Overload( 重载)& Override(重写)的区别来结束:
No. |
区别点 |
重载(overload) |
覆写(override) |
1 |
判断 规则 |
两同一不同 |
一同两小一大 |
2 |
权限 |
没有权限要求 |
被覆写的方法不能拥有比父类更严格的权限 |
3 |
范围 |
发生在一个类之中 |
发生在继承关系中 |
4 |
术语 |
overload |
override |
5 |
多态 |
编译时多态 |
运行时多态 |