Java进阶笔记-多态与内部类

视频地址:https://www.bilibili.com/video/BV1Cv411372m
此笔记是:P113 - P119

1.面向对象三大特征之三:多态(重点)

1.1 多态的概述、多态的形式

  • 什么是多态?

    • 同类型的对象,执行同一个行为,会表现出不同的行为特征。
      • 例如:下面举得例子,同类型的对象(都是动物类型的),执行同一个行为(run方法)
  • 多态的常见形式

    • 接口也可以看成是一种父类(理解成干爹),实现类即为它的子类。
    父类类型 对象名称 = new 子类构造器;
    接口     对象名称 = new 实现类构造器;	
    

Java进阶笔记-多态与内部类_第1张图片

/**
    父类 Animal.java
 */
public class Animal {
    public String name = "父类动物名称";
    public void run(){
        System.out.println("动物可以跑~~");
    }
}

/**
    子类 Dog.java
 */
public class Dog extends Animal{
    public String name = "子类狗名称";
    @Override
    public void run() {
        System.out.println("跑的贼溜~~~~~");
    }
}

/**
    子类 Tortoise.java
 */
public class Tortoise extends Animal{
    public String name = "子类乌龟名称";

    @Override
    public void run() {
        System.out.println("跑的非常慢~~~");
    }
}
  • 多态中成员访问特点

    • 方法调用:编译看左边,运行看右边。
    • 变量调用:编译看左边,运行也看左边。(多态侧重行为多态
    /**
        测试 Test.java
     */
    public class Test {
        public static void main(String[] args) {
            // 目标:先认识多态的形式
            // 父类  对象名称 = new 子类构造器();
            Animal a = new Dog();
            a.run(); // 方法调用:编译看左,运行看右 【执行时,编译看Animal里面是否有run方法,但真正跑的时候走的是真实对象Dog里面的run方法。
            
            System.out.println(a.name); // 变量调用:编译看左,运行也看左 故打印出来为:父类动物名称
    
            Animal a1 = new Tortoise();
            a1.run();
            System.out.println(a1.name); //打印结果为:父类动物名称
        }
    }
    
    • 那么为什么是这样的呢?
      • 设计层面上的考虑,因为多态侧重行为(编译的时候方法代表行为),运行看右边对象才能实现在不同对象下表现不同行为。
      • 从重写角度来说,父类的方法可能会是抽象的。最终还是子类的重写方法才可以跑,一定是要看右边的。
      • 但变量的话,无论子类还是父类变量都是可以用的,写代码的时候,已经说了是访问父类的(看左边),然后变量没有多态的概念,所以变量不再去看右边了。
  • 多态的前提

    • 继承/实现关系;有父类引用指向子类对象;有方法重写

1.2 多态的好处

  • 在多态形式下,右边对象可以实现解耦合,便于扩展和维护。
    在这里插入图片描述

  • 定义方法的时候,使用父类型作为参数,该方法就可以接收这父类的一切子类对象,体现出多态的扩展性与便利。
    Java进阶笔记-多态与内部类_第2张图片
    Java进阶笔记-多态与内部类_第3张图片

  • 多态下会产生的一个问题:多态下不能使用子类的独有功能。

    • 因为编译的时候要看父类(左边的),子类独有行为父类里面是无的,编译阶段就会报错的。
      Java进阶笔记-多态与内部类_第4张图片
      Java进阶笔记-多态与内部类_第5张图片
      Java进阶笔记-多态与内部类_第6张图片

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

  • 自动类型转换(从子到父):子类对象赋值给父类类型的变量指向。

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

    • 此时必须进行强制类型转换:子类 对象变量 = (子类)父类类型的变量
      Java进阶笔记-多态与内部类_第7张图片
      在这里插入图片描述

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

    • 注意: 如果转型后的类型和对象真实类型不是同一种类型,那么在转换的时候就会出现ClassCastException

      Animal t = new Tortoise();
      Dog d = (Dog)t; // 强制类型转换,编译阶段不报错的(注意:有继承或者实现关系编译阶段可以强制,没有毛病)【因为官方会觉得t Animal可能真的指向Dog类型,允许转Dog的】但运行时出现异常 ClassCastException
      
  • Java建议强转转换前使用instanceof判断当前对象的真实类型,再进行强制转换
    在这里插入图片描述
    Java进阶笔记-多态与内部类_第8张图片
    Java进阶笔记-多态与内部类_第9张图片

    • 有时候是必须要加判断的,例如在方法中:
      Java进阶笔记-多态与内部类_第10张图片Java进阶笔记-多态与内部类_第11张图片

1.4 多态的综合案例

Java进阶笔记-多态与内部类_第12张图片

  • USB的接口类:接入、拔出

    public interface USB {
        void connect(); // 接入
        void unconnect(); // 拔出
    }
    
  • 2个USB的实现类:鼠标、键盘

    • 键盘实现类

      public class KeyBoard implements USB{
          // 键盘必须要有自己的名字(商标名称)
          private String name;
          
          // 有参构造器
          public KeyBoard(String name) {
              this.name = name;
          }
      
          @Override
          public void connect() {
              System.out.println(name + "成功的接入了设备了~~~");
          }
          @Override
          public void unconnect() {
              System.out.println(name + "成功的从设备弹出了~~~");
          }
      
          /**
            独有功能
           */
          public void keyDown(){
              System.out.println(name + "写下了:老铁,6666,下次再来哦,老弟~~~~");
          }
      
          // 无参构造器
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
      }
      
    • 鼠标实现类

      public class Mouse implements USB{
          private String name;
          public Mouse(String name) {
              this.name = name;
          }
      
          @Override
          public void connect() {
              System.out.println(name + "成功的接入了设备了~~~");
          }
          @Override
          public void unconnect() {
              System.out.println(name + "成功的从设备弹出了~~~");
          }
      
          /**
            独有功能
           */
          public void click(){
              System.out.println(name + "双击点亮小红心~~~~");
          }
      
          public String getName() {
              return name;
          }
          public void setName(String name) {
              this.name = name;
          }
      }
      
  • 创建一个电脑对象,创建USB设备对象,安装启动

    public class Computer {
        private String name;
        public Mouse(String name) {
            this.name = name;
        }
        
        
        /**
           提供安装USB设备的入口。
         */
        public void installUSB(USB u){ // 这里是多态:父类接口作为入参,所有的实例(子类)对象都能进来
            // 这里的 USB 可能是鼠标也可能是键盘
            
            u.connect(); //这个是通用功能
    
            // 独有功能
            // 调用独有功能时不能直接 u.click() 或者 u.keyDown() 因为它并不知道对象具体指谁
            if(u instanceof Mouse){
                Mouse m = (Mouse) u;
                m.click();
            }else if(u instanceof KeyBoard) {
                KeyBoard k = (KeyBoard) u;
                k.keyDown();
            }
    
            u.unconnect();//这个是通用功能
        }
        
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
    }
    
  • 开始组装

    public class Test {
        public static void main(String[] args) {
            // a、创建电脑对象
            Computer c = new Computer();
            // b、创建USB设备,鼠标对象,键盘对象
            //Mouse u = new Mouse("罗技鼠标"); 这样写也成,但多数是下面多态写法!
            USB u = new Mouse("罗技鼠标");
            c.installUSB(u);
            USB k = new KeyBoard("双飞燕键盘");
            c.installUSB(k);
        }
    
    }
    

2.内部类

2.1 内部类概述

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

    public class People{
        // 内部类
        public class Heart{
        }
    }
    
  • 内部类的使用场景、作用

    • 当一个事物的内部,还有一个部分需要一个完整的结构进行描述,而这个内部的完整的结构又只为外部事物提供服务,那么整个内部的完整结构可以选择使用内部类来设计。【例如:人是一个类,要关于这个人的心脏信息,则在人里面定义一个心脏类】
    • 内部类通常可以方便访问外部类的成员,包括私有的成员
    • 内部类提供了更好的封装性,内部类本身就可以用 private protectecd 等修饰,封装性可以做更多控制。
  • 内部类的分类

    • 静态内部类[了解]
    • 成员内部类(非静态内部类) [了解]
    • 局部内部类[了解]
    • 匿名内部类(重点)

2.2 内部类之一:静态内部类[了解]

  • 什么是静态内部类?

    • static修饰属于外部类本身。
    • 它的特点和使用与普通类是完全一样的,类有的成分它都有【静态成员变量、实例成员变量、Getter、Setter、有参无参构造器、普通方法】,只是位置在别人里面而已。
    public class Outer{
        // 静态成员内部类
        public static class Inner{
            
        }
    }
    
  • 静态内部类创建对象的格式:

    格式:外部类名.内部类名 对象名 = new 外部类名.内部类构造器;
    范例:Outer.Inner in =  new Outer.Inner();
    

Java进阶笔记-多态与内部类_第13张图片

  • 静态内部类的访问拓展:

    • 1、静态内部类中是否可以直接访问外部类的静态成员?

      • 可以,外部类的静态成员只有一份可以被共享访问。
        Java进阶笔记-多态与内部类_第14张图片
    • 2、静态内部类中是否可以直接访问外部类的实例成员?

      • 不可以的,外部类的实例成员必须用外部类对象访问。
        Java进阶笔记-多态与内部类_第15张图片

      • 为什么不能访问?

        • 因为hobby属于外部类对象的,直接访问是不知道 要访问的是外部类那个对象的hobby。

        • 若非要访问外部类成员,必须 new外部类对象
          Java进阶笔记-多态与内部类_第16张图片

          Java进阶笔记-多态与内部类_第17张图片

2.3 内部类之二:成员内部类[了解]

  • 什么是成员内部类?

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

    格式:外部类名.内部类名 对象名 = new  外部类构造器.new 内部类构造器();
    范例:Outer.Inner in =  new Outer().new  Inner();
    

Java进阶笔记-多态与内部类_第18张图片

  • 成员内部类的访问拓展:

    • 1、成员内部类中是否可以直接访问外部类的静态成员?
      • 可以,外部类的静态成员只有一份可以被共享访问。
    • 2、成员内部类的实例方法中是否可以直接访问外部类的实例成员?
      • 可以的,因为必须先有外部类对象,才能有成员内部类对象,所以可以直接访问外部类对象的实例成员。Java进阶笔记-多态与内部类_第19张图片
  • 静态内部类与成员内部类

    • 成员内部类:一定先外部类对象,才有内部类对象。【例如:心脏不可能独立,一定先有个人对象再创建心脏对象】
    • 静态内部类:其实可以独立出来的,可以先不外部类对象。Java进阶笔记-多态与内部类_第20张图片
      Java进阶笔记-多态与内部类_第21张图片

2.4 内部类之三:局部内部类[了解]

  • 局部内部类 (鸡肋语法,了解即可

    • 局部内部类放在方法、代码块、构造器等执行体中。

    • 局部内部类的类文件名为: 外部类$N内部类.class。
      Java进阶笔记-多态与内部类_第22张图片

2.5 内部类之四:匿名内部类概述[重点]

  • 匿名内部类:

    • 本质上是一个没有名字的局部内部类,定义在方法中、代码块中、等。
    • 作用:方便创建子类对象,最终目的为了简化代码编写。
  • 格式:

    new|抽象类名|或者接口名() {
        重写方法;
    };
    
    Animal a = new Animal() {
        public void run() {
            
        }
    };
    a. run();
    
  • 正常我们是

    public class Test {
        public static void main(String[] args) {
            Animal a = new Tiger();
            a.run();
        }
    }
    
    class Tiger extends Animal{
        @Override
        public void run() {
            System.out.println("老虎跑的快~~~");
        }
    }
    
    abstract class Animal{
        public abstract void run();
    }
    
  • 现在匿名内部类是

    public class Test {
        public static void main(String[] args) {
            Animal a = new Animal(){
                @Override
                public void run() {
                    System.out.println("老虎跑的快~~~");
                }
            };
            a.run();
        }
    }
    
    abstract class Animal{
        public abstract void run();
    }
    
  • 特点总结:

    • 匿名内部类是一个没有名字的内部类。
    • 匿名内部类写出来就会产生一个匿名内部类的对象。例如:上面例子,并不是产生了Animal,Animal是抽象类不会创建对象,匿名内部类创建的就只是匿名内部类的对象
    • 匿名内部类的对象类型相当于是当前new的那个的类型的子类类型。例如:上面例子,相当于是Animal的子类类型
      Java进阶笔记-多态与内部类_第23张图片

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

  • 匿名内部类在开发中的使用形式了解

    • 某个学校需要让老师,学生,运动员一起参加游泳比赛
    /*游泳接口*/
    public interface Swimming {
        void swim();
    }
    
    /* 测试类*/
    public class JumppingDemo {
        public static void main(String[] args) {
            //需求:goSwimming方法
        }
         
        // 定义一个方法让所有角色进来一起比赛
        public static void goSwimming(Swimming swimming) {
            swimming.swim();
        }
    }
    
/**
    【之前方法】目标:掌握匿名内部类的使用形式(语法)
 */
public class Test2 {
    public static void main(String[] args) {
        Swimming s = new Student();
        go(s);
    } 
    /**
       学生 老师 运动员可以一起参加游泳比赛
     */
    public static void go(Swimming s){ // 接口充当一种父类,所有子类对象都可以送进来
        System.out.println("开始。。。");
        s.swim();
        System.out.println("结束。。。");
    }
}

class Student implement Swimming{
    @Override
    public void swim() {
       System.out.println("学生快乐的自由泳‍");
     }
}

interface Swimming{
    void swim();
}
/**
    【匿名内部类】目标:掌握匿名内部类的使用形式(语法)
 */
public class Test2 {
    public static void main(String[] args) {
        Swimming s = new Swimming() {
            @Override
            public void swim() {
                System.out.println("学生快乐的自由泳‍");
            }
        };
        go(s);

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

        Swimming s1 = new Swimming() {
            @Override
            public void swim() {
                System.out.println("老师泳的贼快~~~~~");
            }
        };
        go(s1);

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

	   /**
	      匿名内部类可以作为方法的实际参数进行传输。
	   */        
        go(new Swimming() { 
            @Override
            public void swim() {
                System.out.println("运动员的贼快啊~~~~~");
            }
        });


    }

    /**
       学生 老师 运动员可以一起参加游泳比赛
     */
    public static void go(Swimming s){
        System.out.println("开始。。。");
        s.swim();
        System.out.println("结束。。。");
    }
}


interface Swimming{
    void swim();
}

Java进阶笔记-多态与内部类_第24张图片

  • 使用总结:
    • 匿名内部类可以作为方法的实际参数进行传输。

2.7 匿名内部类真实使用场景演示

  • 匿名内部类在开发中的真实使用场景演示

    • 给按钮绑定点击事件
      Java进阶笔记-多态与内部类_第25张图片
    //  为按钮绑定点击事件监听器。
    btn.addActionListener(new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("登录一下~~");
        }
    });
    //  btn.addActionListener(e -> System.out.println("登录一下~~"));
    
  • 具体

    import javax.swing.*;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    /**
       目标:通过GUI编程 理解匿名内部类的真实使用场景
     */
    public class Test3 {
        public static void main(String[] args) {
            // 1、创建窗口
            JFrame win = new JFrame("登录界面");
            JPanel panel = new JPanel(); 
            win.add(panel); //添加桌布
    
            // 2、创建一个按钮对象
            JButton btn = new JButton("登录");
    
            // 注意:讲解匿名内部类的使用
            btn.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    JOptionPane.showMessageDialog(win, "点我一下,说明爱我!");
                }
            });
    
    //btn.addActionListener( e ->JOptionPane.showMessageDialog(win, "别说话!!") );
    
    
            // 3、把按钮对象添加到桌布上展示
            panel.add(btn);
    
            // 4、展示窗口
            win.setSize(400, 300);
            win.setLocationRelativeTo(null);
            win.setVisible(true);
    
        }
    }
    

