java常用API

一、Math类

1.定义

① Math类是定义在java.lang包(java的核心包)下的, 所以不需要导包。

② Math类定义时采用final关键词修饰,表示该类是最终类,不能被继承。

③ Math是一个帮助我们进行数学计算的工具类(私有化构造方法,所有方法都是静态的)

2.属性

 3.常用方法

 方法全部用static修饰,是类方法,无需创建对象,直接使用 类名.方法名 调用方法

(1)abs方法
public static void main(String[] args) {
    //abs  获取绝对值
    System.out.println(Math.abs(88));//88
    System.out.println(Math.abs(-88));//88
        
    System.out.println(Math.abs(-2147483648));//-2147483648

    System.out.println(Math.absExact(-2147483648));//异常
}

 bug:

        以int类型为例,取值范围为-2147483648 ~ 2147483647

        如果没有正数与负数对应,那么传递负数结果有误

        -2147483648没有正数与之对应,所以abs结果就会产生bug

解决办法:

        采用Math中新的方法absExact(jdk15开始)

(2)ceil、floor和round方法 
//ceil  向上取整(进一法,朝数轴的正方向进一)
System.out.println(Math.ceil(12.34));//13.0
System.out.println(Math.ceil(-12.34));//-12.0

//floor  向下取整(去尾法,朝数轴的负方向进一)
System.out.println(Math.floor(12.34));//12.0
System.out.println(Math.floor(-12.34));//-13.0

//round  四舍五入
System.out.println(Math.round(12.34));//12
System.out.println(Math.round(-12.34));//-12
(3)max和min方法
//max  获取两个整数的较大值
System.out.println(Math.max(20, 30));//30

//min  获取两个整数的较小值
System.out.println(Math.min(20, 30));//20
(4)pow、sqrt和cbrt方法
//pow  获取a的b次幂
System.out.println(Math.pow(2, 3));//8
/* 细节:
    如果第二个参数是0~1之间的小数,操作就是开根号
    建议:第二个参数一般传递>=1的正整数
*/
System.out.println(Math.pow(4, 0.5));//2.0
System.out.println(Math.pow(2, -2));//0.25

//sqrt  开根号
System.out.println(Math.sqrt(4));//2.0

//cbrt  开立方
System.out.println(Math.cbrt(8));//2.0
(5)random方法
//random  获取随机数(不常用,前端采用该方式)
/* 获取1~100之间的随机数:
    Math.random()   [0.0,1.0)
    * 100           [0.0,100.0)
    Math.floor      [0,99]
    +1              [1,100]
*/
System.out.println(Math.floor(Math.random() * 100) + 1);

二、System类

1.定义

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

2.常用方法

(1)exit方法
//exit(状态码)  终止当前运行的java虚拟机
/* 状态码:
    0:表示当前虚拟机是正常停止
    非0(一般用1):表示当前虚拟机是正常停止
*/
System.exit(0);
(2)currentTimeMillis方法

时间原点:1970年1月1日00:00:00 --> C语言诞生时间

我国在东八区,有八小时时差,所以os中时间原点为1970年1月1日08:00:00

//currentTimeMillis  返回当前系统距离时间原点的时间毫秒值形式
System.out.println(System.currentTimeMillis());

 用途:可以获取程序运行的总时间

(3)arraycopy方法
//arraycopy  数组拷贝
//参数:arraycopy(源数组,源数组起始索引,目标数组,目标数组起始索引,拷贝个数)
int[] arr1={1,2,3,4,5,6,7,8,9,10};
int[] arr2=new int[10];
System.arraycopy(arr1,6,arr2,2,3);//0 0 7 8 9 0 0 0 0 0

注意事项:

①如果源数组和目标数组都是基本数据类型,那么两者的类型必须保持一致,否则报错

public class Demo {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        double[] arr2 = new double[10];
        System.arraycopy(arr1, 0, arr2, 0, 10);
    }
}

运行结果:

② 在拷贝的时候需要考虑数组的长度,超出范围也会报错

