1.多态

1.1、多态的概述

  • 什么是多态?

    • 指对象可以有多种形态
  • 常见形式

    • Animal dog = new Dog();
      
  • 多态中成员访问特点

    • 方法调用:编译看左边,运行看右边
    • 变量调用:编译看左边,运行也看左边【注意】
  • 多态的前提

    • 有继承/实现关系,有父类引用指向子类对象,有方法重写(多态侧重行为多态)

1.2、多态的优势

  • 在多态形式下,右边对象可以实现解耦合,便于扩展和维护

  • 定义方法的时候,使用父类型作为参数,该方法就可以接受父类的一切子类对象,体现出多态的扩展性和便利

【多态会产生一个问题】:多态下不能使用子类的独有方法

【instance关键字】

  • 用来判断该对象是否某个对象的类型,返回true/false

1.3、多态下:类型转换问题

  • 自动类型转换(从子到父)
Animal c = new Cat();
  • 强制类型转换(从父到子)

    • 从父到子(必须进行强制类型转换,否则报错)

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

    • 作用:可以解决多态下的劣势,可以实现调用子类独有的方法
    • 注意:有继承/实现关系的类就可以在编译阶段进行强制类型转换;但是,如果转型后的类型和真实对象的类型不是同一种类型,那么在运行时就会出现 ClassCastException
    Aniaml c = new Cat();
    Dog d = (Dog) c;//出现异常 ClassCastExcetion
    
  • instance

    • 形式:变量名 instanceof 真实类型
    • 判断关键字左边的变量指向的对象的真实类型,是否是右边的类型或者是其子类类型,返回true/false

1.4、多态综合案例

【需求】

  • 定义一个USB的接口(方法可以接入和拔出)
  • 拥有键盘和鼠标来连接USB
  • 创建电脑对象,分别触发功能

【USB接口】

public interface USB {
    void interposition();//插入
    void pullOut();//拔出
}

【keyboard键盘】

public class keyboard implements USB{
    private String name;
    public void type(){
        System.out.println("打字功能-----");
    }

    @Override
    public void interposition() {
        System.out.println("插入键盘");
    }

    @Override
    public void pullOut() {
        System.out.println("拔出键盘");
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
    public keyboard(String name) {
        this.name = name;
    }
}

【Mouse鼠标】

public class Mouse implements USB{
    private String name;
    public void click(){
        System.out.println("点击功能------");
    }

    @Override
    public void interposition() {
        System.out.println("插入鼠标");
    }

    @Override
    public void pullOut() {
        System.out.println("拔出鼠标");
    }
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

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

【Computer电脑】

public class Computer{
    private String name;

