赞
踩
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那一个类即可。
其中,多个类可以称为子类,单独那一个类称为父类、超类(superclass)或者基类。
继承描述的是事物之间的所属关系,这种关系是:is-a的关系。
例如,图中兔子属于食草动物,食草动物属于动物。
可见,父类更通用,子类更具体。我们通过继承,可以使多种事物之间形成一种关系体系。
继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为。
子类可以直接访问父类中的非私有的属性和行为。
在继承的关系中,“子类就是一个父类”,也就是说,子类可以被当做父类看待。
父类是员工,子类是讲师,那么”讲师就是一个员工“,关系:is - a.
通过extends
关键字,可以声明一个子类继承另外一个父类
从代码的层面来看,在子类的构造方法第一行代码默认就是父类的实例化。
所以子类实例化之前会先实例化父类 。
从设计模式来看,子类继承自父类,需要用到父类的“资源”(没被覆盖的函数以及可见的成员变量等)。
因此需要先实例化父类
定义格式如下:
public class Fu {
// ...
}
public class Zi extends Fu {
public Zi() {
super();
}
}
当类之间产生了关系后,其中各类中的成员变量,又产生了哪些影响呢?
如果子类父类中出现不重名的成员变量,这时的访问是没有影响的。
如果子类父类中出现重名的成员变量,这时的访问是有影响的。
在父类的继承关系当中,如果成员变量重名,则创建子类对象时,访问有两种方式。
Fu
package cn.luis.demo2; public class Fu { int numFu = 10; int num = 100; public void methodFu() { // 使用的是本类当中的num System.out.println(num); } public void method() { System.out.println("父类重名方法执行"); } }
Zi
package cn.luis.demo2; public class Zi extends Fu { int numZi = 20; int num = 500; public void methodZi() { // 因为本类当中有num,所以使用的是本类当中的num System.out.println(num); } public void method() { System.out.println("子类重名方法执行"); } }
测试类
package cn.luis.demo2; public class Demo01ExtendsField { public static void main(String[] args) { // 第一: // 创建父类对象 Fu fu = new Fu(); System.out.println(fu.numFu); // 只能使用父类的东西 System.out.println("==============="); Zi zi = new Zi(); System.out.println(zi.numFu); // 10 System.out.println(zi.numZi); // 20 System.out.println("==============="); // 等号左边是谁,就优先用谁 System.out.println(zi.num); // 优先子类,500, 若子类没有则向父类寻找。 System.out.println("==============="); // 这个方法是子类的,所以优先用子类的,没有再向上找 zi.methodZi(); // 500 // 这个方法是在父类中定义的,是属于父类的 zi.methodFu(); // 100 // 第二: zi.method(); // 创建的是子类对象,所以优先使用子类方法。 fu.method(); } }
结果:
10
===============
10
20
===============
500
===============
500
100
子类重名方法执行
父类重名方法执行
代码:
class Fu { int num = 10; } class Zi extends Fu { int num = 20; public void method() { int num = 30; System.out.println(num); // 30 局部变量 System.out.println(this.num); // 20 本类的成员变量 System.out.println(super.num); // 10 父类的成员变量 } } public class Demo02Extends { public static void main(String[] args) { Zi zi = new Zi(); zi.method(); } }
结果:
30
20
10
无论是成员变量还是成员方法,如果没有都是向上找父类,绝对不会向下找子类。
方法的重写特点: 创建的是子类对象,则优先使用子类方法。
当类之间产生了关系,其中各类中的成员方法,又产生了哪些影响呢?
如果子类父类中出现不重名的成员方法,这时的调用是没有影响的。
对象调用方法时,会先在子类中查找有没有对应的方法。
若子类中存在就会执行子类中的方法,若子类中不存在就会执行父类中相应的方法。
如果子类父类中出现重名的成员方法,这时的访问是一种特殊情况,叫做方法重写(Override)。
子类中出现与父类一模一样的方法时(返回值类型,方法名和参数列表都相同),会出现覆盖效果,也称为重写或者复写。声明不变,重新实现。
@Override,写在方法前面,用来检测是不是正确的有效的覆盖重写。、
这个注解就算不写,只要满足要求,也是正确的覆盖重写方法。
代码如下:
public class Fu { public void show() { System.out.println(Fu show); } } public class Zi extends Fu { public void show() { System.out.println(Zi show); } } public class Demo01ExtendsField { public static void main(String[] args) { Zi zi = new Zi(); zi.show(); //Zi show } } // 结果:Zi show
子类可以根据需要,定义特定于自己的行为。既沿袭了父类的功能名称,又根据子类的需要重新实现父类方法,从而进行扩展增强。比如新的手机增加来电显示头像的功能。
兼容并拓展旧手机功能
/* 定义了一个手机 */ public class Phone { public void call() { System.out.println("打电话!"); } public void send() { System.out.println("发短信!"); } public void show() { System.out.println("显示号码!"); } } /* 定义了一个新手机 */ class NewPhone extends Phone { @Override public void show() { // 把父类的show方法拿来用 super.show(); System.out.println("显示姓名"); System.out.println("显示头像"); } } package cn.luis.demo5; public class Demo01Phone { public static void main(String[] args) { Phone phone = new Phone(); phone.call(); phone.send(); phone.show(); System.out.println("================"); NewPhone newphone = new NewPhone(); newphone.call(); newphone.send(); newphone.show(); } }
结果:
打电话!
发短信!
显示号码!
================
打电话!
发短信!
显示号码!
显示姓名
显示头像
子类方法覆盖父类方法,返回值类型、函数名和参数列表都要一模一样。
子类方法覆盖父类方法,必须要保证权限大于等于父类权限。
public > protect > (default)什么都不写 > private
子类方法的返回值范围必须小于等于父类方法的返回值范围。
java.lang.Object
是java.lang.String
的父类
当类之间产生了关系,其中各类中的构造方法,又产生了哪些影响呢?
首先我们要回忆两个事情,构造方法的定义格式和作用。
构造方法的名字是与类名一致的。所以子类是无法继承父类构造方法的。
构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。
子类必须调用父类构造方法,不写则赠送super()
写了则用写的指定的super调用,super只能有一个,还必须是第一个
子类的构造方法中默认有一个super(),表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。所以一定是先调用的父类构造,后执行子类的构造方法。
super的父类构造调用,必须是子类构造方法的第一个语句。不能一个子类构造调用多次super构造
子类构造方法可以通过super关键字来调用父类重载构造。
代码:
public class Fu { private int n; public Fu() { System.out.println("Fu构造方法执行..."); } } public class Zi extends Fu { public Zi() { //super(); // 调用父类构造方法 System.out.println("Zi构造方法执行..."); } } public class Demo01Construction { public static void main(String[] args) { Zi zi = new Zi(); } }
结果:
Fu构造方法执行...
Zi构造方法执行...
在每次创建子类对象时,先初始化父类空间,再创建其子类对象本身。目的在于子类对象中包含了其对应的父类空间,便可以包含其父类的成员,如果父类成员非private修饰,则子类可以随意使用父类成员。
代码体现在子类的构造方法调用时,一定先调用父类的构造方法。
super:代表父类的存储空间标识,可以理解为父亲的引用。
this:代表当前对象的引用(谁调用就代表谁)。
代码如下:
this.成员变量 本类的
super.成员变量 父类的
this.成员方法名() 本类的
super.成员方法名() 父类的
代码如下:
class Animal { int num = 10; public void eat() { System.out.println("animal : eat"); } } class Cat extends Animal { int num = 100; @Override public void eat() { System.out.println("Cat : eat"); } public void test() { Sthis.num; // 100 super.num; // 10 this.eat(); // Cat : eat super.eat(); // animal : eat } } public class Demo02Extends { public static void main(String[] args) { Cat c = new Cat(); c.test(); Animal a = new Animal(); a.eat(); } }
结果:
100
10
Cat : eat
animal : eat
super()
,调用父类的空参构造。手动调用父类构造会覆盖默认的super()
。super()
和this()
都必须是在构造方法的第一行,所以不能同时出现。Fu
public class Fu {
public Fu() {
System.out.println("Fu无参构造方法执行");
}
public Fu(int n) {
System.out.println("Fu有参构造方法执行");
}
}
Zi
public class Zi extends Fu {
public Zi() {
this(123); // 本类的无参构造,调用本类的有参构造:Zi(int n)
}
public Zi(int n) {
this(1,2);
}
public Zi(int n, int m) {
super(13); // 必须为父类构造方法传递实参 (因为父类是有参构造函数)
// super(); // 若是无参,可省略,会默认给一个super()
}
}
// 一个类只能有一个父类,不可以有多个父类
class C extends A{}
class C extends A,B...{}
Java支持多层继承(继承体系)
顶层父类是Object类,所有的类默认继承Object,作为父类。
class A{}
class B extends A{}
class C extends B{}
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。