public class Demo2 {
    public static void main(String[] args) {
        int[] arr1 = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        int[] arr2 = new int[5];
        System.arraycopy(arr1, 0, arr2, 0, 10);
    }
}

运行结果:

③ 如果源数组和目标数组都是引用数据类型,则子类类型可以复制给父类类型

public class Demo {
    public static void main(String[] args) {
        Student s1 = new Student("zhangsan", 23);
        Student s2 = new Student("lisi", 24);
        Student s3 = new Student("wangwu", 25);

        Student[] arr1 = {s1, s2, s3};
        Person[] arr2 = new Student[3];
        //把arr1中对象的地址值赋值给arr2中
        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());
        }
    }
}

class Person {
    private String name;
    private int age;

    public Person() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

class Student extends Person {
    public Student() {
    }

    public Student(String name, int age) {
        super(name, age);
    }
}

三、Runtime类 

1.定义

Runtime表示当前虚拟机的运行环境

2.常用方法 

注意:方法并没有全被staitc修饰,因此Runtime并不是一个工具类。需要获取其对象,再调用其成员方法 。

(1)getRuntime方法

由于Runtime表示当前虚拟机的运行环境,所以只能有一个对象

通过源码可以看出,Runtime类私有化其构造方法,使得外界不能直接new其对象。

采用单例设计模式--饿汉式单例,确保外界只能有一个Runtime对象。

public class Demo {
    public static void main(String[] args) {
        //getRuntime  获取Runtime对象
        Runtime r1=Runtime.getRuntime();
        Runtime r2=Runtime.getRuntime();
        System.out.println(r1==r2);//true
    }
}
 (2)exit方法
//exit  停止虚拟机
Runtime.getRuntime().exit(0);

question:Runtime的exit方法和System的exit方法有何不同?

通过查看System类中的exit方法,可以发现,底层调用的其实就是Runtime的exit方法,所以两者本质上是一样的。 

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

(4)maxMemory、totalMemory和freeMemory方法
//maxMemory  JVM能从系统中获取的总内存大小(单位byte --> /1024 :kb --> /1024 :Mb)
System.out.println(Runtime.getRuntime().maxMemory() / 1024 / 1024);

//totalMemory  JVM已经从系统中获取的总内存大小(单位byte)
System.out.println(Runtime.getRuntime().totalMemory() / 1024 / 1024);

//freeMemory  JVM剩余内存大小(单位byte)
System.out.println(Runtime.getRuntime().freeMemory() / 1024 / 1024);
(5)exec方法

 shutdown : 关机(加上参数才能执行)

                -s : 默认在1分钟之后关机

                -s -t 指定秒数 : 指定关机时间

                -a : 取消关机操作

                -r : 关机并重启

//exec  运行cmd命令
Runtime.getRuntime().exec("shutdown -s -t 3600");//在3600s后关机

运行后桌面右下角会弹出: 

Runtime.getRuntime().exec("shutdown -a");//取消关机

运行后桌面右下角会弹出: 

四、Object类

1.定义

Object类是java中的顶级父类,所有的类都直接或间接的继承于Object类。

 2.方法

Object类中的方法可以被所有子类访问。

(1)Object类的构造方法

 在Object类中,没有成员变量,所以就没有带参的构造方法,只有一个空参构造。

 理解:

子类中的共性才会抽取到父类中,在java中,不可能有一个属性是所有类的共性,所以Object类中不可能有成员变量

question:针对于任意一个类的构造方法,在第一行都隐藏了一个 super(); 默认访问父类的无参构造,那为什么不能访问父类的带参构造呢?

原因:因为在顶级父类Object类中,只有无参构造方法。

