java练习-继承和多态05

目录

    • 1 继承的概念
    • 2 this和super的区别和应用
    • 3 继承中的面试题1
    • 4 继承中的面试题2
    • 5 方法重写
    • 6 final关键字引入
    • 7 面试题:final修饰局部变量的问题
    • 8 final修饰变量的初始化时机
    • 9 多态的概念
    • 10 多态的练习题-看程序写结果

1 继承的概念

继承概述:
	把多个类中相同的内容给提取出来定义到一个类中。
	
如何实现继承呢?	
	Java提供了关键字:extends
	
格式:
	class 子类名 extends 父类名 {}
	
好处:
	A:提高了代码的复用性
	B:提高了代码的维护性
	C:让类与类之间产生了关系,是多态的前提

类与类产生了关系,其实也是继承的一个弊端:
	类的耦合性增强了。
	
	开发的原则:低耦合,高内聚。
	耦合:类与类的关系
	内聚:就是自己完成某件事情的能力
继承的注意事项:
	A:子类只能继承父类所有非私有的成员(成员方法和成员变量)
	B:子类不能继承父类的构造方法,但是可以通过super(马上讲)关键字去访问父类构造方法。
	C:不要为了部分功能而去继承
那么,我们什么时候考虑使用继承呢?
		继承其实体现的是一种关系:"is a"。
			Person
			Student
			Teacher
		水果
			苹果
			香蕉
			橘子
	采用假设法。
		如果有两个类A,B。只有他们符合A是B的一种,或者B是A的一种,就可以考虑使用继承。
类的组成:
	成员变量:
	构造方法:
	成员方法:
而现在我们又讲解了继承,所以,我们就应该来考虑一下,类的组成部分的各自关系。

继承中成员变量的关系:
	A:子类中的成员变量和父类中的成员变量名称不一样,这个太简单。
	B:子类中的成员变量和父类中的成员变量名称一样,这个怎么玩呢?
		在子类方法中访问一个变量的查找顺序:
			a:在子类方法的局部范围找,有就使用
			b:在子类的成员范围找,有就使用
			c:在父类的成员范围找,有就使用
			d:如果还找不到,就报错。
继承中成员方法的关系:
	A:子类中的方法和父类中的方法声明不一样,这个太简单。
	B:子类中的方法和父类中的方法声明一样,这个该怎么玩呢?
		通过子类对象调用方法:
			a:先找子类中,看有没有这个方法,有就使用
			b:再看父类中,有没有这个方法,有就使用
			c:如果没有就报错。

例子:

package cn.plsite.day04.demo04;

public class FatherClass {
    int age;

    public FatherClass(int age){
        System.out.println("Father有参构造方法");
    }
    public FatherClass(){
        System.out.println("Father无餐构造方法");
    }
}

package cn.plsite.day04.demo04;

public class SonClass extends FatherClass{
    int age;
    public SonClass(){
        System.out.println("Son无参数构造");
    }
    public SonClass(int age){
        System.out.println("Son有参数构造");
    }


}

package cn.plsite.day04.demo04;

public class FatherAndSon {
    public static void main(String[] args) {
        SonClass son = new SonClass();
        SonClass son1 = new SonClass(14);
    }
}

运行结果:

Father无餐构造方法
Son无参数构造
Father无餐构造方法
Son有参数构造

2 this和super的区别和应用

this和super的区别?
	分别是什么呢?
		this代表本类对应的引用。
		super代表父类存储空间的标识(可以理解为父类引用,可以操作父类的成员)

	怎么用呢?
		A:调用成员变量
			this.成员变量  调用本类的成员变量(成员为非私有)
			super.成员变量  调用父类的成员变量(成员为非私有)
		B:调用构造方法
			this(...)	调用本类的构造方法
			super(...)	调用父类的构造方法
		C:调用成员方法
			this.成员方法  调用本类的成员方法
			super.成员方法  调用父类的成员方法


如果父类没有无参构造方法,那么子类的构造方法会出现什么现象呢?
	报错。
如何解决呢?	
	A:在父类中加一个无参构造方法
	B:通过使用super关键字去显示的调用父类的带参构造方法
	C:子类通过this去调用本类的其他构造方法
		子类中一定要有一个去访问了父类的构造方法,否则父类数据就没有初始化。
		
注意事项:
	this(...)或者super(...)必须出现构造方法在第一条语句上。
	如果不是放在第一条语句上,就可能对父类的数据进行了多次初始化,所以必须放在第一条语句上。

3 继承中的面试题1

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

程序:

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();
	}
}

结果是:

静态代码块Fu
	静态代码块Zi
	构造代码块Fu
	构造方法Fu
	构造代码块Zi
	构造方法Zi

4 继承中的面试题2

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

题目:

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(); 
	}
}

答案:

YXYZ

5 方法重写

方法重写:
子类中出现了和父类中方法声明一模一样的方法。

方法重载:
	本类中出现的方法名一样,参数列表不同的方法。与返回值无关。

子类对象调用方法的时候:
	先找子类本身,再找父类。
	
方法重写的应用:
	当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法。
	这样,即沿袭了父类的功能,又定义了子类特有的内容。
方法重写的注意事项
	A:父类中私有方法不能被重写
		因为父类私有方法子类根本就无法继承
	B:子类重写父类方法时,访问权限不能更低
		最好就一致
	C:父类静态方法,子类也必须通过静态方法进行重写,重写时候不能使用@override,如果使用会报错		
	子类重写父类方法的时候,最好声明一模一样。
	
