Java学习笔记-语法篇[继承与多态]

[Java语法篇2] 继承与多态

一、Java类的继承

1.继承定义与结构

1)继承的定义:

继承是一种基于已有类(被称为父类或派生类)创建新类(被称为子类或派生类) 的一种方式
子类继承父类的成员变量(包括值)方法

2)继承的结构

访问权限 class 子类名 extends 父类名{ }

//父类结构
public class Father{
	String name;
	String mobile;
	int age;
	//...
}
//子类继承父类
public class Son extends Father{
	String address;
	//...
}

2.继承的特点

1)Object类是所有类的父类

即使创建类时不加extends Object,创建的类仍是Object的子类

2)Java只有单继承,没有多继承

每个类只能是一个类的子类,不存在一个类是多个类的子类

//Java中不允许存在如下代码,只能单继承
public class Son extends Father1,Father2{
	String address;
	//...
}
3)一个类如果有final修饰,则该类没有子类,即不能被继承

常见的由final修饰的类:String、System、基本数据类型的包装类(Integer、Byte、Short、Long、Double、Float、Double、Boolean、Character)

//此时父类结构不可被继承
final class Father{
	String name;
	String mobile;
	int age;
	//...
}
4)并不是父类所有的方法和成员变量子类都可以继承(private 修饰就不可以)
//此时父类结构不可被继承
public class Father{
	String name;
	String mobile;
	private String hobbit;//此变量不可被子类继承
	int age;
	//...
}
3)如果子类成员变量“名”和父类相同,则子类对象调用的是子类中的变量;(不考虑数据类型,只考虑名字)
//父类结构
public class Father{
	String name = “张氏”;
	String mobile;
	int age = 42;
	//...
}
//子类继承父类
public class Son extends Father{
	String address;
	String age = "18";
	//age变量名与父类的成员变量的变量名同
	
	public static void main(String[] args){
		Son son = new Son();
		
		System.out.println(son.name);
		//此时输出为父类成员变量name的值"张氏"
		
		System.out.println(son.age);
		//此时输出的应为子类成员变量age的值“18”
	}
}

二、继承时子类的重写

1.重写的原因

重写即重新改写父类的方法,为了使子类更准确地描述描述子类的行为特征

//父类结构
public class Father{
	String name = “张氏”;
	String mobile;
	int age = 42;
	
	public void showName(){
		System.out.println("张氏");
	}
	
	public void showRelation(){
		System.out.println("This is father");
	}
	
}
//子类继承父类
public class Son extends Father{
	String address;
	String age = "18";
	
	public void showRelation(){
		System.out.println("This is son");
	}
	
	public static void main(String[] args){
		
		Son son = new Son();
		son.showName();
		//此时调用的是子类从父类继承过来且没有重写的方法,输出“张氏”
		son.showRelation();
		//此时调用的是子类重写后的方法,输出“This is son”
				
	}
	
}

注:改写后的方法可以使用 @Override注解 修饰(不是注释)

2.重写的注意事项

1)访问权限问题
重写后的方法访问权限要么与父类相同,要么大于父类的访问权限

访问权限大小顺序:public > protected > 默认 > private
private修饰的方法就不能被继承

//父类结构
public class Father{
	String name = “张氏”;
	String mobile;
	int age = 42;
	
	void showRelation(){
		System.out.println("This is father");
	}
	
}
//子类继承父类
public class Son extends Father{
	String address;
	String age = "18";
	
	public void showRelation(){
		System.out.println("This is son");
	}
	//访问权限由 默认 提升为 public
	
}
2)修饰符问题

父类final修饰的方法,子类不能重写但可以继承
父类中static修饰的方法,子类不能重写但可以继承
子类重写后的方法不能添加static修饰
父类private修饰的方法就不能被继承,所以也不能被重写。

3)重写方法的方法名与参数列表

重写后的方法,方法名必须与父类方法名相同,参数列表除了名字不做限制外,其余必须一样

//父类结构
public class Father{
	
	public int Test(int x, int y, int z){
		return x+y+z;
	}
	
}
//子类继承父类
public class Son extends Father{
	
	public int Test(int a, int b, int c){
		return a-b+c;
	}
	//方法名同
	//参数列表:参数数目同
	//		   参数类型同
	//		   参数名可以不同
	
}
4)返回值问题

如果 父类方法返回值的数据类型为void或基本数据类型,则 重写后的方法返回值类型必须与父类方法保持一致
如果 父类方法返回值的数据类型为引用类型,则 重写后方法的返回值要么与父类一致要么是父类方法的返回值的类型的子类

//父类结构
public class Father{
	
	public int Test1(int x){
		return x;
	}

	public Object Test2(Object x){
		return x;
	}
	
}
//子类继承父类
public class Son extends Father{
	
	public int Test1(int x){
		return x*x;
	}
	//父类方法返回值为int(基本数据类型),子类重写后必须为int

	public String Test2(Object x){
		return x;
	}
	//父类方法返回值为引用类(Object),子类重写后返回值可以为其子类 String

	/*
	public Object Test2(Object x){
		return x;
	}
	//父类方法返回值为引用类,子类重写后可以保持一致
	*/
	
}

三、Java的多态

