多态
1、方法的多态
package day02;
public class Demo2 {
public static void main(String[] args) {
// 方法重载体现多态
B b = new B();
b.sum(10, 20);
b.sum(10, 20, 30);
// 方法重写体现多态
A a = new A();
a.say();
b.say();
}
}
class A{
public void say(){
System.out.println("A say()");
}
}
class B extends A{
public void sum(int n1, int n2){
System.out.println(n1 + n2);
}
public void sum(int n1, int n2, int n3) {
System.out.println(n1 + n2 + n3);
}
@Override
public void say() {
System.out.println("B say()");
}
}
2、对象的多态(核心,困难,重点)
- 一个对象的编译类型和运行类型可以不一致
- 编译类型在定义对象时,就确定了,不能改变
- 运行类型是可以变化的
- 编译类型看定义时
=号的左边
,运行类型看=号的右边
多态的细节(共 6 点):
- 多态的前提是:两个对象(类)存在继承关系
- 多态的向上转型:
本质:父类的引用指向了子类的对象
语法:父类类型引用名 = new 子类类型();
特点:编译类型看左边,运行类型看右边。 - 可以调用父类中的所有成员(需遵守访问权限),不能调用子类中特有成员;最终运行效果看子类的具体实现!
package day02;
public class Demo3 {
public static void main(String[] args) {
// 向上转型:父类引用指向子类对象
// 父类类型 对象名 = new 子类类型()
Animal animal = new Cat();
Object obj = new Cat();
// 1.可以调用父类中的所有成员(但必须遵守访问权限),不能调用子类的特有成员。
// 因为如果调用子类的特有成员,在编译期间就会报错。即:一个对象能调用哪些成员,是由编译类型决定的
// 所以:animal.catchMouse();错误
// 2.最终运行效果看子类的具体实现,即运行期间调用方法时,按照从子类开始查找方法,然后调用。
// 所以:animal.eat();会执行 Cat 类中重写的 eat 方法
animal.eat(); // 猫吃鱼
animal.run();
animal.sleep();
animal.show();
}
}
class Animal{
private String name;
public void run(){
System.out.println("动物跑");
}
public void eat(){
System.out.println("动物吃");
}
public void sleep(){
System.out.println("动物睡");
}
public void show(){
System.out.println("动物:Hello~");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
- 多态的向下转型:
(1)语法:子类类型引用名 = (子类类型)父类引用;
(2)只能强转父类的引用,不能强转父类的对象
(3)要求父类的引用必须指向的是当前目标类型的对象
(4)当向下转型后,可以调用子类类型中所有的成员
package day02;
public class Demo3 {
public static void main(String[] args) {
// 向上转型:父类引用指向子类对象
// 父类类型 对象名 = new 子类类型()
Animal animal = new Cat();
Object obj = new Cat();
// 多态的向下转型
// 要求:子类类型 子类引用 = (子类类型)父类引用;
// 父类的引用必须指向的是当前目标类型的对象
Cat cat = (Cat) animal;
cat.eat(); // 猫吃鱼
cat.catchMouse(); // 猫抓老鼠
}
}
class Animal{
private String name;
public void run(){
System.out.println("动物跑");
}
public void eat(){
System.out.println("动物吃");
}
public void sleep(){
System.out.println("动物睡");
}
public void show(){
System.out.println("动物:Hello~");
}
}
class Cat extends Animal{
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
- 属性没有重写之说,属性的值看编译类型:
package day02;
public class Demo4 {
public static void main(String[] args) {
// 属性没有重写之说,属性的值看编译类型
Sub sub = new Sub();
System.out.println(sub.n);// 20
// 属性没有重写之说,属性的值看编译类型
// 编译类型为 Base,所以属性值为 Base 中的值
Base base = new Sub();
System.out.println(base.n);// 10
}
}
class Base{
int n = 10;
}
class Sub extends Base{
int n = 20;
}
instanceOf
比较操作符,用于判断对象的 运行类型 是否为XX类型或XX类型的子类型
package day02;
public class Demo4 {
public static void main(String[] args) {
BB bb = new BB();
System.out.println(bb instanceof BB);// true
System.out.println(bb instanceof AA);// true
// 编译类型 AA, 运行类型 BB
AA aa = new BB();
System.out.println(aa instanceof AA);//true
System.out.println(aa instanceof BB);//true
}
}
class AA{
}
class BB extends AA{
}
练习
package day02;
public class Demo4 {
public static void main(String[] args) {
Sub sub = new Sub();
System.out.println(sub.count); // 20
sub.display(); // 20
Base b = sub;
System.out.println(b == sub); // true
System.out.println(b.count); // 10
b.display(); // 20
}
}
class Base{
int count = 10;
public void display(){
System.out.println(this.count);
}
}
class Sub extends Base{
int count = 20;
@Override
public void display() {
System.out.println(this.count);
}
}