 (2)Object类的成员方法

一共有11个,先研究其中3个最常用的方法

① tostring方法
public class Demo {
    public static void main(String[] args) {
        //toString  返回对象的字符表现形式(包名.类名 + @ + 地址值)
        Object obj=new Object();
        String str1=obj.toString();
        System.out.println(str1);//java.lang.Object@4eec7777

        Student stu=new Student();
        String str2=stu.toString();
        System.out.println(str2);//com.mihoyo.objectdemo.Student@41629346
    }
}

源码: 

question1:为什么不用toString方法直接打印对象和调用toString方法的结果一样?

public class Demo {
    public static void main(String[] args) {
        Student stu=new Student();
        String str2=stu.toString();
        System.out.println(str2);//com.mihoyo.objectdemo.Student@41629346

        System.out.println(stu);com.mihoyo.objectdemo.Student@41629346
    }
}

System是一个类,out是该类中的一个静态变量,所以可以用 类名.变量名 调用该静态变量

 out初始值为null,但后续会给它赋值。

简单理解为 System.out 可以获取打印的对象,再调用该对象的println方法,参数就是打印的内容。

 继续查看println方法的源码,可以发现,底层也同样调用了object类中的toString方法,将对象变成字符串。

question2:由上可知,在默认情况下,因为Object类中的toString方法返回的是地址值,所以打印一个对象,输出的就是地址值。但输出地址值并不是我们想要的,我们想要的应该是输出对象内部的属性值,如何实现?

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

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student{" + "name='" + name + ", age=" + age + '}';
    }
}

处理方案:重写父类Object类中的toString方法(见上)

结论:如果想要打印一个对象,想要看到其属性值,就重写toString方法。重写的方法中,把对象的属性值进行拼接。

② equals方法
public class Demo {
    public static void main(String[] args) {
        //equals  比较两个对象是否相等
        Student s1=new Student();
        Student s2=new Student();

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

question:为什么是false呢?

首先,因为是对象s1调用的equals方法,应该先去Student类中查找equals方法。

但Student类中我们并没有定义,就去其父类Object中找。

通过源码可以发现,Object类中的equals方法底层是用==来进行比较

而==比较的是地址值,因为两个对象都是new出来的,在堆中的地址必然不一样,故答案为false。

question: 由上可知,在默认情况下,因为Object类中的equals方法底层使用==,所以比较两个对象,比较的就是地址值。但比较地址值并不是我们想要的,我们想要的应该是比较对象内部的属性值,如何实现?

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

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student{" + "name='" + name + ", age=" + age + '}';
    }

    //重写之后的equals方法比较的就是对象内部的属性值了
    @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);
    }
}

处理方案:重写父类Object类中的equals方法(见上)

 结论:如果没有重回equals方法,默认使用Object类中的equals方法进行比较,比较的是对象的地址值。然而比较地址值意义并不大,使用需要重写,重写之后比较的就是对象内部的属性值了。

**************************************************************************************************************

Test:判断以下代码的结果

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

        System.out.println(s.equals(sb));
        System.out.println(sb.equals(s));
    }
}

运行结果:

分析:

s.equals(sb) :因为equals方法是对象s调用的,而s是String类,所以查看String类中的equals方法

由于sb是StringBuilder类型,不是String类型,所以return结果直接为false 

sb.equals(s) :因为equals方法是对象sb调用的,而s是StringBuilder类,所以查看StringBuilder类中的equals方法

通过查找发现, StringBuilder类中并没有重写equals方法。

那我们查看其父类AbstractStringBuilder中的equals方法。

通过查找发现,其直接父类AbstractStringBuilder中也没有重写equals方法。

而AbstractStringBuilder类默认继承于Object类,所以调用的事实上是Object类的equals方法,默认使用==比较两个对象的地址值。

由于对象s和对象sb的地址值不一样,所以结果为false。

③ clone方法 

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

通过查看源码可以发现,clone方法是被native修饰的,属于本地方法, 外界是不能够直接调用的。

简单地讲,一个Native Method就是一个java调用非java代码的接口。

在定义一个native method时,并不提供实现体(有些像定义一个java interface),因为其实现体是由非java语言在外面实现的。该方法被调用时,是告知jvm去调用非java代码编写的实现体。

jvm能否去调用这个实现体,是根据是否实现了Cloneable这个接口来进行判断。

