JavaSE基础知识之多态

一、 概述

    多态是继封装、继承之后,面向对象的第三大特性,指同一行为,具有多个不同表现形式。生活中,比如跑的动作,小猫、小狗和大象,跑起来是不一样的。再比如飞的动作,昆虫、鸟类和飞机,飞起来也是不一样的。可见,同一行为,

通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

    多态体现的格式:父类类型 变量名 = new 子类对象;变量名.方法名();

    代码如下:
Fu f = new Zi();
f.method();

1.1  多态调用成员方法

    当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写后的方法(编译看左边,运行看右边)。

1.2  多态调用成员变量

    当使用多态方式调用成员变量时,首先检查父类中是否有该变量,如果没有,则编译错误;如果有,执行的是父类的成员变量(编译看左边,运行看左边)。

1.3  多态的类型转换

    当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子类特有的方法,必须做向下转型。

    代码如下:

abstract class Animal {
        abstract void eat();
    }

    class Cat extends Animal {
        public void eat() {
            System.out.println("吃鱼");
        }

        public void catchMouse() {
            System.out.println("抓老鼠");
        }
    }

    class Dog extends Animal {
        public void eat() {
            System.out.println("吃骨头");
        }

        public void watchHouse() {
            System.out.println("看家");
        }
    }

    public class Test {
        public static void main(String[] args) {
            // 向上转型 
            Animal a = new Cat();
            a.eat(); // 调用的是 Cat 的 eat 
            // 向下转型 
            Cat c = (Cat) a;
            c.catchMouse(); // 调用的是 Cat 的 catchMouse
        }
    }

    但是,转型有可能会发生异常,请看下面代码   

public class Test { 
    public static void main(String[] args) { 
        // 向上转型 
        Animal a = new Cat();
        a.eat(); // 调用的是 Cat 的 eat 
        // 向下转型 
        Dog d = (Dog)a; 
        d.watchHouse(); // 调用的是 Dog 的 watchHouse 【运行报错】
    } 
}                
    这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。为了避免ClassCastException的发生,Java提供了 instanceof 关键字,给引用变量做类型的校验,格式如下:
  • 变量名 instanceof 数据类型
  • 如果变量属于该数据类型,返回true。
  • 如果变量不属于该数据类型,返回false。 
    所以,转换前,我们最好先做一个判断,代码如下:
public class Test { 
    public static void main(String[] args) {
        // 向上转型 
        Animal a = new Cat();
        a.eat(); // 调用的是 Cat 的 eat 
        // 向下转型 
        if (a instanceof Cat){ 
            Cat c = (Cat)a;
            c.catchMouse(); // 调用的是 Cat 的 catchMouse 
        } else if (a instanceof Dog){
            Dog d = (Dog)a; 
            d.watchHouse(); // 调用的是 Dog 的 watchHouse 
        } 
    } 
}                        

二、  final关键字

    final: 不可改变。可以用于修饰类、方法和变量。

  • 类:被修饰的类,不能被继承。
  • 方法:被修饰的方法,不能被重写。
  • 变量:被修饰的变量,不能被重新赋值(如果修饰的是引用类型变量,不可修改其指向地址,但是可以修改引用类型的属性值)。

三、  权限修饰符   

    在Java中提供了四种访问权限,使用不同的访问权限修饰符修饰时,被修饰的内容会有不同的访问权限,
  • public:公共的。
  • protected:受保护的
  • default:默认的
  • private:私有的

3.1  不同权限的访问能力

四、  内部类

4.1  概述

     将一个类A定义在另一个类B里面,里面的那个类A就称为内部类,B则称为外部类。内部类可以直接访问外部类的成员,包括私有成员。外部类要访问内部类的成员,必须要建立内部类的对象。

4.2  匿名内部类 

    匿名内部类  是内部类的简化写法。它的本质是 一个带具体实现的父类或者父接口的匿名的子类对象。开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作,
  • 1. 定义子类
  • 2. 重写接口中的方法
  • 3. 创建子类对象
  • 4. 调用重写后的方法
    而我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是这样做的快 捷方式。代码如下
 //定义接口:
    public abstract class FlyAble {
        public abstract void fly();
    }

    public class InnerDemo {
        public static void main(String[] args) {
        /*1.等号右边:是匿名内部类,定义并创建该接口的子类对象 2.等号左边:是多态赋值,接口类型引用指向子类对象 */
            FlyAble f = new FlyAble() {
                public void fly() {
                    System.out.println("我飞了~~~");
                }
            };
            //调用 fly方法,执行重写后的方法 
            f.fly(); 
        }
    }                
    通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:  
public class InnerDemo3 {
  public static void main (String[]args){ 
  /*创建匿名内部类,直接传递给showFly(FlyAble f) */
    showFly(new FlyAble() {
       public void fly() {
         System.out.println("我飞了~~~");
       }
    });
   }
   public static void showFly (FlyAble f){
     f.fly();
   }
}

摘自:黑马程序员讲义

猜你喜欢

转载自www.cnblogs.com/linfuxian/p/11864893.html