#Java-常用API-Math、System、Runtime、Object

1.API介绍

API (Application Programming Interface): 应用程序编程接口

简单理解:API就是别人已经写好的东西, 我们直接使用即可。

例如我们前面说过的Random

public static void main(String[] args) {
	Random r = new Random();
	int number = r.nextInt(100);
}

Java API: 指的就是JDK中提供的各种功能的Java类

这些类将底层的实现封装了起来,我们不需要关心这些类是如何实现的,只需要学习这些类如何使用即可。


2. Math类

Math 是一个帮助我们进行计算的工具类

私有化构造方法,并且其中的方法都是静态的,方便我们使用类名直接调用

2.1 Math中的方法

方法名说明
public static int abs(int a)获取参数绝对值
public static double ceil(double a)向上取整
public static double floor(double a)向下取整
public static int round (float a)四舍五入
public static int max(int a,int b)获取两个int值中的较大值
public static double pow(double a, double b)返回a的b次幂的值
public static double random()返回值为double的随机值, 范围[0.0,1.0)

示例:

  1. abs()
System.out.println(Math.abs(-12.3));
System.out.println(Math.abs(-12));
System.out.println(Math.abs(-2147483648));

这里我们需要注意的是:

  • abs的参数类型有int,double ,long , float
  • 此外int类型的数据范围是:-2147483648~2147483647,所以System.out.println(Math.abs(-2147483648));的返回值是它自己;因为正数中没有可以对应的数字
  1. ceil()
System.out.println(Math.ceil(12.3));
System.out.println(Math.ceil(13.0));

输出的结果都是13.0
向上取整

  1. floor()
 System.out.println(Math.floor(12.3));
 System.out.println(Math.floor(12));

输出的结果都是12.0
向下取整

  1. round()
 System.out.println(Math.round(12.3));
 System.out.println(Math.round(12.5));

输出的结果是1213
它的返回结果是int类型

  1. max()、min()
System.out.println(Math.max(12, 13));
System.out.println(Math.max(13.4, 15.9));

System.out.println(Math.min(12, 13));
System.out.println(Math.min(13.4, 15.9));
  1. pow()
 System.out.println(Math.pow(2, 3));
 //开平方
 System.out.println(Math.sqrt(4.0));
 //开立方
 System.out.println(Math.cbrt(8.0));

值得注意的是:Java提供了专门提供开平方和立方的方法sqrtcbrt

  1. random()
for (int i = 0; i < 10; i++) {
System.out.println(Math.floor(Math.random() * 100) +1);
//Math.random() [0.0 1.0)
//* 100         [0.0 100.0)
//floor         去掉了后面的小数
//+1            [0.q 100.0)|
}

需要我们注意的是random返回的值的范围是:[0.0 - 1.0)


2.2案例练习

a. 判断质数

判断一个范围内的数是否为一个质数

这是以前的代码:

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

这个代码当范围较大的时候时间效率很低:例如:997,去掉1和997,要循环995次
我们优化代码:

  • 一个质数的所有因子个数是偶数,并且小的和大的数两两成对
  • 所有小的因子都在原数的平方根左边(比平方根小)

优化:

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

b.字幂数(包含水仙花数)

自幂数:一个n位自然数 等于自身各个数位上数字的 n次幂 之和

举例1:三位数
举例2:四位数
1^3 +5^3 + 3^3 = 153
1^4+6^4 + 3^4 + 4^3 = 1634
介绍介绍
如果自幂数是一位数, 也叫做:独身数三位自幂数:水仙花数
四位自幂数: 四叶玫瑰数五位自幂数:五角星数
六位自幂数: 六合数七位自幂数:北斗七星数
八位自幂数: 八仙数九位自幂数:九九重阳数
十位自幂数:十全十美数
int count = 0;
//得到每一个三位数
for (int i = 100; i <= 999; 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(count);
}

3.System

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

我们先来了解一下计算机中的时间原点:1970.01.01-00:00:00
因为时差的原因在我们这里要延后8个小时:1970.01.01-08:00:00

同时我们要知道在计算机中时间一般按毫秒计算

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

3.1 方法

方法名说明
public static void exit(int status)终止当前运行的 Java 虚拟机
public static long currentTimeMillis()返回当前系统的时间毫秒值形式
public static void arraycopy(数据源数组,起始索引,目的地数组,起始索引,拷贝个数)数组拷贝