1.方法重写和方法重载的区别?方法重载能改变返回值类型吗?
方法重写:在子类中,出现和父类中一模一样的方法声明的现象。		
方法重载:同一个类中,出现的方法名相同,参数列表不同的现象。方法重载能改变返回值类型,因为它和返回值类型无关。
Override:方法重写
Overload:方法重载

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

this:代表当前类的对象引用
super:代表父类存储空间的标识。(可以理解为父类的引用,通过这个东西可以访问父类的成员)

场景:
	成员变量:
		this.成员变量
		super.成员变量
	构造方法:
		this(...)
		super(...)
	成员方法:
		this.成员方法
		super.成员方法

6 final关键字引入

继承的代码体现
由于继承中方法有一个现象:方法重写。
所以,父类的功能,就会被子类给覆盖调。
有些时候,我们不想让子类去覆盖掉父类的功能,只能让他使用。
这个时候,针对这种情况,Java就提供了一个关键字:final

final:最终的意思。常见的是它可以修饰类,方法,变量。
class Fu {
	public final void show() {
		System.out.println("这里是绝密资源,任何人都不能修改");
	}
}

class Zi extends Fu {
	// Zi中的show()无法覆盖Fu中的show()
	//public void show() {
	//	System.out.println("这是一堆垃圾");
	//}
}

class ZiDemo {
	public static void main(String[] args) {
		Zi z = new Zi();
		z.show();
	}
}
final可以修饰类,方法,变量

特点:
	final可以修饰类,该类不能被继承。
	final可以修饰方法,该方法不能被重写。(覆盖,复写)
	final可以修饰变量,该变量不能被重新赋值。因为这个变量其实常量。
	
常量:
	A:字面值常量
		"hello",10,true
	B:自定义常量
		final int x = 10;

7 面试题: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();
	}
}

结果:

100
10
--------------
10
100
--------------
10
100

8 final修饰变量的初始化时机

	A:被final修饰的变量只能赋值一次。
	B:在构造方法完毕前。(非静态的常量)
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);
	}
}

9 多态的概念

多态:同一个对象(事物),在不同时刻体现出来的不同状态。
举例:
	猫是猫,猫是动物。
	水(液体,固体,气态)。
	
多态的前提:
	A:要有继承关系。
	B:要有方法重写。
		其实没有也是可以的,但是如果没有这个就没有意义。
			动物 d = new 猫();
			d.show();
			动物 d = new 狗();
			d.show();
	C:要有父类引用指向子类对象。
		父 f =  new 子();
		
用代码体现一下多态。

多态中的成员访问特点:
	A:成员变量
		编译看左边,运行看左边。
	B:构造方法
		创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
	C:成员方法
		编译看左边,运行看右边。
	D:静态方法
		编译看左边,运行看左边。
		(静态和类相关,算不上重写,所以,访问还是左边的)
		
	由于成员方法存在方法重写,所以它运行看右边。
	多态的分类:
		a:具体类多态
			class Fu {}
			class Zi extends Fu {}
			
			Fu f = new Zi();
		b:抽象类多态
			abstract class Fu {}
			class Zi extends Fu {}
			
			Fu f = new Zi();
		c:接口多态
			interface Fu {}
			class Zi implements Fu {}
			
			Fu f = new Zi();
class Fu {
	public int num = 100;

	public void show() {
		System.out.println("show Fu");
	}
	
	public static void function() {
		System.out.println("function Fu");
	}
}

class Zi extends Fu {
	public int num = 1000;
	public int num2 = 200;
//重写父类
	public void show() {
		System.out.println("show Zi");
	}
	
	public void method() {
		System.out.println("method zi");
	}
	
	public static void function() {
		System.out.println("function Zi");
	}
}

class DuoTaiDemo {
	public static void main(String[] args) {
		//要有父类引用指向子类对象。
		//父 f =  new 子();
		Fu f = new Zi();
		System.out.println(f.num);//100
		//找不到符号
		//System.out.println(f.num2);
		
		f.show();
		//找不到符号
		//f.method();
		f.function();
	}
}
多态的好处:
	A:提高了代码的维护性(继承保证)
	B:提高了代码的扩展性(由多态保证)
多态的弊端:
	不能使用子类的特有功能。
对象间的转型问题:
		向上转型:
			Fu f = new Zi();
		向下转型:
			Zi z = (Zi)f; //要求该f必须是能够转换为Zi的。

10 多态的练习题-看程序写结果

看程序写结果:先判断有没有问题,如果没有,写出结果

多态的成员访问特点:
	方法:编译看左边,运行看右边。
	
继承的时候:
	子类中有和父类中一样的方法,叫重写。
	子类中没有父亲中出现过的方法,方法就被继承过来了。
class A {
	public void show() {
		show2();
	}
	public void show2() {
		System.out.println("我");
	}
}
class B extends A {
	/*
	public void show() {
		show2();
	}
	*/

	public void show2() {
		System.out.println("爱");
	}
}
class C extends B {
	public void show() {
		super.show();
	}
	public void show2() {
		System.out.println("你");
	}
}
public class DuoTaiTest4 {
	public static void main(String[] args) {
		A a = new B();
		a.show();
		
		B b = new C();
		b.show();
	}
}

运行结果:

爱
你

你可能感兴趣的:(java)