【Java基础】-【继承及方法重写】

一、继承

1.继承概述

多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
通过extends关键字可以实现类与类的继承

class 子类名 extends 父类名 {}  

单独的这个类称为父类,基类或者超类;这多个类可以称为子类或者派生类。

2.继承的优点与缺点

①提高了代码的复用性
多个类相同的成员可以放到同一个类中
②提高了代码的维护性
如果功能的代码需要修改,修改一处即可
③让类与类之间产生了关系,是多态的前提
其实这也是继承的一个弊端:类的耦合性很强
开发原则:低耦合,高内聚
耦合:类与类的关系
内聚:独立完成某件事情的能力

3.Java中继承的特点

①Java只支持单继承,不支持多继承。

//一个类只能有一个父类,不可以有多个父类。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error

②Java支持多层继承(继承体系)

class A{}
class B extends A{}
class C extends B{}

4.Java中继承的注意事项

①子类可以继承父类的所有属性和方法,包括私有属性和方法,但是子类是不可以直接的访问父类的private属性和方法。
无论父类中的成员变量是私有的、共有的、还是其它类型的,子类都会拥有父类中的这些成员变量。但是父类中的私有成员变量,无法在子类中直接访问,必须通过从父类中继承得到的protected、public方法(如getter、setter方法)来访问。
②子类不能继承父类的构造方法,但是可以通过super关键字去访问父类构造方法。
不要为了部分功能而去继承。

class A
 {
	public void show1(){}
	public void show2(){}
 }			
class B
 {
	public void show2(){}
	public void show3(){}
 }
		
//我们发现B类中出现了和A类一样的show2()方法,所以,我们就用继承来体现
class B extends A 
{
	public void show3(){}
}
//这样其实不好,因为这样你不但有了show2(),还多了show1()。

我们到底在什么时候使用继承呢?
继承中类之间体现的是:”is a”的关系。

5.继承中成员变量

①子类中的成员变量和父类中的成员变量名称不一样
②子类中的成员变量和父类中的成员变量名称一样
在子类方法中访问一个变量的查找顺序:
a:在子类方法的局部范围找,有就使用
b:在子类的成员范围找,有就使用
c:在父类的成员范围找,有就使用
d:如果还找不到,就报错。

6.this和super区别和应用

区别
-this代表本类对应的引用。
-super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)。
应用
①调用成员变量
-this.成员变量 调用本类的成员变量。
-super.成员变量 调用父类的成员变量。
②调用构造方法
-this(…) 调用本类的构造方法。
-super(…) 调用父类的构造方法。
③调用成员方法
-this.成员方法 调用本类的成员方法。
-super.成员方法 调用父类的成员方法。

7.继承中构造方法的关系

①子类中所有的构造方法默认都会访问父类中空参数的构造方法。
原因:
因为子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化。
每一个构造方法的第一条语句默认都是:
super()[表示调用父类的无参构造]
②如果父类没有无参构造方法,那么子类的构造方法会出现报错现象。
解决方法:
A:在父类中加一个无参构造方法
B:通过使用super关键字去显示的调用父类的带参构造方法
C:子类通过this去调用本类的其他构造方法。
-子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。
super(…)或者this(….)必须出现在第一条语句上,否则,就会有父类数据的多次初始化

class Father
 {
	/*
	public Father() 
	{
		System.out.println("Father的无参构造方法");
	}
	*/
	
	public Father(String name) 
	{
		System.out.println("Father的带参构造方法");
	}
}

class Son extends Father 
{
	public Son() 
	{
		super("随便给");
		System.out.println("Son的无参构造方法");
		//super("随便给");
	}
	
	public Son(String name)
	 {
		//super("随便给");
		this();
		System.out.println("Son的带参构造方法");
	}
}

思考题:
思考1:
看程序写结果
看程序写结果:

class Fu {
	static {
		System.out.println("静态代码块Fu");
	}

	{
		System.out.println("构造代码块Fu");
	}

	public Fu() {
		System.out.println("构造方法Fu");
	}
}

class Zi extends Fu {
	static {
		System.out.println("静态代码块Zi");
	}

	{
		System.out.println("构造代码块Zi");
	}

	public Zi() {
		System.out.println("构造方法Zi");
	}
}

class ExtendsTest2 {
	public static void main(String[] args) {
		Zi z = new Zi();
	}
}

答:

A:一个类的静态代码块,构造代码块,构造方法的执行流程
	静态代码块 > 构造代码块 > 构造方法
B:静态的内容是随着类的加载而加载
	静态代码块的内容会优先执行
C:子类初始化之前先会进行父类的初始化
	
结果是:
	静态代码块Fu
	静态代码块Zi
	构造代码块Fu
	构造方法Fu
	构造代码块Zi
	构造方法Zi

—————————————————————————

思考二
看程序写结果:
class X 
{
	Y b = new Y();
	X() {
		System.out.print("X");
	}
}

class Y 
{
	Y() {
		System.out.print("Y");
	}
}

public class Z extends X
 {
	Y y = new Y();
	Z() {
		//super
		System.out.print("Z");
	}
public static void main(String[] args) 
	{
		new Z(); 
	}
}

答:

A:成员变量的问题
	int x = 10; //成员变量是基本类型
	Student s = new Student(); //成员变量是引用类型
