【Java类的继承与多态→多态性,对象的转型】懒惰的小黑笔记04(小白一名,请大家多指点)

5.3多态性

声明: 此笔记通过观看【尚学堂】+《Java程序设计(赖小平主编)清华大学出版社》感悟整理得出, 若有抄袭,请注明来源联系作者!

多态(polymorphism):多种形态

多态指的是同一个方法调用,由于对象不同可能会有不同的行为。例如:猫、狗是动物,但它们有不同的形态,狗的叫声:旺旺旺,猫的叫声是:喵喵喵~
在面向对象的程序设计中,多态性主要表现为类声明的变量可指向多种不同的对象,其有多种类型的能力。

多态存在的三个条件:继承、方法重写、父类引用指向子类引用

变量不具有多态性!!!!!!
变量不具有多态性!!!!!!
变量不具有多态性!!!!!!
静态(即类变量类方法)也不具有多态!

多态主要表现为:方法的多态性。变量不具有多态!!!!!,静态(即类变量类方法)也不具有多态

优点:极大的增强了程序的可扩展性,提高了代码的可维护性。

【测试 动物类的多态】

package cn.gdlgxy.David;

class Animal{
	public void shout() {
		System.out.println("叫....");
	}
}
class Dog extends Animal{
	public void shout() {
		System.out.println("汪汪汪....");
	}
	public void Look() {
		System.out.println("看门口");
	}
	
}
class Cat extends Animal{
	public void shout() {
		System.out.println("喵喵喵.....");
	}
}

public class PolyTest {
	public static void main(String[] args) {
		Animal a = new Animal();
		animalShout(a);
		
		Animal d = new Dog();//也可以写成Dog b = new Dog();
		animalShout(d);
		
		//产生多态。子类对象Dog给父类Animal引用,a是Animal类型,调用shout方法。
		//b传的是Dog,则是调用Dog的shout()方法,传猫则调用猫的shout()方法
		animalShout(new Cat());
		}
	static void animalShout(Animal a) {
		a.shout();
	}
	/*
	 * 若无多态,则需要创建更多的animalshout()方法
	 *若传的是狗则需: 
	 *	static void animalShout(Dog a) {
		a.shout();
	}
	   Dog b = new Dog();
		animalShout(b);
	
	 * 若传的是猫则与上同理。所以代码较为复杂。这就是多态的好处,使代码更加简洁
	 */
}

结果:

叫….
汪汪汪…
喵喵喵…

5.4对象的转型

  • 变量的多态性:

    对象的变量可以引用本类的对象,也可以引用子类的对象。就是说,对象的真正类型是由常见对象时调用的构造方法决定的,这就是对象变量的多态。(如上转型对象)

父类引用指向子类对象→向上转型,属于自动类型转换;
向上转型后的父类引用变量只调用它编译类型的方法,若要调用子类的新增方法,则需要强制转型→向下转型

【实例测试】

public class PolyTest {
	public static void main(String[] args) {
		Animal a = new Animal();
		animalShout(a);
		
		Animal d = new Dog();//也可以写成Dog d = new Dog();
		animalShout(d);
		
		//产生多态。子类对象Dog给父类Animal引用,a是Animal类型,调用shout方法。
		//b传的是Dog,则是调用Dog的shout()方法,传猫则调用猫的shout()方法
		animalShout(new Cat());
		
	/*对象的转型:
	 * Animal b = new Dog();
	 *自动向上转型,编译器认为 d 就是Animal,若 d 想调用Dog的其它方法,
	 *则需要进行强制转型:   Dog d1 = (Dog)d;  强制向下转型
	 *                  d1.Look();
	 *注意:
	 *若:       Animal c = new Cat();
	 *       Dog d2 = (Dog)c;
	 *       编译会通过,但是,运行会出现 java.lang.ClassCatException:
	 *       猫不能强制转型为狗。
	 */
		
	}
	static void animalShout(Animal a) {
		a.shout();
	}

注:部分代码在上节