3.2 方法介绍

  1. exit()
    有两个形参:
    • 0 : 表示当前虚拟机正常停止
    • 非0 :表示当前虚拟机异常停止
System.exit(0);
System.out.println("不会执行打印语句");
  1. currentTimeMillis()
long t = System.currentTimeMillis();
System.out.println(t);

可以获取当前代码运行时距离时间原点的时间,当然我们也可以使用这个函数来获取一段程序运行的时间

 long statr = System.currentTimeMillis();
 int i;
 for (i = 0; i < 1000; i++) {
     i += i;
 }
 System.out.println(i);
 long end = System.currentTimeMillis();
 double time = end - statr;
 System.out.println(time);
  1. arraycopy()
    各个参数的含义:
  • 参数一:数据源,要拷贝的数据从哪个数组而来
  • 参数二:从数据源数组中的第几个索引开始拷贝
  • 参数三:目的地,我要把数据拷贝到哪个数组中
  • 参数四:拷贝到目的地数组的起始索引。
  • 参数五:拷贝的个数
//拷贝数组
int[] arr1 = {1,2,3,4,5,6,7,8,9,10};
int[] arr2 = new int[10];
//把arr1数组中的数据考贝到arr2中
System.arraycopy(arr1, srcPos: 0,arr2, destPos: 0, length: 5);
//验证
for (int i = 0; i < arr2.length; i++) {
	System.out.print(arr2[i] +" ");
}

输出的结果为:1,2,3,4,5,0,0,0,0,0

一些注意事项:

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

对于第3的例子:

Student s1 = new Student ( name: "zhangsan", age: 23);
Student s2 = new Student( name: "lisi", age: 24);
Student s3 = new Student( name: "wangwu", age: 25);

Student[] arr1 = {s1, s2, s3};
Person[] arr2 = new Person[3];
//把arr1中对象的地址值赋值给arr2中
System.arraycopy(arr1, srcPos: 0,arr2, destPos: 0, length:3);

//遍历数组arr2
for (int i = 0; i < arr2.length; i++) {
	Student stu = (Student) arr2[i];
	System.out.println(stu.getName() + ","+ stu.getAge());
}

当然子类类型的数组赋值给子类一定是可以的


4.Runtime

Runtime有些特殊,我们无法直接创建它的对象,需要使用一个方法来返回:

public static Runtime getRuntime()
返回当前系统的运行环境对象

下面时其他的方法:

方法名说明
public void exit(int status)停止虚拟机
public int availableProcessors()获得CPU的线程数
public long maxMemory ()JVM能从系统中获取总内存大小(单位byte)
public long totalMemory ()JVM已经从系统中获取总内存大小(单位byte)
public long freeMemory()JVM剩余内存大小(单位byte)
public Process exec(String command)运行cmd命令

代码示例:

public static void main(String[] args) {
    //创建对象并查看线程
    Runtime r = Runtime.getRuntime();
    System.out.println(r.availableProcessors());
    //可获取的总空间
    System.out.println(r.maxMemory() / 1024 / 1024);
    //可用空间
    System.out.println(r.totalMemory() /1024 / 1024);
    //可用空间剩余
    System.out.println(r.freeMemory() / 1024 / 1024);
    //执行cmd命令
    try {
        r.exec("shutdown");
    } catch (IOException e) {
        e.printStackTrace();
    }
    //停止虚拟机
    Runtime.getRuntime().exit(0);
    System.out.println("这个代码不会执行");
}

关于为什么Runtime类不允许外界创建多个对象,因为Runtime反应虚拟机的运行环境,但是运行环境时唯一的,只需要一个对象就够了


实际上在Runtime中创建的对象是用final修饰的,表示对象的地址值不能再被修改,所以不管在哪一个类中创建这个对象,返回的都是同一个对象


5. Object

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

特性:Object类中没有成员变量,没有有参构造

被所有子类继承的父类不可能有共性的成员变量,所以就不设置

a.方法

方法名说明
public String toString()返回对象的字符串表示形式
public boolean equals(Object obj)比较两个对象是否相等
protected Object clone(int a)对象克隆

b.用法示例

在此之前我先写一个Student类用作示例辅助:

public Student{
	private String name;
	private int age;
	
	public Student(){}
	pbulic Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	//getter和setter方法
}

1.toString()

//1.toString 返回对象的字符串表示形式
Object obj = new Object();
String str1 = obj.toString();
System.out.println(str1);//java.lang.Object@119d7047

Student stu = new Student();
String str2 = stu.toString();
System.out.println(str2);//com.itheima.a04objectdemo.Student@4eec7777