B:一个类的初始化过程
	成员变量的初始化
		默认初始化
		显示初始化
	构造方法初始化
C:子父类的初始化(分层初始化)
	先进行父类初始化,然后进行子类初始化。
		
结果:
	YXYZ
	
问题:
	虽然子类中构造方法默认有一个super()
	初始化的时候,不是按照那个顺序进行的。
	而是按照分层初始化进行的。
	它仅仅表示要先初始化父类数据,再初始化子类数据。

8.继承中成员方法的关系

①子类中的方法和父类中的方法声明不一样。
②子类中的方法和父类中的方法声明一样。
通过子类对象调用方法:
a:先找子类中,看有没有这个方法,有就使用
b:再看父类中,有没有这个方法,有就使用
c:如果没有就报错。

二、方法重写

1.方法重写概述

子类中出现了和父类中方法声明一模一样的方法。
-如果方法名不同,就调用对应的方法。
-如果方法名相同,最终使用的是子类自己的。

2.方法重写应用

当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。这样,即沿袭了父类的功能,又定义了子类特有的内容。

案例:
	A:定义一个手机类。
	B:通过研究,我发明了一个新手机,这个手机的作用是在打完电话后,可以听天气预报。
	按照基本的设计把代码给写出。
	但是,又发现新手机应该是手机,所以,它应该继承自手机。
	其实这个时候的设计,并不是最好的。
	因为手机打电话功能,是手机本身就具备的最基本的功能。
	所以,我的新手机是不用在提供这个功能的。
	但是,这个时候,打电话功能就没有了。这个不好。
	最终,还是加上这个功能。由于它继承了手机类,所以,我们就直接使用父类的功能即可。
	那么,通过super关键字调用使用父类的功能

class Phone
 {
	public void call(String name) {
		System.out.println("给"+name+"打电话");
	}
}

class NewPhone extends Phone
 {
	public void call(String name) {
		//System.out.println("给"+name+"打电话");
		super.call(name);
		System.out.println("可以听天气预报了");
	}
}

class ExtendsDemo
 {
	public static void main(String[] args) {
		NewPhone np = new NewPhone();
		np.call("石原里美");
	}
}

3.方法重写注意事项

①父类中私有方法不能被重写。
-因为父类私有方法子类根本就无法继承。
②子类重写父类方法时,访问权限不能更低。
-最好就一致。
③父类静态方法,子类也必须通过静态方法进行重写。[多态]
思考题:

思考1
Override和Overload的区别?方法重载能改变返回值类型吗?

答:
方法重写:在子类中,出现和父类中一模一样的方法声明的现象。
方法重载:同一个类中,出现的方法名相同,参数列表不同的现象。
方法重载能改变返回值类型,因为它和返回值类型无关。
—————————————————————————

思考2
this关键字和super关键字分别代表什么?以及他们各自的使用场景和作用。

答:
this:代表当前类的对象引用
super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员)
场景:
——成员变量:
-this.成员变量
-super.成员变量
——构造方法:
-this(…)
-super(…)
——成员方法:
-this.成员方法
-super.成员方法

4.final关键字

由于继承中方法有一个现象:方法重写。所以,父类的功能,就会被子类给覆盖调。
而有些时候,我们不想让子类去覆盖掉父类的功能,只能让他使用。这个时候,针对这种情况,Java就提供了一个关键字:final
final概述
final关键字是最终的意思,可以修饰类,成员变量,成员方法。
-修饰类,类不能被继承。
-修饰变量,变量就变成了常量,只能被赋值一次。
-修饰方法,方法不能被重写。
思考题

思考1:
final修饰局部变量的问题:

class Student
 {
int age = 10;
}
class FinalTest
 {
	public static void main(String[] args)
	 {
		//局部变量是基本数据类型
		int x = 10;
		x = 100;
		System.out.println(x);
		final int y = 10;
		//无法为最终变量y分配值
		//y = 100;
		System.out.println(y);
		System.out.println("--------------");
		
		//局部变量是引用数据类型
		Student s = new Student();
		System.out.println(s.age);
		s.age = 100;
		System.out.println(s.age);
		System.out.println("--------------");
		
		final Student ss = new Student();
		System.out.println(ss.age);
		ss.age = 100;
		System.out.println(ss.age);
		
		//重新分配内存空间
		//无法为最终变量ss分配值
		//ss = new Student();
	}
}

答:
final修饰局部变量为基本类型时,基本类型的值不能发生改变。
final修饰局部变量为引用类型时,引用类型的地址值不能发生改变,但是,该对象的堆内存的值是可以改变的。
—————————————————————————

思考2:
final修饰变量的初始化时机
class Demo
 {
	//int num = 10;
	//final int num2 = 20;
	
	int num;
	final int num2;
	
	{
		//num2 = 10;
	}
	
	public Demo() {
		num = 100;
		//无法为最终变量num2分配值
		num2 = 200;
	}
}

class FinalTest2 
{
	public static void main(String[] args)
	{
		Demo d = new Demo();
		System.out.println(d.num);
		System.out.println(d.num2);
	}
}

答:
①被final修饰的变量只能赋值一次。
②在构造方法完毕前。(仅针对非静态的常量)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值