Java进阶笔记-多态与内部类_第26张图片

  • 使用总结:

    • 开发中不是我们主动去定义匿名内部类的,而是别人需要我们写或者我们可以写的时候才会使用。
    • 匿名内部类的代码可以实现代码进一步的简化(回扣主题)

3.常用API

3.1 Object

3.1.1 to String方法

  • 什么是API?

    • API(Application Programming interface) 应用程序编程接口。
    • 简单来说:就是Java帮我们已经写好的一些方法,我们直接拿过来用就可以了。
  • Object类的作用:

    • Object类的方法是一切子类对象都可以直接使用的,所以我们要学习Object类的方法。
    • 一个类要么默认继承了Object类,要么间接继承了Object类,Object类是Java中的祖宗类
  • Object类的常用方法:
    Java进阶笔记-多态与内部类_第27张图片

  • Object的toString方法:
    在这里插入图片描述
    Java进阶笔记-多态与内部类_第28张图片

  • 问题引出

    • 开发中直接输出对象,默认输出对象的地址其实是毫无意义的
    • 开发中输出对象变量,更多的时候是希望看到对象的内容数据而不是对象的地址信息。
  • toString存在的意义

    • 父类toString()方法存在的意义就是为了被子类重写,以便返回对象的内容信息,而不是地址信息!!
      Java进阶笔记-多态与内部类_第29张图片
      Java进阶笔记-多态与内部类_第30张图片

