【JAVA入门】Day18 - 常见API(Math、System、Runtime、Object、Objects)

【JAVA入门】Day18 - 常见API(Math、System、Runtime、Object、Objects)



        API 是 Java 帮我们写好的有各种功能的 Java 类,它们内部有很多使用的方法。

一、Math 类

        Math 类在 java.lang 中,直接继承 Object 类。其包含了基本数学运算的方法。
        Math 类是一个最终类,不能被继承:

public final class Math extends Object

        Math 中的方法全是静态方法(static),且私有化构造方法,不可创建对象,所以调用时直接用类名 Math 调用即可。
        常见的方法如下。
在这里插入图片描述

public class MathDemo1 {
    public static void main(String[] args) {
        //abs 获取参数绝对值
        System.out.println(Math.abs(88));       //88
        System.out.println(Math.abs(-88));      //88
        //ceil 获取向上取整
        System.out.println(Math.ceil(12.34));   //13.0
        System.out.println(Math.ceil(12.54));   //13.0
        System.out.println(Math.ceil(-12.34));   //-12.0
        System.out.println(Math.ceil(-12.54));   //-12.0
        //floor 获取向下取整
        System.out.println(Math.floor(12.34));   //12.0
        System.out.println(Math.floor(12.54));   //12.0
        System.out.println(Math.floor(-12.34));   //-13.0
        System.out.println(Math.floor(-12.54));   //-13.0
        //四舍五入
        System.out.println(Math.round(12.34));    //12
        System.out.println(Math.round(12.54));    //13
        System.out.println(Math.round(-12.34));     //-12
        System.out.println(Math.round(-12.54));     //-13
        //获取两个整数较大值
        System.out.println(Math.max(20, 30));   //30
        //获取两个整数较小值
        System.out.println(Math.min(20, 30));   //20
        //获取a的b次幂
        System.out.println(Math.pow(2, 3));     //8
        System.out.println(Math.pow(4, 0.5));   //2
        System.out.println(Math.pow(2, -2));    //0.25
        //开平方
        System.out.println(Math.sqrt(4));       //2.0
        //开立法
        System.out.println(Math.cbrt(8));       //2.0
        //随机数
        //获取一个[0.0, 1.0)的随机数
        for(int i = 0;i < 10; i++) {
            System.out.println(Math.random());
        }
        //获取[1.0, 100.0]的随机整数
        System.out.println(Math.floor(Math.random() * 100) + 1);
    }

【练习1】判断一个数是否为一个质数。

 public static boolean isPrime(int number) {
        for(int i = 0; i <= Math.sqrt(number); i++) {
            if(number % i == 0) {
                return false;
            }
        }
        return true;
    }

【练习2】判断一个数是不是自幂数。求100~999之间的所有自幂数。
※自幂数,一个 n 位自然数等于自身各个数位上数字的 n 次幂之和。

举例1:三位数 1^3 + 5^3 + 3^3 = 153
举例2:四位数 1^4 + 6^4 + 3^4 + 4^3 = 1634

如果自幂数是一位数,也叫做独身数;如果是三位数,也叫做水仙花数;如果是四位数,也叫做四叶玫瑰数

public class ShuiXianHua {
    public static void main(String[] args) {
        //水仙花数:100~999
        int count = 0;
        for(int i = 0; i < 1000; i++) {
            int ge = i % 10;
            int shi = i / 10 % 10;
            int bai = i / 100 % 10;
            //判断
            //每一位的三次方之和跟本身进行比较
            double sum = Math.pow(ge,3) + Math.pow(shi,3) + Math.pow(bai,3);
            if(sum == i){
                count++;
                System.out.println(i);
            }
        }
        System.out.println("100~999之间的水仙花数一共有" + count + "个。");
    }
}

二、System 类

        System 也是一个工具类,提供了一些与系统相关的方法。

2.1 计算机中的时间原点

        在计算机中,时间是有一个原点的,它表示最初的开始时间。
计算机中的时间原点是:

1970年1月1日 00:00:00

        在计算机中:

1秒 = 1000毫秒
1毫秒 = 1000微秒
1微秒 = 1000纳秒

        在计算机中,我们可以用这个方法返回当前系统的时间毫秒值形式。

public static long currentTimeMillis()

2.2 其他 System 中的常用方法

