一、多态性
1.多态性
对象的多态性:父类的引用指向子类的对象
Person p = new Man();//p就是父类的引用
上面的p只能调用父类声明的方法,执行的时候实际上是子类对父类重写的方法(属性不适用,还是要看父类)
编译看左边,运行看右边
多态性的前提是:有继承关系,有方法的重写
2.为什么要有多态性这个东西呢?举个栗子
public class Main {
public static void main(String[] args) {
func(new Cat());
System.out.println("*******");
func(new Dog());
}
private static void func(Animal animal) {
if(animal instanceof Dog){//调用狗特有的方法
Dog d = (Dog)animal;
d.watchDoor();
}
animal.eat();
animal.shot();
}
}
class Animal{
void eat(){
System.out.println("吃");
}
void shot(){
System.out.println("叫");
}
}
class Dog extends Animal{
@Override
void eat() {
System.out.println("狗吃骨头");
}
@Override
void shot() {
System.out.println("汪汪汪");
}
//特有的方法
void watchDoor(){
System.out.println("看门");
}
}
class Cat extends Animal{
@Override
void eat() {
System.out.println("猫吃鱼");
}
@Override
void shot() {
System.out.println("喵喵喵");
}
}
猫吃鱼
喵喵喵
*******
看门
狗吃骨头
汪汪汪
如果没有多态性,可能就要写三个方法来表示动物的行为。
3.虚拟方法
子类重写了父类的方法,此时父类的方法就叫做虚拟方法,父类根据子类的不同动态的调用属于子类的该方法。这时在编译期无法预见的,多态是属于运行时行为
4.instancof关键字
上面说到不能调用子类特有的方法,哪如何才能调用呢?强制类型转换(多态是向上转型)
Man m =new (Man)p;//向下转型
//可能会出现异常
为了避免在向下转型中出现异常,使用instanceof语句,
A instanceof B:判断A是否是B的实列,如果是返回true,可以进行向下转型;
特别的:a instanceof A 返回true,且 B是A父类, 那么 a instanceof B也返回true
练习:
public class InstanceTest {
public static void main(String[] args) {
InstanceTest test = new InstanceTest();
test.method(new Student());
test.method(new Graduate());
test.method(new Person());
}
public void method(Person e){
System.out.println(e.getInfo());
if(e instanceof Graduate){
System.out.println("a graduate student");
}if(e instanceof Student){
System.out.println("a student");
}if(e instanceof Person){
System.out.println("a person");
}
}
}
练习2:
public class GeometricTest {
public static void main(String[] args) {
GeometricTest test = new GeometricTest();
Circle c1 = new Circle("white", 2.3, 1.0);
Circle c2 = new Circle("white", 2.3, 1.0);
MyRectangle m1 = new MyRectangle("white", 2.3, 2, 3);
test.equalsArea(c1, c2);
test.equalsArea(c1, m1);
System.out.println(c1.findArea());
System.out.println(c2.findArea());
System.out.println(m1.findArea());
}
public void equalsArea(GeometricObject s1,GeometricObject s2) {
boolean flag = s1.findArea()==s2.findArea();
if(flag) System.out.println("面积相等");
else System.out.println("面积不相等");
}
public void displayArea(GeometricObject s) {
System.out.println("图像的面积是 "+s.findArea());
}
}
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;
}
}
class Circle extends GeometricObject{
private double radius;
public Circle(String color, double weight, double radius) {
super(color, weight);
this.radius = radius;
}
public double getRadius() {
return radius;
}
public void setRadius(double radius) {
this.radius = radius;
}
@Override
public double findArea() {
return 3.14*radius*radius;
}
}
class MyRectangle extends GeometricObject {
private double width;
private double height;
public MyRectangle(String color, double weight, double width, double height) {
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;
}
@Override
public double findArea() {
return width*height;
}
}
练习3:
请给出下列代码的输出:
public class Main {
public static void main(String[] args) {
Base base = new Sub();
base.add(1,2,3);
Sub sub = (Sub)base;
sub.add(1,2,3);
}
}
class Base{
void add(int a,int...arr){
System.out.println("Base");
}
}
class Sub extends Base{
void add(int a,int...arr){
System.out.println("sub_1");
}
void add(int a,int b,int c){
System.out.println("sub_2");
}
}
sub_1
sub_2
第一个输出sub_1 ,两个方法(1,2)属于重写,base继承父类只调用重写的方法
第二个输出sub_2,两个方法(2,3)属于重载,优先调参数个数确定的