public class Fu {
public void method() {
System.out.println("父类方法");
}
public void methodFu() {
System.out.println("这是父类特有的方法");
}
}
Zi.java
text
1
2
3
4
5
6
public class Zi extends Fu {
@Override
public void method() {
System.out.println("子类方法");
}
}
Demo01Multi.java
text
1
2
3
4
5
6
7
8
9
10
11
public class Demo01Multi {
public static void main(String[] args) {
//使用多态方法
//左侧父类的引用,指向右侧子类的对象
Fu obj=new Zi();
obj.method();//子类方法。看右边new的是谁,就输出谁
obj.methodFu();
}
}
二、多态中成员变量使用特点
访问成员变量的两种方式:
直接通过对象名称访问成员变量:看等号左边是谁,优先用谁,没有则向上找
间接通过成员方法访问成员变量:看该方法属于谁,优先用谁,没有则向上找
Fu1.java
text
1
2
3
4
5
6
public class Fu1 {
int num=10;
public void method() {
System.out.println("父类"+num);
}
}
Zi1.java
text
1
2
3
4
5
6
7
public class Zi1 extends Fu1 {
int num=20;
@Override
public void method() {
System.out.println("子类"+num);
}
}
Demo02MultiField.java
text
1
2
3
4
5
6
7
8
9
10
11
12
public class Demo02MultiField {
public static void main(String[] args) {
//使用多态的方法,父类引用指向子类对象,左父右子
Fu1 obj=new Zi1();
System.out.println(obj.num);//10
obj.method();//20,子类没有覆盖重写,就是父;子类如果覆盖重写,就是子
Zi1 zi=new Zi1();
System.out.println(zi.num);//20
zi.method();//20
}
}
三、多态中成员方法的使用特点
在多态的代码当中,成员方法的访问规则:
看new的是谁,就优先用谁,没有则向上找
口诀:编译看左边,运行看右边
对比:
成员变量:编译看左边,运行还看左边
成员方法:编译看左边,运行看右边
Fu2.java
text
1
2
3
4
5
6
7
8
9
public class Fu2 {
public void method() {
System.out.println("父类方法");
}
public void methodFu() {
System.out.println("父类特有的方法");
}
}
Zi2.java
text
1
2
3
4
5
6
7
8
9
10
public class Zi2 extends Fu2 {
@Override
public void method() {
System.out.println("子类方法");
}
public void methodZi() {
System.out.println("子类特有方法");
}
}
Demo03MultiMethod.java
text
1
2
3
4
5
6
7
8
9
10
11
12
public class Demo03MultiMethod {
public static void main(String[] args) {
Fu2 obj=new Zi2();//多态
obj.method();//父子都有,优先用子
obj.methodFu();//子类没有,父类有,向上找
//obj.methodZi();//报错了,因为编译看左边,左边是Fu,Fu当中没有methodZi方法,所以编译报错
Zi2 zi=new Zi2();
zi.methodZi();
}
}
四、使用多态的好处
如果不用多态,只用子类,那么写法是:
text
1
2
3
4
Teacher one = new Teacher();
one.work();//讲课
Assistant two = new Assistant();
two.work();//辅导
我现在唯一要做的事情,就是调用work方法,其他的功能不关心。
如果使用多态的写法,对比一下:
text
1
2
3
4
Employee one = new Teacher();
one.work();//讲课
Employee two = new Assistant();
two.work();//辅导
好处:
无论右边new的时候换成哪个子类对象,等号左边调用方法不会发生变化
五、对象的向上转型与向下转型
向上转型
对象的向上转型,其实就是多态写法:
text
1
2
3
4
父类名称 对象名 = new 子类名称();
//Animal animal = new Cat();
//创建了一只猫,当做动物看待,没问题。
含义:右侧创建一个子类对象,把它当做父类来看待使用。
注意事项:**向上转型一定是安全的。**从小范围转向了大范围,从小范围的猫,转向了更大范围的动物。
类似于:
text
1
double num=100;//正确,int-->double,自动类型转换
向下转型
对象的向下转型,其实是一个【还原】的动作
格式:
text
1
2
3
4
子类名称 对象名 = (子类名称) 父类对象;//其实类似于 int a = (double) 10.0;
//Animal animal = new Cat();//本来是猫,向上转型为动物
//Cat cat = (Cat) animal;//本来是猫,已经被当做动物了,还原为本来的猫
int num = (int) 10.0;//可以
int num = (int) 10.5;//不可以,精度损失
Animal.java
text
1
2
3
4
public abstract class Animal {
public abstract void eat();
}
Cat.java
text
1
2
3
4
5
6
7
8
9
10
11
12
13
public class Cat extends Animal {
@Override
public void eat() {
// TODO Auto-generated method stub
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
public class Demo02Instanceof {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();// 猫吃鱼
giveMeAPat(animal);
}
public static void giveMeAPat(Animal animal) {
// 如果希望调用子类特有方法,需要向下转型
if (animal instanceof Dog) {
Dog dog = (Dog) animal;
dog.watchHouse();
}
if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}
七、接口多态综合案例
USB.java
text
1
2
3
4
5
6
7
public interface USB {
public abstract void open(); // 打开设备
public abstract void close(); // 关闭设备
}
Mouse.java
text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//鼠标就是一个USB设备
public class Mouse implements USB {
@Override
public void open() {
System.out.println("打开鼠标");
}
@Override
public void close() {
System.out.println("关闭鼠标");
}
public void click() {
System.out.println("鼠标点击");
}
}
Keyboard.java
text
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//键盘就是一个USB设备
public class Keyboard implements USB {
@Override
public void open() {
System.out.println("打开键盘");
}
@Override
public void close() {
System.out.println("关闭键盘");
}
public void type() {
System.out.println("键盘输入");
}
}
packagehomework;classA{publicStringf(Dobj){return("A and D");}publicStringf(Aobj){return("A and A");}}classBextendsA{publicStringf(Bobj){return("B and B");}publicStringf(Aobj){return("B and A");}}classCextendsB{}classDextendsB{}publicclassHomework02{/*
* 这个地方需要注意的点:
* 1. 如果public String f(A obj)方法传进来的对象是B对象,发现没有,就会自动向上转型!因为B extends A
* 2. 向上转型的写法中:A a2=new B();a2调用变量是A中的,调用方法是B中的(只能是A中已有的方法,被重写的可以被调用,独有的是不可以被调用的)
*/publicstaticvoidmain(String[]args){Aa1=newA();Aa2=newB();Bb=newB();Cc=newC();Dd=newD();System.out.println(a1.f(a1));// A and ASystem.out.println(a1.f(b));// A and ASystem.out.println(a1.f(c));// A and ASystem.out.println(a1.f(d));// A and DSystem.out.println(a2.f(a1));//B and ASystem.out.println(a2.f(b));//B and ASystem.out.println(a2.f(c));//B and ASystem.out.println(a2.f(d));//A and DSystem.out.println(b.f(a1));//B and ASystem.out.println(b.f(b));//B and BSystem.out.println(b.f(c));//B and BSystem.out.println(b.f(d));//A and D}}