Java复习笔记进阶05:多态、内部类

一、多态

1.多态概述

1.1什么是多态

        同类型对象,执行同一行为,表现出不同的行为特征;

1.2多态常见形式

  • 父类类型 对象名称 = new 子类构造器;

  • 接口 对象名称 = new 实现类构造器;

1.3 多态中成员访问特点

  • 方法调用:编译看左边,运行看右边(多态侧重行为多态)

    • 编译,查看父类中是否有对应方法

    • 运行,执行子类方法结果

  • 变量调用:编译看左边,运行看左边;

1.4 多态前提

  • 有继承/实现关系;

  • 有父类引用指向子类对象;

  • 有方法重写

public abstract class Animal {
    public String name = "动物原型";
    public abstract void run();
}

public class Dog extends Animal{
    public String name = "Dog原型";

    @Override
    public void run() {
        System.out.println("Dog is run");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal dog = new Dog();
        //编译看左,运行看右
        //Dog is run
        dog.run();
        System.out.println(dog.name);

        Animal cat = new Cat();
        cat.run();
        //动物原型,变量采用父类
        System.out.println(cat.name);
    }
}

2.多态优势和问题

  • 多态形态下,右边对象实现解耦合,便于扩展维护;

    • 右侧的子类对象可以调换,不影响其他代码

  • 定义方法,采用父类对象,兼容性强,接收一切子类对象,体现多态扩展性;

  • 存在问题:

    • 以父类为主,使用子类独有方法,报错

public class Test {
    public static void main(String[] args) {
        Animal dog = new Dog();
        go(dog);
        
        Cat cat = new Cat();
        go(cat);
        
        //dog and cat 在go()中效果一致
    }

    /**
     * 要求所有动物都可用
     * @param animal
     */
    public static void go(Animal animal){
        System.out.println("Start Up");
        animal.run();
        System.out.println("Time Out");
    }
}

3.多态下引用数据类型的数据转换

  • 自动类型转换(从子到父,范围小到大):

    • 子类对象赋值给父类类型的变量转换;

  • 强制类型转换(从父到子):

    • 子类 对象变量 = (子类)父类类型变量;

    • 作用:解决多态下劣势,实现调用子类多有功能

      • 		//自动类型转换
                Animal a = new Dog();
                a.run();
        
                //强制类型转换
                Animal b = new Cat();
                b.run();
                //b由父类型强制转换为子类型
                Cat cat = (Cat) b;
                //转为子类型,可以使用独有方法
                cat.eatFish();
    • 转型后类型和对象真实类型不是同一种,类型异常ClassCastException

      • //强制类型转换,编译阶段不报错(有继承或者实现关系可以强转),运行时可能出错;类型异常ClassCastException
        //Dog dog = (Dog) b;

    • Java建议强制转换前 使用instanceof判断

      • /**
             * 要求所有动物都可用
             * 不清楚传进来的动物类型
             * @param animal
             */
            public static void go(Animal animal){
                if (animal instanceof Dog){
                    Dog dog = (Dog) animal;
                    dog.lookDoor();
                }else if (animal instanceof Cat){
                    Cat cat = (Cat) animal;
                    cat.eatFish();
                }
            }

4.多态综合

public interface USB {
    void connect();
    void unConnect();
}

public class KeyBoard implements USB{
    private String name;

    public KeyBoard(String name) {
        this.name = name;
    }

    @Override
    public void connect() {
        System.out.println(name+"成功连接");
    }

    /**
     * 独有功能
     */
    public void keyDown(){
        System.out.println(name+"键入字符");
    }

    @Override
    public void unConnect() {
        System.out.println(name+"成功拔出");
    }
}

public class Mouse implements USB{

    其他同上

    /**
     * 独有功能
     */
    public void dbClick(){
        System.out.println(name+"单击图标");
    }
}

public class Computer {
		其他同上
    /**
     * 提供USB设备安装接口
     */
    public void installUSB(USB usb){
        usb.connect();
        //判断子类类型,强转实现功能
        if (usb instanceof KeyBoard){
            KeyBoard keyBoard = (KeyBoard) usb;
            keyBoard.keyDown();
        }else if (usb instanceof Mouse){
            Mouse mouse = (Mouse) usb;
            mouse.dbClick();
        }
        usb.unConnect();
    }
}
public class Test {
    public static void main(String[] args) {
        Computer computer = new Computer("机械师T58");
        computer.start();

        KeyBoard keyBoard = new KeyBoard("PHILIPS");
        //插入键盘
        computer.installUSB(keyBoard);

        Mouse mouse = new Mouse("罗技");
        computer.installUSB(mouse);
    }
}

