1,多态性可以理解为事物的多种形态
2,何为多态性:对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)
3,多态的使用:虚拟方法调用:
引入对象的多态性之后,我们在编译期只能调用父类中声明的方法,但在运行(执行)期实际运行的是子类重写父类的方法“即编译看左边,运行看右边”。
4,多态性的使用前提:
①有类的继承关系 ;②要有方法的重写。
5,对象的多态性只适用于方法,不适用于属性(属性编译运行都看左边)。
代码理解:
package com.atguigu.java3;
//多态性的使用举例
public class AnimalTest {
public static void main(String[] args) {
AnimalTest test=new AnimalTest();
test.func(new Dog()); //把此匿名对象赋给animal
test.func(new Cat()); //把此匿名对象赋给animal
}
public void func(Animal animal){ //相当于:Animal animal=new Dog();-----对象的多态性
animal.eat(); //此方法体内部只能调用Animal的方法,但运行的是重写的方法
animal.shout();
}
//如果没多态性,需要造很多重载的方法,即需要如下代码
}
class Animal{ //父类
public void eat(){
System.out.println("动物饮食");
}
public void shout(){
System.out.println("动物叫");
}
}
class Dog extends Animal{
public void eat(){
System.out.println("狗吃骨头");
}
public void shout(){
System.out.println("汪汪汪");
}
}
class Cat extends Animal{
public void eat(){
System.out.println("猫吃鱼");
}
public void shout(){
System.out.println("喵喵喵");
}
}
instanceof操作符
关于转型:问题引入:
以Person、Man、Woman为例:
①Person
package com.atguigu.java3;
public class Person {
String name;
int age;
public void eat(){
System.out.println("人:吃饭");
}
public void walk(){
System.out.println("人:走路");
}
}
②Man
package com.atguigu.java3;
public class Man extends Person {
boolean isSmoking;
public void earnMoney(){
System.out.println("男人负责挣钱养家");
}
//对父类中方法进行重写
public void eat(){
System.out.println("男人多吃肉,长肌肉");
}
public void walk(){
System.out.println("男人要霸气的走路走路");
}
}
③Woman
package com.atguigu.java3;
public class Woman extends Person {
boolean isBeauty;
public void goShopping(){
System.out.println("女人喜欢购物");
}
public void eat(){
System.out.println("女人少吃,为了减肥");
}
public void walk(){
System.out.println("女人要窈窕地走路");
}
}
使用PersonTest测试:
package com.atguigu.java3;
public class PersonTest {
public static void main(String[] args) {
Person p1=new Person();
//引入多态性:父类的引用指向子类的对象
Person p2=new Man();
//多态性的使用:当调用子父类同名同参数的方法时,实际执行的是子类中重写父类的方法----------称为虚拟方法调用
p2.eat(); //执行子类中重写父类的方法
p2.walk(); //执行子类中重写父类的方法
//不能调用子类所特有的属性和方法:编译时,p2是Person类型,Person中没有定义earnMoney()方法和isSmoking属性
// p2.earnMoney(); 报红
// p2.isSmoking=true; 报红
//向下转型:使用强制类型转换符才能调用子类特有的属性和方法
Man m1=(Man)p2;
System.out.println("*********");
//则以下方法属性可以调用
m1.earnMoney();
m1.isSmoking=true;
}
}
但是使用强转时,可能出现ClassCastException异常
如图:
于是引入instanceof关键字:.
instanceof使用:
a instanceof A来判断对象a是否为类A的实例。如果是返回true,如果不是返回false。
完善PersonTest代码:
package com.atguigu.java3;
public class PersonTest {
public static void main(String[] args) {
Person p1=new Person();
//引入多态性:父类的引用指向子类的对象
Person p2=new Man(); //注意new的p2是男的
//多态性的使用:当调用子父类同名同参数的方法时,实际执行的是子类中重写父类的方法----------称为虚拟方法调用
p2.eat(); //执行子类中重写父类的方法
p2.walk(); //执行子类中重写父类的方法
System.out.println("*********");
//使用强转时,可能出现ClassCastException异常,为了避免异常,在向下转型之前先进行instanceof判断,true时再进行向下转型
if(p2 instanceof Woman){ //关注p2是男还是女
Woman w1=(Woman)p2; //则强转
w1.goShopping();
System.out.println("*****Woman*******");
}
if(p2 instanceof Man){
Man m2=(Man)p2; //则强转
m2.earnMoney();
System.out.println("*****Man*******");
}
//如果a instanceof A为true、类B是类A的父类,则a instanceof B也返回true
if(p2 instanceof Person){
System.out.println("*****Person*******");
}
if(p2 instanceof Object){
System.out.println("*****Object*******");
}
}
}
总结:
多态练习:
练习1:
package com.atguigu.exer;
class base {
int count = 10;
public void display() {
System.out.println(this.count);
}
}
class Sub extends base {
int count = 20;
public void display() {
System.out.println(this.count);
}
}
public class FieldMethodTest {
public static void main(String[] args){
Sub s = new Sub();
System.out.println(s.count); //20
s.display(); //20
base b = s; //多态。子类对象赋给了父类引用
System.out.println(b == s); //true,地址一样,此处二者指向堆空间中的同一个对象。“==”对于引用数据类型比较的是地址值是否相同
System.out.println(b.count); //10。多态性不适用于属性
//需要注意开发中我们尽量不要定义同名的属性
b.display(); //20。虚拟方法调用
}
}
总结:
练习2:
package com.atguigu.exer;
public class InstanceTest {
public static void main(String[] args) {
InstanceTest test=new InstanceTest();
test.method(new Student());
}
public void method(Person e){ //赋值过来,变成多态
//虚拟方法调用
String info = e.getInfo();
System.out.println(info);
//方式一:
if(e instanceof Graduate){ //先写范围小的
System.out.println("a graduated student");
System.out.println("a student");
System.out.println("a person");
}else if(e instanceof Student){ //我们new的是Student,进入此分支
System.out.println("a student");
System.out.println("a person");
}else{
System.out.println("a person");
}
//方式二:(更简洁)
}
}
class Person {
protected String name="person";
protected int age=50;
public String getInfo() {
return "Name: "+ name + "n" +"age: "+ age;
}
}
class Student extends Person {
protected String school="pku";
public String getInfo() { //重写
return "Name: "+ name + "nage: "+ age + "nschool: "+ school;
}
}
class Graduate extends Student{
public String major="IT";
public String getInfo(){ //重写
return "Name: "+ name + "nage: "+ age
+ "nschool: "+ school+"nmajor:"+major;
}
}
练习3:
①GeometricObject
package com.atguigu.exer;
public class GeometricObject { //几何图形
protected String color;
protected double weight;
public GeometricObject(String color, double weight) {
super();
this.color = color;
this.weight = weight;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public double getWeight() {
return weight;
}
public void setWeight(double weight) {
this.weight = weight;
}
public double findArea(){
return 0.0;
}
}
②Circle
package com.atguigu.exer;
public class Circle extends GeometricObject {
private double radius;
public Circle(double radius,String color, double weight) {
super(color, weight);
this.radius=radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
public double findArea(){
return 3.14*radius*radius;
}
}
③MyRectangle
package com.atguigu.exer;
public class MyRectangle extends GeometricObject {
private double width;
private double height;
public MyRectangle(double width,double height,String color, double weight) {
super(color, weight);
this.width=width;
this.height=height;
}
public double getWidth() {
return width;
}
public void setWidth(double width) {
this.width = width;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
//重写findArea()
@Override
public double findArea() {
return width*height;
}
}
GeometricTest:
package com.atguigu.exer;
public class GeometricTest {
public static void main(String[] args) {
GeometricTest test=new GeometricTest();
Circle c1=new Circle(2.3, "white", 1.0);
test.displayGeometricObject(c1); //实际调用时放的是Circle
Circle c2=new Circle(3.3, "white", 1.0);
test.displayGeometricObject(c2);
boolean isEquals = test.equalsArea(c1, c2);
System.out.println("c1和c2的面积是否相等:"+isEquals);
MyRectangle rect=new MyRectangle(2.1, 3.4, "red", 2.0);
test.displayGeometricObject(rect);
}
//displayGeometricObject方法显示对象的面积
public void displayGeometricObject(GeometricObject o){ //多态性
System.out.println("面积为:"+o.findArea());
}
//测试两个对象面积是否相等
public boolean equalsArea(GeometricObject o1,GeometricObject o2){
return o1.findArea()==o2.findArea();
}
}
面试题:
型一:
package com.atguigu.exer;
//考查多态的笔试题目:
public class InterviewTest1 {
public static void main(String[] args) {
base1 base = new Sub1(); //多态
base.add(1, 2, 3); //问题:此处输出什么内容? 答:输出“sub_1”
}
}
//父类
class base1 {
public void add(int a, int... arr) { //含可变个数的形参
System.out.println("base");
}
}
//子类
class Sub1 extends base1 {
public void add(int a, int[] arr) { //解题关键:此处认为是重写
System.out.println("sub_1");
}
// public void add(int a, int b, int c) { //若此处三行打开,输出结果不会变仍为“sub_1”
// System.out.println("sub_2"); //此处不认为重写父类add方法(形参列表不同)
// }
}
型二:
package com.atguigu.exer;
//考查多态的笔试题目:
public class InterviewTest1 {
public static void main(String[] args) {
base1 base = new Sub1(); //多态
base.add(1, 2, 3); //问题:输出什么内容? 输出“sub_2”
Sub1 s = (Sub1)base; //此处对base进行强转(向下转型)
s.add(1,2,3); // 输出 “sub_2”,因为确定参数个数的方法会优先调用
}
}
//父类
class base1 {
public void add(int a, int... arr) { //可变形参
System.out.println("base");
}
}
//子类
class Sub1 extends base1 {
public void add(int a, int[] arr) {
System.out.println("sub_1");
}
public void add(int a, int b, int c) {
System.out.println("sub_2");
}
}