虽然这个接口并没有什么方法,但是必须实现该标志接口。如果不实现将会在运行期间抛出:CloneNotSupportedException异常。

通过查看文档,可以发现Object类本身也没有实现Cloneable接口,所以也不能在其对象上直接第调用,否则抛出异常。

question:那clone方法究竟怎么才能使用呢? 

使用步骤:

Ⅰ.在需要调用clone方法的对象的类上,添加实现Cloneable接口

Ⅱ.重写clone方法,在自己的clone方法中调用父类的clone方法,将返回值类型强转成本类类型,将当前clone方法修饰符改成public

完整代码:

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

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student{" + "name='" + name + ", age=" + age + '}';
    }

    @Override
    public Student clone() throws CloneNotSupportedException {
        return (Student) super.clone();
    }
}

Ⅲ.在测试类中调用对象的clone方法(默认是浅克隆)

运行结果:

**************************************************************************************************************

浅克隆与深克隆

 User类:

import java.util.Arrays;

public class User implements Cloneable{
    private int id;
    private String username;
    private String password;
    private String path;//游戏图片
    private int[] data;//游戏进度

    public User() {
    }

    public User(int id, String username, String password, String path, int[] data) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.path = path;
        this.data = data;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public int[] getData() {
        return data;
    }

    public void setData(int[] data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "User{" + "id=" + id +
                ", username='" + username +
                ", password='" + password +
                ", path='" + path +
                ", data=" + Arrays.toString(data) +
                '}';
    }

    @Override
    public User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }
}

Ⅰ. 浅克隆:不管对象内部的属性是基本数据类型 还是引用数据类型,都完全拷贝过来(Object类默认是浅克隆)

public class CloneDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        //1.创建一个对象
        int[] data = {1, 2, 3, 4, 5};
        User u1 = new User(1, "zhangsan", "1234qwer", "animal1", data);

        //2.克隆对象,修改源对象的属性,查看克隆的对象是否发生变化
        User u2 = u1.clone();
        int[] arr = u1.getData();
        arr[0] = 100;

        //3.输出对象
        System.out.println(u1);
        System.out.println(u2);
    }
}

运行结果:

可以看出,由于u2是浅克隆产生的,和u1的data指向的地址一样,所以当u1的data发生变化,u2也会同步改变 

Ⅱ. 深克隆:基本数据类型拷贝过来,字符串复用,引用数据类型会重新创建新的

 虽然字符串也是引用数据类型,但是在对象的字符串类型属性的赋值中,不是通过new创建的,而是直接赋值的,因此就会去串池中找。

由于user1对象创建时,串池中创建了。user2对象再创建时,就会复用了。

字符串的创建方式icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/136662234如果需要深克隆,就需要重写clone方法或者使用第三方工具类

 完整代码:

import java.util.Arrays;

public class User implements Cloneable {
    private int id;
    private String username;
    private String password;
    private String path;//游戏图片
    private int[] data;//游戏进度

    public User() {
    }

    public User(int id, String username, String password, String path, int[] data) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.path = path;
        this.data = data;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getPath() {
        return path;
    }

    public void setPath(String path) {
        this.path = path;
    }

    public int[] getData() {
        return data;
    }

    public void setData(int[] data) {
        this.data = data;
    }

    @Override
    public String toString() {
        return "User{" + "id=" + id +
                ", username='" + username +
                ", password='" + password +
                ", path='" + path +
                ", data=" + Arrays.toString(data) +
                '}';
    }

    /*  浅克隆
    @Override
    public User clone() throws CloneNotSupportedException {
        return (User) super.clone();
    }*/

    //深克隆
    public User clone() throws CloneNotSupportedException {
        //1.先获取源对象的data数组
        int[] data = this.data;
        //2.创建新的数组,拷贝数据
        int[] newdata = new int[data.length];
        for (int i = 0; i < newdata.length; i++) {
            newdata[i] = data[i];
        }
        //3.调用父类中的方法克隆对象
        User u = (User) super.clone();
        //4.由于Object中的clone默认是浅克隆,需要替换克隆的data属性
        u.data = newdata;
        return u;
    }
}