二、内部类

1.概述

定义在一个类内的类,里面类可以理解为寄生,外面是宿主;

public class People {
    public class Heart {
		}
}

2.使用场景

  • 一个事务内部,还有一个部分需要完整的结构描述,并且这个内部结构只为外部事务服务,可以用内部类设计

    • (人和各人体器官)(汽车和发动机)与现实对接

  • 内部类通常可以方便访问外部类成员,包括私有

  • 内部类提供更好的封装性,内部类本身可以用private protected修饰,封装做更多控制

    • 外部类只能用public修饰

3.内部类分类

3.1静态内部类

  • 和内部类无区别

  • Outer.inner inner = new Outer.inner();
  • 静态内部类可以直接访问外部类静态成员;共享

  • 静态内部类不可以直接访问外部类实例成员;需要外部类对象

3.2成员内部类(非静态)

  • JDK16后运行成员内部静态

  • Outer.inner inner = new Outer().new inner();
  • 成员内部类可以直接访问外部类静态成员;共享

  • 成员内部类的实例方法可以直接访问外部类实例成员;先有外部,才有内部;

/**
 * 面试试题:
 *      输出对应值
 */
public class People {
    private int heartbeat = 158;
    public class Heart{
        private int heartbeat = 110;
        public void show(){
            int heartbeat = 78;
            System.out.println(heartbeat);//78
            System.out.println(this.heartbeat);//110
            System.out.println(People.this.heartbeat);//158
        }
    }
}

3.3 局部内部类

  • 放在方法,代码块,构造器等执行体中;

  • 局部 内部类产生class文件:外部类$内部类

3.4匿名内部类(重点)

  • 本质:没有名字的局部内部类,放在方法,代码块等执行体中;

  • 作用:方便创建子类对象,为了简化代码编写

  • 特点总结:

    • 匿名内部类写出来就会产生一个匿名对象

    • 匿名对象类型是当前new的类的子类

public class Test {
    public static void main(String[] args) {
        Animal tiger = new Tiger();
        tiger.run();

        //匿名内部类
        Animal rabbit = new Animal() {
            @Override
            public void run() {
                System.out.println("兔子跑");
            }
        };
        rabbit.run();
    }
}

class Tiger extends Animal{
    @Override
    public void run() {
        System.out.println("老虎跑");
    }
}

abstract class Animal{
    public abstract void run();

}

3.4.1匿名内部类常见使用形式

匿名内部类可以作为方法的实际参数进行传输;

public class Test2 {
    public static void main(String[] args) {
        Swimming student = new Swimming() {
            @Override
            public void swim() {
                System.out.println("学生游泳");
            }
        };
        goSwim(student);

        goSwim(new Swimming() {
            @Override
            public void swim() {
                System.out.println("teacher游泳");
            }
        });

    }

    public static void goSwim(Swimming swimming){
        System.out.println("开始");
        swimming.swim();
        System.out.println("结束");
    }
}
interface Swimming{
    void swim();
}

3.4.2 常用使用场景

  • 开发中不是主动去定义匿名内部类代码,别人需要我们写才会用

  • 匿名内部类代码实现代码进一步简化

public class Test3 {
    public static void main(String[] args) {
        //窗口
        JFrame win = new JFrame("清理垃圾界面");
        //画布创建
        JPanel jPanel = new JPanel();
        win.add(jPanel);

        JButton btn1 = new JButton("清理");
        JButton btn2 = new JButton("二次清理");

        //匿名内部类
        btn1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(win,"垃圾清理开始!");
            }
        });
        //匿名内部类:最终目的简化代码
        btn2.addActionListener(e -> JOptionPane.showMessageDialog(win,"二次垃圾清理开始!") );

        jPanel.add(btn1);
        jPanel.add(btn2);

        //窗口宽高,居中,显示
        win.setSize(400,300);
        win.setLocationRelativeTo(null);
        win.setVisible(true);

    }
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值