  • 终止当前运行的 Java 虚拟机。
public static void exit(int status)
  • 数组拷贝
public static void arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数);

【练习】使用以上三个方法。

public class SystemTest {
    public static void main(String[] args) {
        //方法的形参:
        //状态码:
        //0:表示当前虚拟机是正常停止
        //非0:表示当前虚拟机是异常停止
        //System.exit(0);

        long l = System.currentTimeMillis();
        System.out.println(l);

        //public static void arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数);
        int[] a1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int[] a2 = new int[10];
        System.arraycopy(a1, 0, a2, 0, 5);
        //1 2 3 4 5 0 0 0 0 0 
        for(int i = 0; i < a2.length; i++) {
            System.out.print(a2[i] + " ");
        }
    }
}

        注意:
        1.如果数据源数组和目的地数组都是基本数据类型,那么两者的数据类型必须保持一致,否则会报错。
        2.在拷贝的时候需要考虑数组的长度,如果超出范围也会报错。
        3.如果数据源数组和目的地数组都是引用数据类型,那么子类类型可以赋值给父类类型(多态)。

public class Test2 {
    public static void main(String[] args) {
        Student s1 = new Student(23, "zhangsan");
        Student s2 = new Student(24, "lisi");
        Student s3 = new Student(25, "wangwu");
        Student[] arr1 = {s1, s2, s3};
        Person[] arr2 = new Person[3];
        //子类数组拷贝给父类数组,实现多态
        System.arraycopy(arr1, 0, arr2, 0, 3);

        //遍历arr2
        for(int i = 0; i < arr2.length; i++) {
            //在使用时,需要使用强转把数组转回子类
            Student stu = (Student) arr2[i];
            System.out.println(stu.getName() + ", " + stu.getAge());
        }
    }
}

三、Runtime 类

        Runtime 表示当前虚拟机的运行环境。
        常见方法有这些:

  • 获取系统的运行环境对象
 public static Runtime getRuntime()
  • 停止虚拟机(System 类中调用的 exit 方法就是这个方法)
public void exit(int status)
  • 获得CPU的线程数
public int availableProcessors()
  • JVM能从系统中获取总内存的大小(单位 byte)
public long maxMemory()
  • JVM已经从系统中获取总内存大小(单位 byte)
public long totalMemory()
  • JVM剩余内存大小(单位 byte)
public long freeMemory()
  • 运行 cmd 命令
public Process exec(String command)

【练习】使用 Runtime 类。

package RuntimeTest;

import java.io.IOException;

public class RuntimeDemo1 {
    public static void main(String[] args) throws IOException {
        //1.获取Runtime对象
        //Runtime是私有化构造方法,需要调用它自己的getRuntime()方法来获取对象
        //这是为了保证系统运行中永远只有一个Runtime对象
        Runtime r = Runtime.getRuntime();
        System.out.println(r);

        //2.exit 停止虚拟机
        //Runtime.getRuntime().exit(0);

        //3.获得CPU线程数
        System.out.println(Runtime.getRuntime().availableProcessors());

        //4.总内存大小,单位byte,/1024是KB,再/1024是MB
        System.out.println(Runtime.getRuntime().maxMemory() / 1024 / 1024);

        //5.已经获取的总内存大小
        System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);

        //6.剩余内存大小
        System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024);

        //7.运行cmd命令
        Runtime.getRuntime().exec("notepad");
    }
}

四、Object

        Object 是 Java 中的顶级父类。所有的类都直接或间接的继承于 Object 类。
        Object 类中的方法可以被所有子类访问。

  • 空参构造
public Object()
  • 返回对象的字符串表示形式
public String toString()
  • 比较两个对象是否相等
public boolean equals(Object obj)
  • 对象克隆
protected Object clone(int a)

【练习】使用这几个方法。

package ObjectTest;