此时运行相同的代码

public class CloneDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        //1.创建一个对象
        int[] data = {1, 2, 3, 4, 5};
        User u1 = new User(1, "zhangsan", "1234qwer", "animal1", data);

        //2.克隆对象,修改源对象的属性,查看克隆的对象是否发生变化
        User u2 = u1.clone();
        int[] arr = u1.getData();
        arr[0] = 100;

        //3.输出对象
        System.out.println(u1);
        System.out.println(u2);
    }
}

运行结果:

由于修改了重写的clone方法,使之成为深克隆。修改源对象u1的data属性,克隆后的u2对象的data属性并不会发生改变。

**************************************************************************************************************注:如果对象中存在多个引用数据类型,或者说存在的属性是二维数组,那么修改clone方法,就会涉及很多地址值,修改非常复杂,这时候就可以通过使用第三方工具类的方法

Ⅰ. 首先在本module下创建一个新的文件夹lib,引入jar包

Ⅱ. 右键jar包,点击Add as Library

Ⅲ. 编写代码

import com.google.gson.Gson;

public class CloneDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        //1.创建一个对象
        int[] data = {1, 2, 3, 4, 5};
        User u1 = new User(1, "zhangsan", "1234qwer", "animal1", data);

        //2.克隆对象,修改源对象的属性,查看克隆的对象是否发生变化
        Gson gson=new Gson();
        //2.1将User对象变成一个字符串
        String s=gson.toJson(u1);
        //2.2再把字符串变回User类型的对象
        User u2=gson.fromJson(s,User.class);

        int[] arr = u1.getData();
        arr[0] = 100;

        //3.输出对象
        System.out.println(u1);
        System.out.println(u2);
    }
}

运行结果:

从结果可以看出,只用了极少的代码,同样也实现了深克隆的功能。

五、Objects类

1.定义

Objects是一个对象工具类,提供了一些操作对象的方法。

 2.常用方法

(1)equals方法

student类:

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

    public Student() {
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

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

    @Override
    public String toString() {
        return "Student{" + "name='" + name + ", age=" + age + '}';
    }

    //重写之后的equals方法比较的就是对象内部的属性值了
    @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);
    }
}

以上是重写了Object类的equals之后的代码,原则上是没问题的。

当调用者为null时,结果会怎么样呢?

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

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

运行结果:

很明显,系统抛出了空指针异常,所以仅重写 Object类的equals方法是不够的,还需要进行非空判断。

如果自己写 if 判断是否为空,过于麻烦。

通过查看Objects的equals方法源码,可以发现

① 首先判断a和b的地址值是否一样, 相等返回true

② 再判断a是否为空, 为空返回false

③ 最后在调用equals方法判断对象a和b的值(没重写默认判断地址值,重写判断内部属性值)

import java.util.Objects;

public class EqualsDemo {
    public static void main(String[] args) {
        Student s1=null;
        Student s2=new Student();

        //Objects.equals  先做非空判断,再比较两个对象
        boolean result= Objects.equals(s1,s2);
        System.out.println(result);
    }
}

运行结果:

 

结论:通过调用Objects类的equals方法,就可以避免 if 判断调用者是否为空了

(2)isNull和nonNull方法

通过查看源码,可以发现,本质上就是判断一个对象是否为空,两个方法返回的值是相反的。

import java.util.Objects;

public class Demo {
    public static void main(String[] args) {
        Student s1=null;
        Student s2=new Student();

        //Objects.isNull  判断对象是否为空
        System.out.println(Objects.isNull(s1));//true
        System.out.println(Objects.isNull(s2));//false

        //Objects.nonNull  判断对象是否不为空
        System.out.println(Objects.nonNull(s1));//false
        System.out.println(Objects.nonNull(s2));//true
    }
}

结论:调用该两个方法可以直接进行判断,不用写 if 来判断对象是否为空 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值