Java day08——多态、内部类

这里写目录标题

  • 多态
    • 前提
    • 表现
      • 成员变量的调用
      • 方法的调用
    • 总结
    • 类型转换异常
  • 内部类
    • 成员内部类
    • 访问特点
    • 创建内部类对象格式
    • 局部内部类
    • 匿名内部类
    • 静态内部类

多态

多态:是指同⼀⾏为,具有多个不同表现形式 。它是继封装继承之后,⾯向对象的第三⼤特性。
⽣活中,⽐如跑的动作,⼩猫、⼩狗和⼤象,跑起来是不⼀样的。再⽐如⻜的动作,昆⾍、⻦类和⻜机,⻜起来也是不⼀样的。可⻅,同⼀⾏为,通过不同的事物,可以体现出来的不同的形态。多态,描述的就是这样的状态。

前提

  • 继承或者实现【⼆选⼀】,不同种类,两种类型
  • ⽅法的重写【意义体现:不重写,⽆意义】
  • ⽗类引⽤指向⼦类对象【格式体现】

表现

父类型引用 指向 子类型对象 -> 向上造型
父类型 a = new 子类型对象();
接口类型 a = new 实现类对象();

成员变量的调用

  • 多态表现方面1: 成员变量的调用, 子父类中拥有相同的成员变量,并且都有一对get/set方法
  • 如果通过引用直接调用成员变量 - f.age, 看左边类型
  • 通过方法调用成员变量 - f.getAge(), 看右边对象
public class Fu {
    int age = 10;
    int num = 100;

    public void m1() {
        System.out.println("Fu m1方法");
    }
    public void m2() {
        System.out.println("Fu m2方法");
    }
    public int getAge() {
        return this.age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}

public class Zi extends Fu {
    // 和父类中同名的成员变量
    int age = 20;
    // 和父类中不同的成员变量 - 子类自己单独声明的
    int score = 150;
    // 额外继承了父类中的num变量

    // 重写父类中的m1方法
    @Override
    public void m1() {
        System.out.println("Zi m1方法");
    }
    // 继承了父类的m2方法

    // 子类自己的方法 m3
    public void m3() {
        System.out.println("Zi m3方法");
    }
    @Override
    public int getAge() {
        return age;
    }
}

public class Main {
   public static void main(String[] args) {
        // 父类型引用 指向 子类型对象
        Fu f = new Zi();

public class Main1 {
    public static void main(String[] args) {
        Fu f = new Zi();
        System.out.println(f.age); // 10
        
        // 子类中重写了getAge()方法, 得到20,若没有重写getAge()方法, 得到10
        System.out.println(f.getAge()); // 20
        
        // Fu类中没有声明score变量, 不能直接调用
//        System.out.println(f.score);
        // int a = (int)3.14;   double d = 3;
        // 向下转换类型
        Zi zi = (Zi) f;
        System.out.println(zi.score);

方法的调用

  • 多态的表现方面2: 成员方法的调用
  • 最终调用的是哪个方法:优先调用子类重写过的,
    子类中如果没有重写, 就调用父类的方法
public class Main2 {
    public static void main(String[] args) {
        Fu f = new Zi();
        f.m1();//输出:“Zi m1方法”
        // m3没有在Fu中声明, 所以不能直接调用
//        f.m3();
        // 如果想用子类自己的方法, 需要强制转换
        Zi zi = (Zi) f;
        zi.m3();
    }
}

总结

左边类型决定了变量 能调用哪些方法,
右边类型决定了最终使用的方法是哪个 - 优先调用自己重写过的
编译器 看 = 左边类型, 运行时JVM 看 = 右边类型
口诀: 编译看左边, 运行看右边

类型转换异常

ClassCastException: 类型转换异常
解决方案: 转换之前先判断引用 实际上是不是要转换的类型对象
引用a instanceof 子类型 => boolean
问 a 实际上是不是子类型对象,返回true/false

public abstract class Animal {
    public abstract void eat();
}
public class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头!");
    }
    public void watchHouse() {
        System.out.println("狗看家!");
    }
}
public class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼!");
    }
    public void catchMouse() {
        System.out.println("猫和老鼠的故事!");
    }
}

public class Main {
    public static void main(String[] args) {
        Animal d = new Dog();
        d.eat();
        Animal c = new Cat();
        c.eat();

        // 想要调用cat中的catchMouse方法,向下转型
        Cat cat = (Cat) c;
        cat.catchMouse();
        // 编译器看c是Animal类型, 和Dog是父子关系, 所以语法通过
        // 运行时, 发现c实际上是Cat, 不能转换成Dog, 提示ClassCastException
        if(c instanceof Dog) {
            Dog dog = (Dog) c;
            dog.watchHouse();
        }
        giveMePet(new Dog());
        giveMePet(new Cat());
    }
    // Animal作为返回值类型, 这个方法就可以返回多种不同种类的对象
    public Animal salePet() {
        return null;
    }
    // Animal作为参数, 可以传递多种类型的对象
    public static void giveMePet(Animal a){
        if (a instanceof Dog) {
            ((Dog) a).watchHouse();
        } else if (a instanceof Cat) {
            ((Cat) a).catchMouse();
        }
        a.eat();
    }
    /*public static void giveMePet(Dog d) {
        d.watchHouse();
        d.eat();
    }*/

    /*public static void giveMePet(Cat d) {
        d.catchMouse();
        d.eat();
    }*/

}

内部类

类中写个类
人体类 中有 心脏类
车类 中有 发动机类
种类: 成员内部类,静态内部类,局部内部类[匿名内部类]

成员内部类

成员内部类: 权限 public,protected,(default),private
语法:
public class Outer{
// …
public class Inner{
//…
}
}

访问特点

内部类中, 可以随意使用外部类成员
外部类中, 使用内部类成员时需要创建内部类对象
无关类中, 使用内部类成员
1.间接调用, 在外部类方法中调用内部类方法
main方法中, 调用外部类方法
2.直接调用, 需要创建内部类对象
外部类.内部类 a = new 外部类().new 内部类();
内部类和外部类有同名成员变量
外部类的成员变量: 外部类.this.变量
内部类的成员变量: this.变量

创建内部类对象格式

外部类名.内部类名 对象名 = new 外部类型().new 内部类型();

局部内部类

局部内部类: 在方法内部定义类, 只在方法中有效
不能使用权限修饰符
在局部内部类中, 使用局部变量, 必须是final的
JDK8 后, 局部变量事实上没有发生改变, 那么final可以省略
一次性的类, 只能用一次

局部内部类, 需要类只使用一次, 优化 -> 匿名内部类

匿名内部类

继承抽象类或实现接口
语法: new 接口/抽象类() {
int a;
// 实现的所有抽象方法
}
匿名内部类, 只能用一次, new一个对象
匿名对象, 只能使用一次, 只能调用一次方法
注意: 匿名内部类 和 匿名对象 不是一回事 ! ! !

静态内部类

静态内部类 对比 成员内部类 => 静态方法 和 成员方法

你可能感兴趣的:(javaEE)