public class ObjectDemo1 {
    public static void main(String[] args) {
        //1.toString
        Object obj = new Object();
        String str1 = obj.toString();
        System.out.println(str1);               //java.lang.Object@4c873330  //包名+ @ +地址值

        Student stu = new Student();
        String str2 = stu.toString();           //Student也继承于Object,可以直接调用其的toString()方法
        System.out.println(str2);               //ObjectTest.Student@776ec8df

        //当我们直接打印一个对象的时候,底层会调用对象的toString()方法,把对象变成字符串,然后再打印在控制台上,打印完毕后换行处理
        //所以,默认情况下,打印一个对象打印的就是地址值
        //要想获取对象内部的属性值,可以用get方法
        //System.out.println(stu.getName() + " " + stu.getAge());
        //要想使代码更简洁,我们可以在Student类中重写toString()方法
        System.out.println(stu);                //ObjectTest.Student@776ec8df
    }
}
package ObjectTest;

public class Student {
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Student() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return name + " " + age;
    }
}

        通过在 Student 类中重写继承自 Object 类的 toString() 方法,我们可以让 System.out.println() 语句直接输出对象的属性值。
        一样的道理,equals() 方法比较的是两个对象的地址值,我们可以通过重写,让它实现比较对象的属性值。

package ObjectTest;

public class ObjectDemo2 {
    public static void main(String[] args) {
        //比较两个对象(地址值)是否相等
        Student s1 = new Student();
        Student s2 = new Student();

        boolean result1 = s1.equals(s2);        //false
        System.out.println(result1);

        Student s3 = s2;
        boolean result2 = s2.equals(s3);        //true
        System.out.println(result2);
    }
}
package ObjectTest;

import java.util.Objects;

public class Student {
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Student() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return name + " " + age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }
    
}

        我们常用的 String 类,也重写了 equals 方法,它的逻辑是这样的:

package ObjectTest;

public class ObjectDemo3 {
    public static void main(String[] args) {
        String s = "abc";
        StringBuilder sb = new StringBuilder("abc");

		//字符串中的equals方法,先判断参数是否为字符串,不是直接返回 false
        //如果参数是字符串,再比较字符串的内容
        //因为传递的参数是一个StringBuilder对象而非字符串,所以直接返回 false
        System.out.println(s.equals(sb));    //false


        //StringBuilder中根本没有重写equals方法
        //所以StringBuilder中的equals还是Object的原生equals方法,它比较的是对象的地址值
        //因为sb和s是两个不同对象,所以返回false
        System.out.println(sb.equals(s));    //false
    }
}

        对象克隆,即把 A 对象的属性值完全拷贝给 B 对象,也叫对象拷贝,对象复制。

package ObjectTest;

public class Student implements Cloneable {
    //Cloneable
    //如果一个接口里没有抽象方法
    //表示当前接口是一个标记性接口
    //现在用Student实现Cloneable,表示该接口已经被实现,那么当前类的对象就可以被克隆
    //如果没有实现,当前类的对象就不能被克隆(类似flag标记)
    private int age;
    private String name;

    public Student(int age, String name) {
        this.age = age;
        this.name = name;
    }

    public Student() {
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return name + " " + age;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //调用父类中的clone方法
        //相当于让Java帮我们克隆一个对象,并把克隆之后的对象返回出去
        return super.clone();
    }
}
package ObjectTest;

public class ObjectDemo4 {
    public static void main(String[] args) throws CloneNotSupportedException {
        //protected Object clone(int a)
        //因为clone()是一个protected修饰的方法,不能直接用其他对象调用(除非在lang包下创建这个对象)
        //因此要在Student类中先重写clone()方法才可以调用
        //然后我们需要让Student类实现一个额外接口Cloneable
        Student stu1 = new Student();
        stu1.setAge(25);
        stu1.setName("王五");

        //2.克隆对象
        //注意clone()方法返回的是Object类,需要强转才能变成Student类
        Student stu2 = (Student) stu1.clone();

        System.out.println(stu1);
        System.out.println(stu2);
    }
}

        注意:克隆对象的时候有以下书写细节!

1.首先在要克隆的Javabean类内部先重写Object中的clone方法。
2.让这个Javabean类实现Cloneable接口。
3.抛出CloneNotSupportedException异常。
4.创建原对象并调用clone,注意克隆完的对象是Object,要进行强转。

        在Java中,存在两种克隆方式,一种叫浅克隆,一种叫深克隆

  • 所谓浅克隆:不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来,记录其值。
  • 所谓深克隆:基本数据类型直接拷贝过来,字符串直接复用串池,引用数据类型则会重新创建新的,并记录其地址值。

        Object 中的 clone() ,它是浅克隆。

        验证:我们可以用 Object 克隆一个含数组的对象,然后修改数组的元素,看看克隆后的对象数组元素是否跟着改变了(如果跟着改变,则说明是浅克隆,两个对象中的数组共用了一个地址值)。