  • 上转型的特征:

1、 上转型对象只能访问父类中声明的成员变量和成员方法,不可以访问子类新增的成员变量和成员方法。
2、 如果子类重写了父类的方法,则向上转型的对象调用的方法则是重写后的方法
3、 如果父类重新定义了父类的同名变量,则上转型对象引用该变量时是父类定义的变量,而不是子类中定义的变量

【实例测试 向上转型对象】

package cn.gdlgxy.David;

class Animal02{
	public final String type = "动物";
	private String name;
	public Animal02(String name) {
		this.name = name;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	
	public void shout02(){
		System.out.println("不同动物不同叫声");
	}
}
class Dog02 extends Animal02{
	public final String type = "狗";
	private String color;
	public Dog02(String name,String color) {
		super(name);
		this.color = color;
	}
	public String getColor() {
		return color;
	}
	public void setColor(String color) {
		this.color = color;
	}
	public void shout02() {
		System.out.println(getName()+"汪汪汪....");
	}
	public void Look() {
		System.out.println("看门口");
	}
	
}
class Cat02 extends Animal{
	public void shout02() {
		System.out.println("喵喵喵.....");
	}
}

public class PloyTest02 {
	public static void main(String[] args) {
		System.out.println("====向上转型对象====");
		Animal02 dog = new Dog02("旺财","黑色");
		System.out.println("该对象是:"+dog.type);
						//上转型对象引用覆盖变量时父类中定义的变量
		dog.shout02();	//上转型对象调用重写后的方法
		//System.out.println("动物颜色为:"+dog.getColor());
		//编译报错,上转型对象不能访问子类新增的方法
		
	}

}

结果:
上转型结果

重新观看《懒惰的小黑笔记02》操作符instanceof,加深了解!

5.5 final关键字

- final关键字的作用:

  • 1、 修饰变量:

(1)被修饰的变量一旦赋值就不可以被重新赋值
(2)final修饰的成员变量必须在构造器结束前赋值,即可在声明的同时赋值,在构造方法中赋值,或在静态代码块中赋值,其后不可更改。
(3)static与final共同修饰的变量,将其看做常量,大写字母命名,且在声明时赋值
final int 变量(一般用大写,每个单词用“_”分开) = 51;

  • 2、 修饰方法:

该方法不能被子类重写,但可以重载(在一定程度上,final方法的执行效率高,因为在调用该方法时,JVM不需要进行重写判断)

final void rest(){}

  • 3、 修饰类:

修饰的类不能继承,比如:Math、String等

public final class FinalTest{…} class Student extends
FinalTest{….} //编译出错,final类不能被继承

第五章 应用实例

【实例 测试图形派的继承】

package cn.gdlgxy.test;
import java.util.Scanner;
/**
 * 测试图形类
 * @author 卟淡
 *
 */
class Geom {
	private String color;
	private boolean isFilled;
	public Geom() {		//无参构造方法,方便输入
		
	}
	public Geom(String color,boolean isFilled) {		//有参构造方法
		this.color = color;
		this.isFilled = isFilled;
	}
	public String getColor() {  
		return color;
	}
	public void setColor(String color) {				//设置颜色
		this.color = color;
	}
	public Boolean getIsFilled() {
		return isFilled;
	}
	public void setIsFilled(Boolean isFilled) {			//设置填充
		this.isFilled = isFilled;
	}
	public String toString() {							//toString方法
		return "构建图形颜色:"+color+"\n是否填充:"+isFilled;
	}
}

//继承圆形类的矩形类
class Rectangle extends Geom{
	private double length;
	private double width;
	
	public Rectangle() {
		
	}
	public Rectangle(String color,boolean isFilled,double length
			,double width) {
		super(color,isFilled);
		this.length = length;
		this.width =width;
	}
	public double getLength() {
		return length;
	}
	public void setLength(double  length)throws Exception {
		if(length<0)throw new Exception("长不能小于0");
		this.length = length;
	}
	public double getWidth() {
		return width;
	}
	public void setWidth(double width)throws Exception {
		if(width<0)throw new Exception("宽不能小于0");
		this.width = width;
	}
	public double getArea() {
		return length*width;
	}
}

//继承矩形的长方形类
class Rectlinder extends Rectangle{
	private double higth;
	
