1.1 概述
-
多态:事物的多种形态。同一方法调用可以根据实际调用对象的不同而采用多种不同的行为方式。
-
多态的前提:
-
要有子父类的继承(实现)关系
-
有方法的重写
-
父类的引用指向子类的对象
-
-
示例:
class Animal { protected void method1() { System.out.println("动物会叫"); } } public class Cat extends Animal { @Override protected void method1() { System.out.println("猫会喵喵的叫"); } } public class Demo { public static void main(String[] args) { Animal animal = new Cat(); animal.method1(); } }
1.2 多态中成员变量访问特点
-
编译看左边,运行看左边
-
编译的时候,要看【=】左边的引用的类型中,是否有该变量的定义,如果有,就编译成功,如果没有,就编译失败。
-
运行的时候,要看【=】左边的引用所属类型中,真正如何给变量赋值的。获取到的是父类的赋值结果。
-
示例:
class Animal { int age = 3; public void method1() { System.out.println("动物会叫"); } } public class Cat extends Animal { int age = 7; String name; @Override public void method1() { System.out.println("猫会喵喵的叫"); } } public class Demo { public static void main(String[] args) { Animal animal = new Cat(); animal.method1(); System.out.println(animal.age); } }
1.3 多态中方法的访问特点
-
编译看左边,运行看右边
-
编译的时候,要看【=】左边的引用所属的类型中,是否有该方法的定义,如果有,就编译成功,如果没有,就编译失败。
-
运行的时候,要看【=】右边的对象所属的类型中,是如何实现这个方法的。最终运行的是子类重写过的方法实现。
-
示例:
class Animal { public void method1() { System.out.println("动物会叫"); } } public class Cat extends Animal { @Override public void method1() { System.out.println("猫会喵喵的叫"); } } public class Demo { public static void main(String[] args) { Animal animal = new Cat(); animal.method1(); } }
1.4 多态中静态方法的访问特点
-
编译看左边,运行看左边
-
编译的时候,要看【=】左边的引用所属的类型中,是否有该方法的定义,如果有,就编译成功,如果没有,就编译失败
-
运行的时候,要看【=】左边的引用所属的类型中,如何实现该方法的。最终运行的是【=】左边类型中方法的结果(方法属于类,不属于重写关系,所以不加@Override)
-
静态解释:
-
静态变量:存储在类的字节码中的变量,被所有对象所共享,不随着对象的变化而变化,都有相同的值,所以称为静态变量。
-
静态方法:只会根据引用所属的父类,来决定运行的内容,运行内容,不会随着子类的变化而变化,都是引用所属的父类的方法实现,所以称为静态方法。
-
-
示例:
class Animal { public static void method1() { System.out.println("动物会叫"); } } public class Cat extends Animal { public static void method1() { System.out.println("猫会喵喵的叫"); } } public class Demo { public static void main(String[] args) { Animal animal = new Cat(); animal.method1(); Animal.method1(); Cat.method1(); } }
1.5 向上或向下转型
-
向上转型:
-
使用子类的引用指向子类的对象(正常情况),父类的引用指向子类的对象(多态)
-
多态中,使用父类的引用指向子类的对象(向上转型)
-
本质:缩小了对象本身的访问范围,减少了访问的权限(只能访问父类中定义的内容)
-
-
向下转型:
-
子类的引用指向父类的对象
-
格式:
子类类型 引用名称 = (子类类型)父类类型的引用 SuperMan sm = (SuperMan)m;
-
本质:【恢复】子类类型原本就有的访问范围
-
-
示例:
class Animal { int age = 3; public void method1() { System.out.println("动物会叫"); } } public class Cat extends Animal { int age = 10; public void method1() { System.out.println("猫会喵喵的叫"); } } // 向上转型 public class Demo { public static void main(String[] args) { Animal animal = new Cat(); System.out.println(animal.age); } } // 向下转型 public class Demo { public static void main(String[] args) { Animal animal = new Cat(); Cat cat = (Cat) animal; System.out.println(cat.age); } }
1.6 多态的好处
-
提高了代码的可扩展性,不需要修改源代码
-
在方法的参数列表中,可以定义父类类型的引用,将来调用的时候,所有的子类类型的对象,都可以作为方法的实际参数。
void test(Animal){ }
-
不在方法的参数列表中,使用父类的类型指向子类的对象,也能提高代码的可扩展性。对象的来源非常广泛,不仅仅是new出来的,(还可能是通过反射获取的,通过文件读取的,还可能是网络传递的,在写代码的编译阶段,无法知道对象具体的子类类型的)需要使用父类类型的引用,操作不知道的子类类型的对象。
-
示例:
-
有一个榨汁机,放什么水果就能榨什么水果的果汁。
class Animal { int age = 3; public void method1() { System.out.println("动物会叫"); } } public class Cat extends Animal { int age = 10; public void method1() { System.out.println("猫会喵喵的叫"); } } // 向上转型 public class Demo { public static void main(String[] args) { Animal animal = new Cat(); System.out.println(animal.age); } } // 向下转型 public class Demo { public static void main(String[] args) { Animal animal = new Cat(); Cat cat = (Cat) animal; System.out.println(cat.age); } }
-