多态
1、多态介绍
多态:某个事物(物体)采用不同的形态表示(描述)。针对这个事物或个体(实例)称为它发生了多态的现象。
一个事物的多种形态。
例如:
饭很好吃:针对具体到的是什么饭,然后这个饭被使用笼统的方式描述。
水果:苹果、西瓜、香蕉等。
动物:可能面对的是一只猫,但这个小动物很可爱。猫就发生多态,如果说猫很可爱,猫就用自己本身形态表示。
不管什么物种,采用什么形式描述,但是这个物种永远不会发生变化。
2、在Java中多态的体现
Java中如果要能够发生多态现象,必须有继承或者实现的存在。
一个类应该有父类或者有接口。否则无法使用多态。
多态的代码体现:
- 父类类型或接口类型 变量名 = new 子类或实现类( ) ;
- 父类类型或接口类型 变量名 = 引用变量;
class Animal{
}
class Dog extends Animal{
}
public class Demo {
public static void main(String[] args) {
// 没有发生多态
Dog d = new Dog();
// 多态的体现
Animal a = new Dog();
// 多态
Animal a2 = d;
}
}
只要是父类或接口的引用变量指向了子类或者实现类对象,都是多态。
3、多态的使用
abstract class Animal{
// 描述的是所有动物共性的eat行为
public abstract void eat();
}
// 缉毒的接口
interface AntiDrug{
public void antiDrug();
}
// Dog经过后天训练具备缉毒的行为
class Dog extends Animal implements AntiDrug{
public void eat() {
System.out.println("啃骨头");
}
// 复写缉毒的行为
public void antiDrug() {
System.out.println("狗缉毒");
}
// 看家
public void lookHome() {
System.out.println("小狗看家");
}
}
class Cat extends Animal{
public void eat() {
System.out.println("吃鱼");
}
}
//Pig经过后天训练具备缉毒的行为
class Pig extends Animal implements AntiDrug{
public void eat() {
System.out.println("吃糠");
}
// 复写缉毒的行为
public void antiDrug() {
System.out.println("猪缉毒");
}
}
public class InterfaceDemo2 {
public static void main(String[] args) {
// 多态
Animal a = new Dog();
// 多态之后,只能调用父类或者接口中公共的方法
a.eat();
// 多态之后,无法调用子类中特有的方法
//a.lookHome();
// 如果已经明确知道多态所指的对象的具体类型,
// 可以将整个多态的引用进行强转
Dog d = (Dog)a;
d.lookHome();
run( new Dog() );
}
// 这个方法接受的参数一定是Animal的子类对象
// 只要下面run方法被调用,一定会发生多态的参数传递
public static void run( Animal a) { // Animal a = new Dog();
a.eat();
}
}
4、多态的细节
- 非静态方法:编译的时候要求父类或接口中必须拥有这个方法,但是运行的时候执行的子类或者实现类复写后的方法。(编译看父类,运行看子类)
- 变量:编译运行都是使用父类或接口中的(编译运行都是父类)
- 静态方法:多态下调用静态方法,编译和运行都是父类中(编译运行都是父类)
class Fu{
int x = 12;
public void run() {
System.out.println("Fu run .... ");
}
public static void method() {
System.out.println("Fu method ....");
}
}
class Zi extends Fu{
int x = 34;
public void run() {
System.out.println("Zi run .... ");
}
public static void method() {
System.out.println("Zi method ....");
}
}
public class Demo {
public static void main(String[] args) {
// 没有多态
Zi z = new Zi();
z.run();
// 多态中的方法调用
Fu f = new Zi();
f.run();
// 针对变量,编译运行都是父类中的
System.out.println( f.x );
// 静态方法通过类名直接调用
Zi.method();
Fu.method();
// 多态下调用静态方法,编译和运行都是父类中
f.method();
}
}
5、多态中的转型
多态发生之后,子类对象被父类或者接口类型引用。
- 向上转型:父类或接口引用 指向 子类或实现类对象
- 向下转型:将父类或接口引用类型转成具体的子类或实现类类型。
如果使用的行为(方法)在A 类中已经存在(抽象方法),这时就可以任意找到A类某个子类创建对象,然后使用A类的类型进行引用。调用方法执行。
public class DemoTest {
public static void main(String[] args) {
/*
* 什么时候使用向上转型:
* 在程序调用的时候,我们只关注父类或者接口中的内容,而不去具体使用子类或实现类中的特有行为时
* 可以直接将某个子类或实现类对象赋值给接口或父类引用。
*/
// 向上转型
Animal a = new Dog();
Animal a2 = new Cat();
Animal a3 = new Pig();
/*
* 什么时候使用向下转型:
* 程序中需要使用子类或实现类中特有的行为,需要将父类或接口引用转成子类或实现类类型
*/
// 向下转型(强制类型转换)
Dog d = (Dog) a;
}
}
向下转型有风险:
// 多态
A a = new C();
// 向下转型
C c = (C)a;
// 如果现在不清楚a引用指向具体是哪个子类类型
B b = (B)a; // 这里一定会报错
public class DemoTest2 {
public static void main(String[] args) {
Animal a = new Dog();
Cat c = (Cat) a;
}
}
程序中遇到ClassCastException异常,都是进行类型转成时发生。将一种不是当前类型的对象(引用)强转成了当前类型。
public class DemoTest2 {
public static void main(String[] args) {
Animal a = new Dog();
// 会发生类型转转异常
//Cat c = (Cat) a;
/*
* 在进行类型转换的时候,可以进行预先的判断
* instanceof 判断某个引用是否指向了指定的类型,如果是返回true,否则false
*/
if( a instanceof Cat ) {
Cat c = (Cat) a;
// 通过c调用Cat中的特有方法
}
if( a instanceof Dog ) {
Dog d = (Dog) a;
}
if( a instanceof Pig ) {
Pig p = (Pig) a;
}
}
}