    public void installUSB(USB usb){
        if(usb instanceof keyboard){
            keyboard k = (keyboard) usb;
            k.type();
        }else if(usb instanceof Mouse){
            Mouse m = (Mouse) usb;
            m.click();
        }
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

【Test】

public class Test {
    public static void main(String[] args) {
        Computer computer = new Computer("神州");

        USB usb = new keyboard("达尔优");
        computer.installUSB(usb);
        USB usb1 = new Mouse("狗屁王");
        computer.installUSB(usb1);
    }
}

2.内部类

2.1、内部类概述【了解】

  • 内部类

    • 内部类就是定义在一个类里面的类,里面的类可以理解成(寄生),外部类可以理解成(宿主)

    • public class People{
          //内部类
          public class heart{
      
          }
      }
      
  • 内部类场景使用

    • 当一个事物的内部,还有一个部分需要一个完整的结构进行描述时。
  • 基本作用
    • 内部类通常可以方便访问外部类的成员,包括私有成员
    • 内部类提供了更好的封装性,内部类本身就可以用 private,protected等修饰,封装性可以做更多控制

2.2、静态内部类【了解】

  • 静态内部类

    • static修饰,属于外部类本身
    • 特点和使用于普通类完全一样,类有的成分它都有,只是位置在别人里面而已
    public class Outer{
        //静态内部类
        public static class inner{
    
        }
    }
    
  • 静态内部类创建对象格式

    • 外部类名.内部类名 对象名 = new 外部类名.内部类名构造器

2.3、成员内部类【了解】

  • 成员内部类
    • 无static修饰,属于外部类的对象
    • JDK16之前,成员内部类中不能定义静态变量,JDK 16开始也可以定义静态成员了。
public class Outer{
    //成员内部类
    public class Inner{

    }
}
  • 成员内部类创建对象的格式:

  • 外部类名.内部类名 对象名= new 外部类构造器.内部类构造器();

Outer.Innter inner = new Outer().new Inner();

【成员内部类-面试笔试题】

  • 观察以下代码,些出合适的代码对应其注释要求输出结果
class People{
    private int heartbeat = 150;
    public class Heart{
        private int heartbeat = 110;
        public void show(){
            int heartbeat = 78;
            System.out.println(??);//78
            System.out.println(??);//110
            System.out.println(??);//150
        }    
    }
}

【heartbeat,this.heartbeat,People.this.heartbeat】

2.4、匿名内部类概述【重点】

  • 匿名内部类
    • 本质上是一个没有名字的局部内部类
    • 作用:方便创建子类对象,最终目的是为了简化代码
  • 格式
    • new 类|抽象类名|接口名(){ 重写方法; };
Employee a = new Employee(){//Employee为接口
    @Override
    public void work(){
        System.out.println("员工正在工作");
    }
}
  • 特点
    • 匿名内部类是一个没有名字的内部类,同时也代表了一个对象
    • 匿名内部产生的对象类型,相当于是当前 new 的那个类型的子类类型

2.5、匿名内部类常见使用形式

【需求】:某学校要求让老师,学生,运动员一起参加游泳比赛

public class Test {
    public static void main(String[] args) {
        Swimming s = new Swimming(){
            @Override
            public void swim(){
                System.out.println("学生正在🏊‍");
            }
        };
        go(s);
        Swimming teacher = new Swimming() {
            @Override
            public void swim() {
                System.out.println("老师正在🏊‍");
            }
        };
        go(teacher);
        Swimming athlete = new Swimming() {
            @Override
            public void swim() {
                System.out.println("运动员🏊的很快‍");
            }
        };
        go(athlete);
    }
    public static void go(Swimming s){
        System.out.println("开始");
        s.swim();
        System.out.println("结束");
    }
}
interface Swimming{
    void swim();
}

2.6、匿名内部类真实使用场景

【需求】:给按钮绑定单击时间

public class Test02 {
    public static void main(String[] args) {
        //1.创建窗口
        JFrame windows = new JFrame("登录界面");

        //2.创建一个按钮
        JButton bt = new JButton("登录");

        //绑定按钮监听器
//        bt.addActionListener(new ActionListener() {
//            @Override
//            public void actionPerformed(ActionEvent e) {
//                System.out.println("登录成功");
//            }
//        });
        //简化代码
        bt.addActionListener( e -> System.out.println("登录成功"));

        //3.展示设置
        windows.setSize(400,300);
        windows.setVisible(true);
        //类似于桌布,设置大小吧按钮放在桌布上
        JPanel panel = new JPanel();
        panel.add(bt);

        windows.add(panel);
    }

3.常用API

3.1、object类:toString方法

  • object类的作用:
    • 一个类要么默认继承了Object类,要么间接继承了Objec类,Object类是Java中的祖宗类
    • Object作为所有类的父类,提供了很多常用的方法给每个子类对象拿来使用
  • Object类的常用方法

  • 问题引出
    • 开发中直接输出对象,默认输出对象的地址是没有用
    • 开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息
  • toString存在的意义
    • 父类 toString() 方法存在的意义就是为了被子类重写,以便返回对象的内部信息,而不是地址信息。

【idea提供了每个类可以快捷重写toString方法,来输出对象的信息,而不是地址】

3.2、Object类:equals方法

  • 问题思考
    • 直接比较两个对象的地址是否完全相同用 “==” 代替 equals
    • 同时,开发中很多业务情况下,更像判断2个对象的内容是一样的
  • equals存在的意义
    • 为了被子类重写,以便子类自己来定义比较规则(比如比较对象内容)

3.3、Objects

  • 概述
    • Objects是一个工具类,提供了一些方法去完成一些功能
  • 官方在进行字符串比较时,没有用字符串对象的equals方法,而是用Objects的equals方法来比较
  • 因为更安全【Objects里面的equals方法存在判定为空逻辑】

  • Objects常见方法

  • 源码分析
public static boolean equals(Object a,Object b){
    return (a == b) || (a !=null && a.equals(b));
}

3.4、StringBuilder

  • 概述

    • StringBuilder 是一个可变的字符串的操作类,可以看作是一个对象容器
    • 使用 StringBuilder 的核心作用:操作字符串的性能比 String要更高(如拼接,修改)
  • String原理图

【一个加号,堆内存中就会有两个对象】(性能不好)

  • StringBuilder提高效率原理图

  • StringBuilder 构造器

  • StringBuilder常用方法

3.5、打印整形数组内容案例

【需求】:设计一个方法用于输出任意整型数组的内容,要求输出成如下格式:"该数组内容为:[11,22,33,44,55]"

public class Test {
    public static void main(String[] args) {

    }
    public static String toString(int[] arr){
        if(arr!=null){
            int[] numbers = {11,22,33,44,55};
            StringBuilder sb = new StringBuilder("[");
            for (int i = 0; i < numbers.length; i++) {
                sb.append(numbers[i]).append(i==numbers.length-1 ?"":",");
            }
            return sb.append("]").toString();
        }
        return null;
    }
}

3.6、Math

  • Math类

    • 包含执行基本数字运算的方法,Math类没有提供公开的构造器
    • 如何使用?—看类的成员是否都是静态的,如果是,通过类名就可以直接调用
  • Math类的常用方法

  • 举例输出
public static void main(String[] args) {
        //1.取绝对值:返回正数
        System.out.println(Math.abs(-20));
        //2.向上取整:
        System.out.println(Math.ceil(4.0000001));
        //3.向下取整:
        System.out.println(Math.floor(4.999999));
        //4.求指数次方
        System.out.println(Math.pow(2,3));
        //5.四舍五入
        System.out.println(Math.round(4.49999));
        System.out.println(Math.round(4.500001));
        //6.0-1.0之间随机数
        System.out.println(Math.random());
    }

3.7、System

  • System类概述
    • System的功能是通用的,都是直接用类名调用即可,所以Syste不能被实例化
  • System类的常用方法

  • 时间毫秒值
    • 计算机认为时间是有起点的,起始时间:1970.1.1 00:00:00
    • 指的是从1970年1月1日 00:00:00走到此刻的总的毫秒数
  • 原因

    • 1969年8月,贝尔实验室的程序员肯汤普逊利用妻儿离开一个月的机会,开始着手创造一个全新的革命性的操作系统,他使用B编译语言在老旧的PDP-7机器上开发出了Unix的一个版本,随后,汤普逊和同时丹尼斯里奇改进了B语言,开发出了C语言,重写了Unix
    • 1970.1.1 算是C语言的生日
  • 作用:

    • 做性能分析:【通过两个时间中间的代码来测试代码执行的时间】
public class Test {
    public static void main(String[] args) {
        System.out.println("程序开始");

        //System.exit(0);//JVM终止

        //2,计算机认为时间有起源:发牛1970-1-1 00:00 走到此时的总毫秒值
        System.out.println(System.currentTimeMillis());

        //3.数组拷贝(了解)
        int[] arr = {10,20,30,40,50,60,70};
        int[] arr2 = new int[6];//[0,0,0,0,0,0] => [0,0,40,50,60,0]
        System.arraycopy(arr,3,arr2,2,3);
        System.out.println(Arrays.toString(arr2));

        System.out.println("程序结束");
    }
}

3.8、BigDecimal

  • 作用
    • 用于解决浮点型运算精度失真的问题
public static void main(String[] args){
    //浮点型运算的时候直接+* /可能会出现数据失真(精度问题)
    System.out.println(0.09+0.01);//0.09999999999999999
    System.out.println(1.0-0.32);//0.6799999999999999
    System.out.println(1.015*100);//101.49999999999999
    System.out.println(1.301 / 100);//0.013009999999999999
    double c = 0.1+0.2;
    System.out.println(c);//0.30000000000000004
}
  • 使用步骤

    • 创建对象BigDecimal封装浮点型数据(最好是调用方法)
    public static BigDecimal valueOf(double val);
    //包装浮点数称为Bigdecimal对象
    
  • BigDecimal常用API

public class Test {
    public static void main(String[] args) {
        double a = 0.1;
        double b = 0.2;
        double c = a + b;
        System.out.println(c);

        System.out.println("-----------------");

        BigDecimal a1 = BigDecimal.valueOf(a);
        BigDecimal b1 = BigDecimal.valueOf(b);
        //加
        System.out.println(a1.add(b1));
        //减
        System.out.println(a1.subtract(b1));
        //乘
        System.out.println(a1.multiply(b1));
        //除
        System.out.println(a1.divide(b1));

        //转为Double
        double rs = a1.doubleValue();
        System.out.println(rs);
    }
}

results matching ""

    No results matching ""