多态
在Java中,多态是指不同类的对象在调用同一个方法时所呈现出的多种不同行为。通常来说,在一个类中定义的属性和方法被其他类继承或重写后,当把子类对象直接赋值给父类引用变量时,相同引用类型的变量调用同一个方法所呈现的多种不同形态
通过多态,消除了类之间的耦合关系,大大提高了程序的可扩展性和可维护性
1. 多态性
Java的多态性由类的继承、方法的重写以及父类引用指向子类对象体现的
对面向对象来说,多态分为编译时多态和运行时多态。
- 编译时多态是静态的,主要是指方法的重载,它是根据参数列表的不同来区分不同的方法。通过编译之后会变成两个不同的方法,在运行时谈不上多态。
- 运行时多态是动态的,它是通过动态绑定来实现的,也就是大家通常所说的多态性。
实现多态有 3 个必要条件:继承、重写和向上转型。
- 继承:在多态中必须存在有继承关系的子类和父类。
- 重写:子类对父类中某些方法进行重新定义,在调用这些方法时就会调用子类的方法。
- 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样该引用才既能可以调用父类的方法,又能调用子类的方法。
class Calc{
int a;
int b;
public Calc(int a,int b){
this.a = a;
this.b = b;
}
int end(){
System.out.println("没什么含义");
return 0;
}
}
class Add extends Calc{
public Add(int a, int b) {
super(a, b);
}
@Override
int end() {
System.out.println("相加后:");
return super.a + super.b;
}
}
class Mul extends Calc{
public Mul(int a, int b) {
super(a, b);
}
@Override
int end() {
System.out.println("相乘后:");
return super.a * super.b;
}
}
public class testduo {
public static void main(String[] args) {
Calc calc01 = new Add(2,3);
Calc calc02 = new Mul(2,3);
Calc calc03 = new Calc(2,3);
System.out.println(calc01.end());
System.out.println(calc02.end());
System.out.println(calc03.end());
}
}
2.对象的类型转换
2.1 向上转型
向上转型:父类引用指向子类对象
Calc calc01 = new Add(2,3);
Calc calc02 = new Mul(2,3);
此时不能通过父类变量调用子类特有的方法
2.2 向下转型
向下转型:子类对象指向父类引用
此时运行正常
2.2.1 在进行对象向下类型转换时,必须转换为本质类型,否则转换时会出现错误
2.2.2 通过引用类型变量来访问所引用对象的属性和方法时,Java 虚拟机将采用以下绑定规则:
- 实例方法与引用变量实际引用的对象的方法进行绑定,这种绑定属于动态绑定,因为是在运行时由 Java虚拟机动态决定的。例如,animal.eat() 是将 eat() 方法与 Dog 类绑定。
- 静态方法与引用变量所声明的类型的方法绑定,这种绑定属于静态绑定,因为是在编译阶段已经做了绑定。例如,animal.staticEat() 是将 staticEat() 方法与 Animal 类进行绑定。
- 成员变量(包括静态变量和实例变量)与引用变量所声明的类型的成员变量绑定,这种绑定属于静态绑定,因为在编译阶段已经做了绑定。例如,animal.name 和 animal.staticName 都是与 Animal 类进行绑定。
class Animal {
String name = "小动物";
static String staticName = "可爱的小动物";
void eat() {
System.out.println("吃饭");
}
static void staticEat() {
System.out.println("小动物在吃饭");
}
}
class Dog extends Animal {
String name = "小狗";
String str = "一只小狗";
static String staticName = "旺财";
@Override
void eat() {
System.out.println("开饭啦!!!");
}
static void staticEat() {
System.out.println("小狗在吃饭");
}
void eatMethod() {
System.out.println("小狗啃骨头");
}
}
public class testtest {
public static void main(String[] args) {
Animal animal = new Dog();
Dog dog = (Dog) animal; // 向下转型
System.out.println(animal.name); // 输出 Animal 类的 name 变量
System.out.println(animal.staticName);
animal.eat(); // 输出 Dog 类的 eat() 方法
animal.staticEat();
System.out.println("************************");
System.out.println(dog.name); // 输出 Dog 类的 name 变量
System.out.println(dog.str);
System.out.println(dog.staticName);
dog.eat();
dog.staticEat();
dog.eatMethod();
}
}
2.3 强制类型转换 —— instanceof
类型强制转换时想运行成功就必须保证父类引用指向的对象一定是该子类对象,最好使用 instanceof 运算符判断后,再强转
2.4 instanceof
在 Java 中可以使用 instanceof 关键字判断一个对象是否为一个类(或接口、抽象类、父类)的实例
boolean result = obj instanceof Class
//obj 是一个对象,Class 表示一个类或接口
//obj 是 class 类(或接口)的实例或者子类实例时,结果 result 返回 true,否则返回 false