	public Rectlinder() {
		
	}
	public Rectlinder(String color,boolean isFilled,double length
			,double width,double higth) {
		super(color,isFilled,length,width);
		this.higth = higth;
	}
	public double getHigth() {
		return higth;
	}
	public void setHigth(double higth) {
		this.higth = higth;
	}
	public double getVolume() {
		return getArea()*higth;
	}
	public String toString() {
		return super.toString() + "\n长方形的体积为:"+getVolume();
	}
}

//测试类
public class GeomTest {
	public static void main(String[] args) {
		
		while(true) {
			Scanner sc = new Scanner(System.in);
			double L,w,h;
			String color;
			boolean isFilled;
			System.out.println("输入颜色、填充(true/false)、底面长、宽和高:");
			
			color = sc.nextLine();
			isFilled = sc.nextBoolean();
			L = sc.nextDouble();
			w = sc.nextDouble();
			h = sc.nextDouble();
				
			Rectlinder rectliner = new Rectlinder(color,isFilled,L,w,h);
			System.out.println(rectliner.toString());
			
		}
	}
}

【正确答案:】

// 有个疑问点:color是String类型,输入的不是颜色也能通过编译!!


/*
 * 《java程序设计》答案:
 * try {
	Scanner sc = new Scanner(System.in);
	double L,w,h;
	String color;
	boolean isFilled;
	while(true) {
		System.out.print("请输入空格分隔的长方形的颜色、填充(true/false)、底面长"
			+ "宽和高\n(end结束程序)");
	color =sc.nextLine();
	if(color.equals("end")) {     //equals类→查看源码
		System.out.println("程序结束");
		return;
		}
	isFilled = sc.nextBoolean();
	L = sc.nextDouble();
	w = sc.nextDouble();
	h = sc.nextDouble();
	Rectlinder rectliner = new Rectlinder(color,isFilled,L,w,h);
	System.out.println(rectliner.toString());
  }
}catch(Exception e) {
	System.out.println(e);
		}
	}
}*/

【编译结果:】
图形类派生结果
【测试 动物的多态】

package cn.gdlgxy.test;
import java.util.Scanner;
/**
 * 测试动物的多态性
 * @author 卟淡
 *
 */
//动物类
class Animal{
	private String name;
	private int legs;
	public Animal(){   //给成员变量赋值
		this.name = "人";
		this.legs = 4;	
	}
	public Animal(String name,int legs) { //带参数的构造方法
		this.name = name;
		this.legs = legs;
	}
	public String getName() {		//获取名称
		return name;
	}
	public void setName(String name ) {	//设置名称
		this.name = name;
	}
	public int getLegs() { 		//获取腿数
		return legs;
	}
	public void setLegs(int legs)throws Exception {	//设置腿数
		if(legs<0)throw new Exception("输入的腿数有误");
		this.legs = legs;
	}
	public void move() {		//创建move()方法
		System.out.println(name + "在移动"+",他有"+legs+"条腿");
	}
	public void move(int n) {	//带参数的move()方法
		if(n>=0) {
			System.out.println("移动了"+n+"次" );
			n--;
		}else {
			System.out.println("输入有误!");
		}
	}
}
//鱼类继承动物类
class Fish extends Animal{
	public Fish(String name) { //设置只有名字的构造方法,腿数直接赋值
		super(name,0);
	}
	public void move() {	//重写move()方法
		System.out.println(getName() +"在水中游来游去"+",他有"
	+super.getLegs()+"条腿");
	}
	
}
//马类继承动物类
class Horse extends Animal{
	public Horse(String name) {
		super(name,4);
	}
	public void move() {	//重写move()方法
		System.out.println(getName()+"在草原驰骋"+",他有"
				+super.getLegs()+"条腿");
	}
	
}

public class Zoo {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		System.out.println("===测试动物的多态性====");
		while(true) {		
			System.out.println("请输入(1表示动物,2表示鱼,3表示马,其它程序结束):");
			int num;
			num = sc.nextInt();
			if(num == 1) {
				Animal an= new Animal();
				an.move();
			}else if(num == 2) {
				Animal fish = new Fish("鱼"); 
				//向上转型,覆盖父类的变量,上转型对象调用重写后的方法
				fish.move();
			}else if(num == 3) {
				Animal horse = new Horse("马");
				horse.move();
			}else {
				System.out.println("===程序结束===");
				return;
			}
		}
	}

}

【编译结果:】
动物多态结果
注:在子类中定义构造方法时,也可以利用super直接给变量赋值。如:super(name,0);

  • 本章总结:

本章介绍了面向对象的三大特征:继承、封装和多态。继承是一种由己存在的类型创建一个或多个子类型的机制,即在现有的基础类上构建子类。
Super用于指代父类对象,用super作为前缀,可以引用父类被覆盖的成员变量,调用父类被重写的构造方法以及调用父类的构造方法。Final关键字可以修饰类、变量和方法,一旦赋值,其后不能改变。Final修饰的类不能被继承,修饰的方法不能被子类重写,变量值不可更改。
一个类通过派生或实现接口可演化成多种类型,这就是类的多态性。主要表现在变量的多态性(如对象的向上转型)和方法的多态性。
子类对象有向上转型对象,父类可以直接引用子类的对象;但父类对象没有下转型对象,子类变量不能直接引用父类对象,必须通过强制转型。

发布了9 篇原创文章 · 获赞 12 · 访问量 783

猜你喜欢

转载自blog.csdn.net/weixin_45625687/article/details/104420087