3.1.2 equals方法

  • Object的equals方法:
    在这里插入图片描述
    Java进阶笔记-多态与内部类_第31张图片

  • 问题思考

    • 直接比较两个对象的地址是否相同完全可以用“==”替代equals。
  • equals存在的意义

    • 父类equals方法存在的意义就是为了被子类重写,以便子类自己来定制比较规则。【下面重写例子IDEA中可自动生成】
      Java进阶笔记-多态与内部类_第32张图片
      Java进阶笔记-多态与内部类_第33张图片

3.2 Objects

  • Objects概述

    • Objects类与Object还是继承关系,Objects类是从JDK 1.7开始之后才有的。
    • Objects是一个工具类,提供了一些方法去完成一些功能。
  • 官方在进行字符串比较时,没有用字符串对象的的equals方法,而是选择了Objects的equals方法来比较。

    @Override
    public boolean equals(Object o) {
        // 1、判断是否是同一个对象比较,如果是返回true。
        if (this == o) return true;
        // 2、如果o是null返回false  如果o不是学生类型返回false  ...Student !=  ..Pig
        if (o == null || this.getClass() != o.getClass()) return false;
        // 3、说明o一定是学生类型而且不为null
        Student student = (Student) o;
        return sex == student.sex && age == student.age && Objects.equals(name, student.name);
    }
    
  • 使用Objects的equals方法在进行对象的比较结果是一样的,但是会更安全。

    public class Test {
        public static void main(String[] args) {
            String s1 = "itheima";
            String s2 = new String("itheima");
            System.out.println(s1.equals(s2));   // true 
            // 尽管s2创建对象,但还是比较的是内容。String类提供的equals,拿的是object类的,但String类已经重写了。
    }
    

Java进阶笔记-多态与内部类_第34张图片
Java进阶笔记-多态与内部类_第35张图片

  • Objects的常见方法
    Java进阶笔记-多态与内部类_第36张图片
    Java进阶笔记-多态与内部类_第37张图片

  • 源码分析

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

Java进阶笔记-多态与内部类_第38张图片

3.3 StringBuilder

  • StringBuilder概述

    • StringBuilder是一个可变的字符串类,我们可以把它看成是一个对象容器
    • 作用:提高字符串的操作效率,如拼接、修改等。
  • StringBuilder 构造器
    Java进阶笔记-多态与内部类_第39张图片

  • StringBuilder常用方法
    Java进阶笔记-多态与内部类_第40张图片

    /**
        目标:学会使用StringBuilder操作字符串,最终还需要知道它性能好的原因
     */
    public class StringBuilderDemo1 {
        public static void main(String[] args) {
            StringBuilder sb = new StringBuilder(); // 相当于现在sb里面什么都没有,如:""
            sb.append("a"); // append用于拼接内容
            sb.append("b");
            sb.append("c");
            sb.append(1);
            sb.append(false);
            sb.append(3.3);
            sb.append("abc");
            System.out.println(sb); // 打印结果为:abc1false3.3abc
    
            StringBuilder sb1 = new StringBuilder();
            // 支持链式编程
            sb1.append("a").append("b").append("c").append("我爱你中国");
            System.out.println(sb1); // 打印结果为:abc我爱你中国
    
            // 反转
            sb1.reverse().append("110");
            System.out.println(sb1); // 打印结果为:国中你爱我cba110
    
            System.out.println(sb1.length()); // 取长度 打印结果为:11
    
            /**
            	注意:StringBuilder只是拼接字符串的手段:效率好。
            	最终的目的还是要恢复成String类型。
            */  
            StringBuilder sb2 = new StringBuilder();
            sb2.append("123").append("456");
            // check(sb2); //会发现不行,因为check要的是string类型,而s2是StringBuilder类型
            // 恢复成String类型
            String rs = sb2.toString();
            check(rs); // 打印结果为:123456
        }
    
        public static void check(String data){
            System.out.println(data);
        }
    }
    
  • String类拼接字符串原理图
    Java进阶笔记-多态与内部类_第41张图片

  • StringBuilder提高效率原理图
    Java进阶笔记-多态与内部类_第42张图片
    Java进阶笔记-多态与内部类_第43张图片

  • 案例——打印整型数组内容
    Java进阶笔记-多态与内部类_第44张图片

    public class StringBuilderTest2 {
        public static void main(String[] args) {
            int[] arr1 = null;
            System.out.println(toString(arr1)); // 打印结果为:null
    
            int[] arr2 = {10, 88, 99};
            System.out.println(toString(arr2)); // 打印结果为:[10,,88,99]
    
            int[] arr3 = {};
            System.out.println(toString(arr3));// 打印结果为:[]
        }
    
        /**
           1、定义方法接收任意整型数组,返回数组内容格式
         */
        public static String toString(int[] arr){
           if(arr != null){
                // 2、开始拼接内容。
               StringBuilder sb = new StringBuilder("[");
               for (int i = 0; i < arr.length; i++) {
                   sb.append(arr[i] ).append(i == arr.length - 1 ? "" : ", ");
               }
     // 下面不能用这个替换:sb.append(arr[i] ).append(i == arr.length - 1 ? "]" : ", ");
    		// 因为如传入的为int[] arr3 = {}; 打印结果为:[
               sb.append("]");
               return sb.toString();
           }else {
               return null;
           }
        }
    }
    

3.4 Math

  • Math类

    • 包含执行基本数字运算的方法,Math类没有提供公开的构造器

    • 如何使用类中的成员呢?

      • 看类的成员是否都是静态的,如果是,通过类名就可以直接调用
    • Math 类的常用方法
      Java进阶笔记-多态与内部类_第45张图片

      /**
          目标:Math类的使用。
          Math用于做数学运算。
          Math类中的方法全部是静态方法,直接用类名调用即可。
          方法:
                方法名                                          说明
                public static int abs(int a)                   获取参数a的绝对值:
                public static double ceil(double a)            向上取整
                public static double floor(double a)           向下取整
                public static double pow(double a, double b)   获取a的b次幂
                public static long round(double a)             四舍五入取整
          小结:
                记住。
       */
      public class MathDemo {
          public static void main(String[] args) {
              // 1.取绝对值:返回正数
              System.out.println(Math.abs(10)); // 10
              System.out.println(Math.abs(-10.3)); // 10.3
      
              // 2.向上取整: 5
              System.out.println(Math.ceil(4.00000001)); // 5.0
              System.out.println(Math.ceil(4.0)); // 4.0
              // 3.向下取整:4
              System.out.println(Math.floor(4.99999999)); // 4.0
              System.out.println(Math.floor(4.0)); // 4.0
      
              // 4.求指数次方
              System.out.println(Math.pow(2 , 3)); // 2^3 = 8.0
              // 5.四舍五入 10
              System.out.println(Math.round(4.49999)); // 4
              System.out.println(Math.round(4.500001)); // 5
      
              System.out.println(Math.random());  // 0.0 - 1.0 (包前不包后)
      
              // 拓展: 3 - 9 之间的随机数  (0 - 6) + 3
              //  [0 - 6] + 3
              int data =  (int)(Math.random() * 7) + 3;
              System.out.println(data);
      
          }
      }
      

3.5 System

  • System 类概述

    • System的功能是通用的,都是直接类名调用即可,所以System不能被实例化
    • System也是一个工具类,代表了当前系统,提供了一些与系统相关的方法。
  • System 类的常用方法
    Java进阶笔记-多态与内部类_第46张图片

  • 时间毫秒值

    • 计算机认为时间是有起点的,起始时间: 1970年1月1日 00:00:00
    • 时间毫秒值:指的是从1970年1月1日 00:00:00走到此刻的总的毫秒数,应该是很大的。 1s = 1000ms。
  • 原因:

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

      long time = System.currentTimeMillis();
      System.out.println(time);//1575465416955
      
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.Arrays;

/**
    目标:System系统类的使用。
    System代表当前系统。(虚拟机系统)
    静态方法:
        1.public static void exit(int status):终止JVM虚拟机,非0是异常终止。
        2.public static long currentTimeMillis():获取当前系统此刻时间毫秒值。(重点)
        3.可以做数组的拷贝。
             arraycopy(Object var0, int var1, Object var2, int var3, int var4);
             * 参数一:原数组
             * 参数二:从原数组的哪个位置开始赋值。
             * 参数三:目标数组
             * 参数四:赋值到目标数组的哪个位置
             * 参数五:赋值几个。
 */
public class SystemDemo {
    public static void main(String[] args) {
        System.out.println("程序开始。。。");

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

        // 2、计算机认为时间有起源:返回1970-1-1 00:00:00 走到此刻的总的毫秒值:时间毫秒值。
        long time = System.currentTimeMillis();
        System.out.println(time); 

 
        // 计算10万次循环在计算机中所花时间
        long startTime = System.currentTimeMillis();
       		// 进行时间的计算:性能分析
        for (int i = 0; i < 100000; i++) {
            System.out.println("输出:" + i);
        }
        long endTime = System.currentTimeMillis();
        System.out.println((endTime - startTime)/1000.0 + "s");


        // 3、做数组拷贝(了解)
        /**
         arraycopy(Object src,  int  srcPos,
         Object dest, int destPos,
         int length)
         	参数一:被拷贝的数组
         	参数二:从哪个索引位置开始拷贝
         	参数三:复制的目标数组
         	参数四:粘贴位置
         	参数五:拷贝元素的个数
         */
        int[] arr1 = {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(arr1, 3, arr2, 2, 3);
        System.out.println(Arrays.toString(arr2)); // 打印结果:[0, 0, 40, 50, 60, 0]

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

3.6 BigDecimal

  • BigDecimal作用

    • 用于解决浮点型运算精度失真的问题
      Java进阶笔记-多态与内部类_第47张图片
  • 使用步骤

    • 创建对象BigDecimal封装浮点型数据(最好的方式是调用方法
    public static BigDecimal valueOf(double val):   包装浮点数成为BigDecimal对象。
    
  • BigDecima常用API
    Java进阶笔记-多态与内部类_第48张图片

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.NumberFormat;

/**
    目标:BigDecimal大数据类。

    引入:
        浮点型运算的时候直接+  * / 可能会出现数据失真(精度问题)。
        BigDecimal可以解决浮点型运算数据失真的问题。

    BigDicimal类:
        包:java.math.
        创建对象的方式(最好的方式:)
              public static BigDecimal valueOf(double val) :包装浮点数成为大数据对象。
        方法声明
              public BigDecimal add(BigDecimal value)       加法运算
              public BigDecimal subtract(BigDecimal value)  减法运算 
              public BigDecimal multiply(BigDecimal value)  乘法运算 
              public BigDecimal divide(BigDecimal value)    除法运算
              public double doubleValue(): 把BigDecimal转换成double类型。
 */
public class BigDecimalDemo {
    public static void main(String[] args) {
        // 浮点型运算的时候直接+  * / 可能会出现数据失真(精度问题)。
        System.out.println(0.09 + 0.01);
        System.out.println(1.0 - 0.32);
        System.out.println(1.015 * 100);
        System.out.println(1.301 / 100);

        System.out.println("-------------------------");
        double a = 0.1;
        double b = 0.2;
        double c = a + b;
        System.out.println(c);
        System.out.println("--------------------------");
        
        // 包装浮点型数据成为大数据对象 BigDeciaml
        BigDecimal a1 = BigDecimal.valueOf(a);
        BigDecimal b1 = BigDecimal.valueOf(b);
        BigDecimal c1 = a1.add(b1); // +
        // BigDecimal c1 = a1.subtract(b1); // -
        // BigDecimal c1 = a1.multiply(b1); // *
        // BigDecimal c1 = a1.divide(b1);  // /
        System.out.println(c1); // 打印结果为:0.3

        // 用BigDecimal运算出来后还要转成double类型的
        	// 目的:double
        double rs = c1.doubleValue();
        System.out.println(rs); // 已转成double类型 打印结果为:0.3

        // 注意事项:BigDecimal是一定要精度运算的
        BigDecimal a11 = BigDecimal.valueOf(10.0);
        BigDecimal b11 = BigDecimal.valueOf(3.0);
        //BigDecimal c11 = a11.divide(b11);
        //System.out.println(c11); 用上面直接运算会崩,因为除不尽,直接报错!
        /**
           参数一:除数 参数二:保留小数位数  参数三:舍入模式
           HALF_UP 指四舍五入的意思
         */
        BigDecimal c11 = a11.divide(b11, 2, RoundingMode.HALF_UP); // 3.3333333333
        System.out.println(c11);  // 打印结果为:3.33

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

Java进阶笔记-多态与内部类_第49张图片
Java进阶笔记-多态与内部类_第50张图片

你可能感兴趣的:(#,Java,java,开发语言)