这里讲一下System.out.println()

  • System:类名
  • out:静态变量
  • System.out:获取打印的对象
  • println():方法
    • 参数:表示打印的内容
    • 核心逻辑:当我们打印一个对象的时候,底层会调用对象的toString方法,把对象变成字符串。然后再打印在控制台上,打印完毕换行处理。
System.out.println(stu);//com.itheima.a04objectdemo.Student@4eec7777
//思考:默认情况下,因为Objeqt类中的toString方法返回的是地址值
//所以,默认情况下,打印一个对象打印的就是地址值
//但是地址值对于我们是没什么意义的?

我们可以在要打印的类中重写toString方法

因为在打印的时候调用的是被打印的对象的toString方法(继承于Object类)

@Override
public String toString() {
	return name + ", " + age;
}//name 和 age 是类中的成员变量

2.equals()

Student s1 = new Student( name: "zhangsan", age: 23);
Student s2 = new Student ( name: "zhangsan", age: 23);

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

结论:

  1. 如果没有重写equals方法,那么默认使用object中的方法进行比较,比较的是地址值是否相等
  2. 一般来讲地址值对于我们意义不大, 所以我们会重写, 重写之后比较的就是对象内部的属性值了

重写:我们可以使用idea自带的重写程序
在这里插入图片描述
之后一直点击下一步即可,得到的重写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);
    }

一个大厂面试题:

String s = "abc";
StringBuilder sb = new StringBuilder("abc");

System.out.println(s.equals(sb));// false
//因为equals方法是被s调用的,而s是字符串
//所以equals要看String类中的
//字符串中的equals方法,先判断参数是否为字符串
//如果是字符串,再比较内部的属性
//但是如果参数不是字符串,直接返回false

System.out.println(sb.equals(s));// false
//因为equals方法是被sb调用的,而sb是StringBuilder
//所以这里的equals方法要看StringBuilder中的equals方法
//那么在StringBuilder当中,没有重写equals方法
//使用的是Object中的
//在Object当中默认是使用 == 号比较两个对象的地址值
//而这里的s和sb记录的地址值是不一样的,所以结果返回false

3.clone()
这个方法是protected修饰的,我们创建的对象要使用这个方法要在类中重写(或者说是super调用)
例如前面的Student类:

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
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

值得注意的是:我们需要实现Cloneable接口,但是这个接口中没有抽象方法。像这样的接口称为标记性接口。
例如:当类实现了Cloneable接口就表示当前类可以被克隆,没有实现的话当前类就不可以被克隆

实现克隆:

Student s = new Student("lsh", 18);
Student s1 = (Student) s.clone();
 System.out.println(s1.getAge());
 System.out.println(s1.getName());

同时clone()返回值是Object类型,所以需要强制转换


克隆分类

1.浅克隆

  • 不管对象内部的属性是基本数据类型还是引用数据类型,都完全拷贝过来

2.深克隆

  • 基本数据类型拷贝过来
  • 字符串复用
  • 引用数据类型会重新创建新

我们给出一个重写为深克隆的例子:(假设类中有一维数组)

@Override
protected Object clone() throws CloneNotSupportedException {
	//调用父类中的clone方法
	//相当于让Java帮我们克隆一个对象,并把克隆之后的对象返回出去。
	
	//先把被克隆对象中的数组获取出来
	int[] data = this.data;
	//创建新的数组
	int[] newData = new int[data.length];
	//拷贝数组中的数据
	for (int i = 0; i < data.length; i++) {
	newData[i] = data[i];
	
	//调用父类中的方法克隆对象
	User u = (User) super.clone();
	//因为父类中的克隆方法是浅克隆,替换克隆出来对象中的数组地址值
	u.data = newData;
	return u;
}


6.Objects

Objects是一个对象工具类,有以下的方法:

方法名说明
public static boolean equals(Object a, Object b)先做非空判断,比较两个对象
public static boolean isNull(Object obj)判断对象是否为null,为null返回true,反之
public static boolean nonNull(Object obj)判断对象是否为null,跟isNull的结果相反

a.方法说明


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

注意:

  1. 方法的底层会判断s1是否为nu11,如果为nu11,直接返回false
  2. 如果s1不为null, 那么就利用s1再次调用equals方法
  3. 此时s1Student类型,所以最终还是会调用Student中的equals方法。
    在这个类中如果没有重写, 比较地址值, 如果重写了,就比较属性值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值