package ObjectTest;

import java.util.Arrays;

public class BeCloned implements Cloneable {
    int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int number = 1;

    @Override
    public String toString() {
        return "BeCloned{" +
                "data=" + Arrays.toString(data) +
                ", number=" + number +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
public class ObjectDemo5 {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建bc1,克隆得到bc2
        BeCloned bc1 = new BeCloned();
        BeCloned bc2 = (BeCloned)bc1.clone();

        //修改bc2的数组值
        bc2.data[0] = 100;

        //bc1的值也发生了改变
        System.out.println(bc1);
        System.out.println(bc2);
    }
}

在这里插入图片描述
        我们可以用重写的方法把 clone() 改写为一个深克隆。

package ObjectTest;

import java.util.Arrays;

public class BeCloned implements Cloneable {
    int[] data = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int number = 1;

    @Override
    public String toString() {
        return "BeCloned{" +
                "data=" + Arrays.toString(data) +
                ", number=" + number +
                '}';
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        //先把被克隆对象中的数组获取出来
        int[] data = this.data;
        //创建新数组
        int[] newData = new int[data.length];
        //拷贝数据
        for(int i = 0; i < newData.length; i++) {
            newData[i] = data[i];
        }
        //先调用Object的clone方法进行浅克隆
        BeCloned bc = (BeCloned) super.clone();
        //再自己手动将新数组赋给bc,替换克隆出来对象中的数组地址值,完成深克隆
        bc.data = newData;
        return bc;
    }
}
public class ObjectDemo5 {
    public static void main(String[] args) throws CloneNotSupportedException {
        //创建bc1,克隆得到bc2
        BeCloned bc1 = new BeCloned();
        BeCloned bc2 = (BeCloned)bc1.clone();

        //修改bc2的数组值
        bc2.data[0] = 100;

        //bc1的值没有发生改变,完成深克隆
        System.out.println(bc1);
        System.out.println(bc2);
    }
}

在这里插入图片描述
        如果以后想要让 clone() 进行的是深克隆,我们可以使用第三方工具(jar包)。

扩展:使用第三方Jar包完成深克隆

        我们下载的第三方 jar 包一般都放到 lib 文件夹下。
在这里插入图片描述
        之后 Add as Library,就可以使用其他人编写的代码了。

package ObjectTest;

import com.google.gson.Gson;

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

        //创建一个对象
        BeCloned bc1 = new BeCloned();
        //通过Gson克隆对象
        Gson gson = new Gson();
        //把对象变为一个字符串
        String s = gson.toJson(bc1);
        System.out.println(s);              //{"data":[1,2,3,4,5,6,7,8,9,10],"number":1}
        //再把字符串变回对象就可以了
        BeCloned bc2 = gson.fromJson(s, BeCloned.class);

        //验证:实现了深克隆
        bc2.data[0] = 100;

        System.out.println(bc1);            //BeCloned{data=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10], number=1}
        System.out.println(bc2);            //BeCloned{data=[100, 2, 3, 4, 5, 6, 7, 8, 9, 10], number=1}
    }
}

五、Objects

        Objects 也是 Java 的一个常用工具类。其内部有几个常用方法。

public static boolean equals(Object a, Object b)                                 先做非空判断,再比较两个对象。
public static boolean isNull(Object obj)                                               判断对象是否为null,是返回true,反之返回false。
public static boolean nonNull(Object obj)                                            还是判断,但是结果和isNull相反。

        Objects.equals() 的运行逻辑:1.方法先判断s1是不是null,如果是null,直接返回 false。2.如果s1不是null,就利用s1再次调用equals()方法。

package ObjectsTest;

import java.util.Objects;

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

        Student s1 = null;
        Student s2 = new Student(21, "张三");

        boolean result = Objects.equals(s1, s2);
        System.out.println(result);
    }
}

        isNull() 和 nonNull() 的结果是相反的,就是用来判断当前对象是否为空的。

Student s3 = new Student();
System.out.println(Objects.isNull(s3));         //false
System.out.println(Objects.nonNull(s3));        //true
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值