JavaSE进阶笔记:03(多态、内部类、)

109 阅读6分钟

一、多态

1.多态概述

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

1.1多态常见形式

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

1.2 多态中成员访问特点

  • 方法调用:编译看左边,运行看右边(多态侧重行为多态)
    • 编译,查看父类中是否有对应方法
    • 运行,执行子类方法结果
  • 变量调用:编译看左边,运行看左边;

1.3 多态前提

  • 有继承/实现关系;
  • 有父类引用指向子类对象;
  • 有方法重写
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.多态下引用数据类型的数据转换

类型转换范围作用
自动类型转换从子到父,范围小到大子类对象赋值给父类类型的变量转换;
强制类型转换父到子子类 对象变量 = (子类)父类类型变量;解决多态下劣势,实现调用子类多有功能

3.1 数据转换实例

    		//自动类型转换
            Animal a = new Dog();
            a.run();
      
            //强制类型转换
            Animal b = new Cat();
            b.run();
            //b由父类型强制转换为子类型
            Cat cat = (Cat) b;
            //转为子类型,可以使用独有方法
            cat.eatFish();

3.2 转型后类型和对象真实类型不是同一种,类型异常ClassCastException

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

3.3 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 Swim {
    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.包装类:8种基本数据类型的引用类

基本数据类型引用数据类型
byteByte
shortShort
intInteger
longLong
charCharacter
floatFloat
doubleDouble
booleanBoolean

2.为什么提供包装类

  • java为了实现一切皆对象;
  • 集合和泛型只能支持包装类型;

3.自动装箱拆箱

自动装箱基本数据类型变量可以直接赋值给包装类型变量
自动拆箱包装类型变量可以直接赋值给基本数据类型变量

4.包装类特有功能

  • 包装类变量默认值null,容错率高;
  • 可以把基本类型数据转为字符串类型;
    • toString()方法
    • Integer.toString(基本类型数据)
    • 可以直接得到字符串类型String rs = i +"";
  • 可以把字符串类型数值转为真实数据类型(重点):
    • Integer.parseInt("字符串类型整数")
    • Double.parsedouble("字符串类型小数")
    • 要去转换的String内容必须符合转换后要求;

RecordDate:2021/08/12