目录
继承的概述
- 多个类中存在相同属性(成员变量)和行为(方法)时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
- 子类可以直接访问父类中的非私有的属性和行为。
- 通过 extends 关键字让类与类之间产生继承关系。
–class SubDemo extends Demo{} SubDemo是子类,Demo是父类
package com.demo01;
/*
* 继承:多个类有共同的成员变量和成员方法,抽取到另外一个类中(父类),在让多个类去继承这个父类,我们的多个类就可以获取到父类中的成员了。
* extends
*
*/
public class ExtendsDemo {
public static void main(String[] args) {
DotA d = new DotA();
d.start();
LOL l = new LOL();
l.start();
}
}
// 父类
class Game {
String name;
double version;//版本号
String agent;//代理商
//法
public void start() {
System.out.println("游戏启动了");
}
public void stop() {
System.out.println("游戏关闭了");
}
}
//子类 继承了游戏所有的属性和方法
class DotA extends Game {
}
//子类 继承了游戏所有的属性和方法
class LOL extends Game {
}
代码分析:我们创建一个游戏父类——class game,我们创建了DotA、LOL子类来继承游戏的父类,继承了游戏的所有属性和方法,我们创建两个子类对象,执行父类里边的东西。
结果显示:
继承的特点
- Java只支持单继承,不支持多继承。
–一个类只能有一个父类,不可以有多个父类。
–class SubDemo extends Demo{} //ok
–class SubDemo extends Demo1,Demo2...//这种是错误的
- Java支持多层继承(继承体系)
–class A{}
–class B extends A{}
–class C extends B{}
声明一个父类:A,子类B可以继承C,子类C也可以继承子类B,也就是说一个类既可以当子类,也可以当父类。
package com.demo02;
/*
* Java中继承的特点:
* Java语言只支持单一继承,只能继承一个父类(一个儿子只能有一个亲爹)
* Java语言支持多层继承(一个儿子可以有一个亲爹,还可以有一个亲爷爷)
*
*/
public class ExtendsDemo2 {
public static void main(String[] args) {
LOL l = new LOL();
MobileGame s = new MobileGame();
l.update();
l.start();
s.update();
s.start();
}
}
class Game {
public void start() {
System.out.println("游戏启动了");
}
}
class PCGame extends Game {
public void update() {
System.out.println("PCGame更新了");
}
}
class MobileGame extends Game {
public void update() {
System.out.println("MobileGame更新了");
}
}
class LOL extends PCGame {
}
代码分析:我们创建了一个父类,为Game, 其中子类PCGame和MobileGame都继承了父类Game——作为爷爷级别,而LOL又继承了PCGame——作为爸爸类,我们new一个LOL对象。
结果显示:
继承中的成员变量
- 如果子父类中出现非私有的同名成员变量时,子类要访问本类中的变量,用this;访问父类中的同名变量 用super。
- super的使用和this的使用几乎一致。
- this代表的是本类对象的引用;super当前子类对象父类的引用。
继承中成员变量的特点:
子类只能获取父类非私有成员
子父类中成员变量的名字不一样,直接获取父类的成员变量
子父类中成员变量名字是一样的,获取的是子类的成员变量
package com.demo02;
/*
* 继承中成员变量的特点
* 子类只能获取父类非私有成员
* 子父类中成员变量的名字不一样,直接获取父类的成员变量
* 子父类中成员变量名字是一样的,获取的是子类的成员变量
*
* 就近原则:谁离我近我就用谁
* 如果有局部变量就使用局部变量
* 如果没有局部变量,有子类的成员变量就使用子类的成员变量
* 如果没有局部变量和子类的成员变量,有父类的成员变量就使用父类的成员变量
* 啥都没有,出错了!!!
*
* super:可以获取父类的成员变量和成员方法,用法和this是相似的
*/
public class ExtendsDemo3 {
public static void main(String[] args) {
Kid3 k = new Kid3();
k.show();
}
}
class Dad3 {
String name = "建霖";
String superName = "父类中的成员变量";
}
class Kid3 extends Dad3 {
String name = "四葱";
public void show() {
System.out.println(super.superName);
String name = "五葱";
//System.out.println(super.name);
System.out.println(this.name);
System.out.println(name);
}
}
代码分析:创建一个父类——Dad3,成员变量是name,superName,在子类中Kid3也有name,要想访问子类中的成员变量name,要用this,而子类中要想访问父类中的superName,要用super,而访问局部变量,不用this,采用的是就近原则。
继承中的成员方法
- 当子类出现和父类一模一样的方法时,当子类对象调用该方法,会运行子类方法的内容。如同父类的方法被覆盖一样。
- 这种情况是方法的另一个特性:
- 重写(覆盖)(override)
- 重载overload
继承中成员方法的特点:
子类中没有这个方法,调用父类的
子类中重写了这个方法,调用子类的
方法的重写(override):在子父类当中,子类的方法和父类的完全一样,子类重写了父类的方法(覆盖),当子类重写了父类的方法之后,使用子类对象调用的就是子类的方法
方法的重载(overload):在一个类中,有多个重名的方法,但是其参数不一样(参数的个数,参数的类型,参数的顺序),和返回值无关
package com.demo02;
/*
* 继承中成员方法的特点
* 子类中没有这个方法,调用父类的
* 子类中重写了这个方法,调用子类的
*
方法的重写(override):在子父类当中,子类的方法和父类的完全一样,子类重写了父类的方法(覆盖),当子类重写了父类的方法之后,使用子类对象调用的就是子类的方法
方法的重载(overload):在一个类中,有多个重名的方法,但是其参数不一样(参数的个数,参数的类型,参数的顺序),和返回值无关
*/
public class ExtendsDemo4 {
public static void main(String[] args) {
Kid4 k = new Kid4();
k.eat();
k.eat(null);
}
}
class Dad4 {
public void eat() {
System.out.println("小酌两口");
System.out.println("去睡觉了");
}
}
class Kid4 extends Dad4 {
public void eat() {
super.eat();
System.out.println("好好吃饭");
}
public void eat(String name) {
super.eat();
System.out.println("好好吃饭1");
}
}
代码分析:定义了一个父类——Dad4,里边定义了一个eat()方法,定义了一个子类Kid4继承父类Dad4,也定义了一个eat()方法,和父类的方法一致,用super来调用父类的方法,创建一个类对象,执行程序,先执行父类,再执行子类。
方法的重写
- 子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写。
- 父类中的私有方法可不可以被覆盖呢?子类根本就看不到父类的方法
- 在子类覆盖方法中,继续使用被覆盖的方法可以通过super.方法名获取。
- 覆盖注意事项:
–覆盖时,子类方法权限一定要大于等于父类方法权限
- 覆盖的应用:
–当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。
package com.demo03;
/*
* 方法重写的应用场景:当父类的方法不能完全满足子类使用,这个时候子类重写父类的方法,
* 并可以在方法中使用关键字super调用父类的方法,这样做即可以保有父类的功能,也可以拥有子类特有的功能
* 方法重写的注意事项:
* 不能重写父类私有的方法
* 权限必须大于等于父类方法的权限
*
* 注解:@
*
*/
public class ExtendsDemo5 {
public static void main(String[] args) {
NewPhone np = new NewPhone();
np.call();
}
}
//父类
class Phone {
void call() {
System.out.println("打电话");
}
}
//子类
class NewPhone extends Phone {
@Override // 说明方法是重写父类中的方法
public void call() {
System.out.println("录音");
//System.out.println("打电话");
//super.call();
}
}
代码分析:首先创建一个父类——Phone,父类的方法是call,我们又创建一个子类,利用@Override对call方法进行重写,父类中函数类型是什么,子类中的函数类型必须是什么,;例如:父类中是Public,子类也必须是Public。
继承中的构造方法
- 在对子类对象进行初始化时,父类的构造方法也会运行,那是因为子类的构造方法默认第一行有一条隐式的语句super()
- super():会访问父类中的空参数构造方法。而且子类中所有的构造方法默认第一行都是super( )
package com.demo03;
/*
* 继承中构造方法的执行顺序
* 在子父类中,创建子类对象,调用子类的构造方法,
* 在子类的构造方法的第一行代码如果没有调用父类的构造或者没有调用子类的其他构造,则默认调用父类无参构造
* 为什么要调用父类构造?
* 因为需要给父类的成员变量初始化
* 肯定会先把父类的构造执行完毕,再去执行子类构造中的其他代码
*
* 我是父类无参构造 --- 我是子类有参构造 --- 我是子类无参构造
*/
public class ExtendsDemo6 {
public static void main(String[] args) {
//Parent d = new Parent();
Son6 son = new Son6(1);
}
}
class Parent6 {
public Parent6() {
System.out.println("我是父类无参构造");
}
public Parent6(int num) {
System.out.println("我是父类有参构造");
}
}
//子类
class Son6 extends Parent6 {
public Son6() {
super(1);//写不写一定会执行父类无参数
System.out.println("我是子类无参构造");
}
public Son6(int num) {
this(1l);
//会默认调用父类无参构造
System.out.println("我是子类有参构造");
}
public Son6(long num) {
//会默认调用父类无参构造
System.out.println("我是子类有参构造");
}
}
代码分析:在子类中不管写不写super(),都会执行父类无参构造,如果写super(1),将会执行父类有参构造,如果不想调用父类中的无参构造,我们应该写this(1),这样就不会调用父类中的无参构造了,但是最后子类Son6还是带调用了。这样一定会有一个子类方法去调用父类。他们之间不可以循环的调用。最终会导致子类中一定会有一个子类调用父类。
结果:
super关键字
- super和this的用法相像
- this代表对象的引用(谁调用就代表谁)
- super代表当前子类对象父类的引用
- 当子父类出现同名成员时,可以用super进行区分
- 子类要调用父类构造方法时,可以使用super语句
super和this的区别
- this :对象的引用(谁调用就代表谁)
- 使用this关键字引用成员变量。
- 使用this关键字在自身构造方法内部引用其他构造方法。
- 使用this关键字引用成员方法
- super :当前对象里面的父类的引用。
- 在子类的构造方法内部引用父类的构造方法。
- 在子类中调用父类中的成员方法。
- 在子类中调用父类中的成员变量。
package com.demo03;
/*
* this和super的区别
this:当前对象的引用
调用子类的成员变量
调用子类的成员方法
在子类的构造方法第一行调用子类其他构造方法
super:子类对象的父类引用
调用父类的成员变量
调用父类的成员方法
在子类的构造方法第一行调用父类的构造方法
*/
public class ExtendsDemo7 {
public static void main(String[] args) {
Son z = new Son();
z.function();
}
}
//父类
class Parent {
int num = 10;
//无参构造方法
public Parent() {
System.out.println("我是父类无参构造");
}
// 有参构造方法
public Parent(int num) {
System.out.println("我是父类有参构造");
}
// 普通方法
public void method() {
System.out.println("我是父类的方法");
}
}
// 子类
class Son extends Parent {
int num = 30;
public Son() {
this(1);//第一行不调用子类其他构造或者是父类构造,默认调用父类无参构造
//super();
System.out.println("我是子类无参构造");
}
public Son(int num) {
System.out.println("我是子类有参构造");
}
public void method() {
System.out.println("我是子类的方法");
}
public void function() {
//this.num = 50;
//System.out.println(num);
//this.method();
//super.num = 40;
super.method();
//System.out.println(super.num);
//System.out.println(this.num);
}
}
代码分析:我们new了一个子类对象,看到this(1),子类的有参构造方法,但是里边没有super(),默认是父类的无参构造,再执行我是子类有参构造,执行完返回去,执行我是子类有参构造,构造方法执行完毕,再执行z.function。
结果显示:
继承的优缺点
- 缺点:
–类的耦合性增强了
–开发的原则:高内聚低耦合
–内聚:就是自己完成某件事情的能力
–耦合:类与类的关系