面向对象的三大特征:封装性,继承性,多态性
extends继承和implements实现,是多态性的前提。
1.多态
代码中体现多态性:父类引用指向子类对象
父类名称 对象名 = new 子类名称();
接口名称 对象名 = new 实现类名称();
public class Father {
public void method() {
System.out.println("father's method");
}
public void methodFather() {
System.out.println("father's own method");
}
}
public class Children extends Father{
@Override
public void method(){
System.out.println("children's method");
}
}
public class demo01Multi {
public static void main(String[] args) {
//多态写法
//左侧父类的引用,指向右侧子类的对象
Father obj = new Children();
obj.method();//children's method 会调用子类的方法
obj.methodFather();//father's own method 调用父类独有的方法
}
}
2.多态中成员变量的使用特点
1.直接通过对象名称访问成员变量,看等号左边是谁,优先用谁,没有就向上找。
2.间接通过成员方法访问成员变量。该方法属于谁则优先用谁,没有则向上找。
public class Father {
int num = 10;
public void showNumber() {
System.out.println(num);
}
}
public class Children extends Father {
int num = 20;
}
public class demo01MultiFiled {
public static void main(String[] args) {
Father obj = new Children();
System.out.println(obj.num);//10(父类的成员变量)
obj.showNumber();//10 showNumber属于父类
}
}
如果子类覆盖重写了父类中的方法
public class Children extends Father {
int num = 20;
@Override
public void showNumber() {
System.out.println(num);
}
}
public class demo01MultiFiled {
public static void main(String[] args) {
Father obj = new Children();
System.out.println(obj.num);//10(父类的成员变量)
obj.showNumber();//20 showNumber属于子类(子类覆盖重写了父类的方法)
}
}
3.多态中成员方法的使用特点
多态的代码中,成员方法的访问规则是 看new的是谁,就优先用谁,没有就向上找。
成员变量:编译看左边,运行看左边
成员方法:编译看左边,运行看右边
public class Father {
public void method() {
System.out.println("Father's method");
}
public void methodFather() {
System.out.println("Father's own method");
}
}
public class Children extends Father {
int num = 20;
@Override
public void method() {
System.out.println("children's method");
}
public void methodChildren() {
System.out.println("children's own method");
}
}
public class demo02MultiMethod {
public static void main(String[] args) {
Father obj = new Children();
obj.method();//父子都有的方法,优先用子类的方法
obj.methodFather();//子类没有,父类有,向上找到父类。
//obj.methodChildren();//错误,因为obj是父类的对象,父类中没有methodChildren方法()
}
}
4.对象的向上转型
对象的向上转型,其实就是多态写法。
格式:父类名称 对象名 = new 子类名称();
含义:右侧创建一个子类对象,把它当作父类来看待使用。
public abstract class Animal {
public abstract void eat();
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("eat fish");
}
}
public class demo01Main {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
}
}
对象向上转型就是父类引用指向子类对象。向上转型一定是安全的,从小范围转向了大范围。
(类似与数值转换) double num =100 (int->double)
5.对象的向下转型
向上转型一定是安全的,但是对象一旦转型为父类,那么就无法调用子类原本特有的内容。
如上例中Cat类定义一个自己的方法catchMouse(),这个方法在子类中是没有办法调用的。
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("eat fish");
}
public void catchMouse() {//定义子类自己的方法
System.out.println("catch mouse");
}
}
public class demo01Main {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
animal.catchMouse();//编译错误
}
}
解决方案:用对象的向下转型还原。
对象的向下转型其实是一个还原动作。
格式:子类名称 对象名 = (子类名称)父类对象
含义:将父类对象,还原为本来的子类对象。
public class demo01Main {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
//animal.catchMouse();
Cat cat = (Cat) animal;//向下转型成为原来的Cat类
cat.catchMouse();
}
}
1.必须保证对象创建的时候就是Cat,才可以向下转型为Cat类。
2.如果对象创建的时候本来不是Cat,强行转型成为Cat 就会报错。
如新建一个类Dog
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("eat bone");
}
public void watchHouse() {
System.out.println("watch house");
}
}
public class demo01Main {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
//animal.catchMouse();
Cat cat = (Cat) animal;
cat.catchMouse();
Dog dog = (Dog) animal;//错误的向下转型 编译不报错,运行会异常,类转换异常。
}
}
(类似与数值转换)int num=(int)10.5(精度损失)
为了保证安全的向下转型,使用instanceof关键字类型判断。
格式 对象 instanceof 类名称 返回一个bool值,表示是否可以转型为这个类。
public class demo02Instanceof {
public static void main(String[] args) {
Animal animal = new Cat();
animal.eat();
//如果需要调用子类特有方法,就需要向下转型。
if (animal instanceof Dog) {//判断是否可以转型
Dog dog = (Dog) animal;
dog.watchHouse();
}
if (animal instanceof Cat) {
Cat cat = (Cat) animal;
cat.catchMouse();
}
}
}