1、详述Java多态;2、总结String类常用方法;3、详述父类构造方法对子类构造方法影响;

1.多态的引入

观察如下代码

//哺乳动物类
public class Mammal {
	
	String weight = "2.5KG";
	
	public void move() {
		
		System.out.println("正在移动");
		
	}
	
}
//蝙蝠类,继承哺乳动物类
public class Bat extends Mammal{
	
	double weight = 2.5;
	
	public void eat() {
		
		System.out.println("进食飞蛾");
		
	}
	
	@Override
	public void move() {
		
		System.out.println("靠翅飞行");
		
	}
	
}

//测试代码
public class Test {

	public static void main(String[] args) {
		
		Bat bat = new Bat();
		bat.move();

		Mammal mammal = new Bat();
		mammal.move();//Java多态的表现
	}

}

2.Java多态的定义

Java中小范围精度的数据可以直接赋值给大范围数据类型变量,java的不同类间也存在类似的规则
定义:父类类型(比如Mammal)的变量(比如mammal)指向子类创建的对象,使用该变量调用父类中一个被子类重写的方法(比如move方法),则父类中的方法呈现出不同的行为特征,这就是多态。
结构:父类名 变量名 = new 子类名();

//测试代码
public class Test {

	public static void main(String[] args) {

		Mammal mammal = new Bat();
		//父类名 变量名 = new 子类名();
		mammal.move();//Java多态的表现,调用的是子类重写后的方法
		
	}

}

3.Bat bat = new Bat();与Mammal mammal = new Bat();创建的对象在编译执行时的区别

以调用类中move()方法为例
前者:bat.move();
编译时:由于变量类型为子类类型,所以编译时调用的子类(Bat)的move方法
运行时:执行时,bat指向的就是子类(Bat)创建的对象,所以调用子类(Bat)重写后的move方法;
后者(多态的表现):mammal.move();
编译时:由于变量类型为父类类型,所以编译时调用的父类(Mammal)的move方法
运行时:执行时,mammal指向的就是子类(Bat)创建的对象,所以调用子类(Bat)重写后的move方法;

4.多态的特点

1)编译时和运行时类型不一致,否则一定不会产生多态
2)编译时调用的方法一定被子类所重写
3)父类类型变量 = 子类创建的对象(又称为上转型对象)

5.上转型对象的特点

1)上转型对象不能调用子类"新增"的属性和方法
//哺乳动物类
public class Mammal {
	
	String weight = "2.5KG";
	
	public void move() {
		
		System.out.println("正在移动");
		
	}
	
}
//蝙蝠类,继承哺乳动物类
public class Bat extends Mammal{
	
	double weight = 2.5;
	
	public void eat() {
		
		System.out.println("进食飞蛾");
		
	}//子类新增方法,不可被上转型对象调用
	
	@Override
	public void move() {
		
		System.out.println("靠翅飞行");
		
	}
	
}

//测试代码
public class Test {

	public static void main(String[] args) {
		
		Bat bat = new Bat();
		bat.move();

		Mammal mammal = new Bat();
		mammal.move();//Java多态的表现
		//mammal.eat();//此代码不可用,因为上转型对象mammal不可调用子类新增方法
	}

}

注:上转型对象如果必须调用子类新增的属性和方法,则必须下转型
//测试代码
public class Test {

	public static void main(String[] args) {
		
		Bat bat = new Bat();
		bat.move();

		Mammal mammal = new Bat();
		mammal.move();//Java多态的表现
		Bat b = (Bat) mammal;//对上转型对象进行下转型处理,相当于创建了一个新的变量,但没有创建新的空间
		b.eat();//下转型对象调用子类新增方法

		Mammal mammals = new Mammal();
		//Bat bb = (Bat) mammals; //此代码不正确,因为变量mammals中指向的对象为非上转型对象,不可进行下转型处理

	}

}

2)只有上转型对象可以进行下转型操作,非上转型对象不可进行下转型处理
//测试代码
public class Test {

	public static void main(String[] args) {

		Mammal mammals = new Mammal();
		//Bat bb = (Bat) mammals; //此代码不正确,因为变量mammals中指向的对象为非上转型对象,不可进行下转型处理

	}

}

3)如果子类成员变量与父类成员变量名字重复(不考虑数据类型),则上转型对象调用的是父类中的成员变量

注:注意区分和继承时的关系,继承后父类变量与子类变量名一致时,正常创建的子类对象调用时调用的是子类的成员变量对应的值,创建的上转型对象则是采用的是父类变量对应的值

//哺乳动物类
public class Mammal {
	
	String weight = "2.5KG";
	
}
//蝙蝠类,继承哺乳动物类
public class Bat extends Mammal{
	
	double weight = 2.5;
	
}

public class Test {

	public static void main(String[] args) {
		
		Mammal mammal = new Bat();
	    System.out.println(mammal.weight);//变量指向的时上转型对象,调用的时由于同名,调用父类的成员变量的值

		Bat bat = new Bat();
		System.out.println(bat.weight);//变量指向的是正常创建的子类对象,调用时由于同名,调用子类成员变量的值
	    
	}

}

发布了7 篇原创文章 · 获赞 3 · 访问量 160

猜你喜欢

转载自blog.csdn.net/FishFinger1214/article/details/104762490