API

101 阅读13分钟

9.2 和数学相关API

9.2.1 java.lang.Math类

1、java.lang.Math类
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
Math类是final修饰的,不能被继承,构造器private,不能在外面直接创建对象。
全部都是静态方法,静态常量。
(1double Math.random():产生[0,1)范围的double值
(2double Math.sqrt(double x):求平方根
(3double Math.PI:常量,圆周率
(4)xx Math.abs(xx):求xx的绝对值,支持多种数据类型
(5double Math.ceil(xx):向上取整
(6double Math.floor(xx):向下取整
(7long Math.round(xx):四舍五入取整
(8)xx Math.max(xx x, xx y):取最大值,支持多种数据类型
(9)xx Math.min(xx x, xx y):取最小值,支持多种数据类型
(10double Math.pow(double a, double b)
import org.junit.Test;
​
public class TestMath {
    @Test
    public void test1(){
        System.out.println(Math.ceil(2.1));//3.0
        System.out.println(Math.floor(2.1));//2.0
        System.out.println(Math.round(2.1));//2
    }
​
    @Test
    public void test2(){
        System.out.println(Math.ceil(2.7));//3.0
        System.out.println(Math.floor(2.7));//2.0
        System.out.println(Math.round(2.7));//3
    }
​
    @Test
    public void test3(){
        System.out.println(Math.pow(2,10));//2的10次方    1024.0   10月24日
    }
}
​

9.2.2 java.math包

2、java.math包下BigInteger和BigDecimal
BigInteger:任意精度的整数,任意大小的整数
BigDecimal:任意精度的小数
​
- BigInteger add(BigInteger val)
- BigInteger subtract(BigInteger val)
- BigInteger multiply(BigInteger val)
- BigInteger divide(BigInteger val)
- BigInteger remainder(BigInteger val)
​
- BigDecimal add(BigDecimal val)
- BigDecimal subtract(BigDecimal val)
- BigDecimal multiply(BigDecimal val)
- BigDecimal divide(BigDecimal val)
- BigDecimal divide(BigDecimal divisor, int roundingMode)
- BigDecimal divide(BigDecimal divisor, int scale, RoundingMode roundingMode)
- BigDecimal remainder(BigDecimal val)
import org.junit.Test;
​
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
​
public class TestBigIntegerAndDecimal {
    @Test
    public void test1(){
        /*
        需求:求两个整数的和、差、乘积...
        89782782892475211851452851851144524785155455548652441297827828924752118514528518511445247851554555486
        52441297827828924752118514528518511445247851554555486
​
         */
//        long num1 = 897827828924752118514528518511445247851554555486L;//也不行
        BigInteger a = new BigInteger("89782782892475211851452851851144524785155455548652441297827828924752118514528518511445247851554555486");
        BigInteger b = new BigInteger("52441297827828924752118514528518511445247851554555486");
​
        //System.out.println("和:" + (a+b));//报错,因为除了基本数据类型的数值类型能够使用+,字符串使用+
                                            //其余类型不支持+
        System.out.println("和:" + a.add(b));
        System.out.println("差:" + a.subtract(b));
        System.out.println("乘积:" + a.multiply(b));
        System.out.println("商:" + a.divide(b));
        System.out.println("余:" + a.remainder(b));
    }
​
    @Test
    public void test2(){
        /*
        需求:求两个小数的和、差、乘积...
        8978278289247521185145285185114452478515.5455548652441297827828924752118514528518511445247851554555486
        52441297827828924752118.514528518511445247851554555486
​
         */
//        long num1 = 897827828924752118514528518511445247851554555486L;//也不行
        BigDecimal a = new BigDecimal("8978278289247521185145285185114452478515.5455548652441297827828924752118514528518511445247851554555486");
        BigDecimal b = new BigDecimal("52441297827828924752118.514528518511445247851554555486");
​
        //其余类型不支持+
        System.out.println("和:" + a.add(b));
        System.out.println("差:" + a.subtract(b));
        System.out.println("乘积:" + a.multiply(b));
//        System.out.println("商:" + a.divide(b));//如果除不尽,这个方法会报错
        System.out.println("商:" + a.divide(b,102, RoundingMode.CEILING));//如果除不尽,这个方法会报错
        System.out.println("商:" + a.divide(b,100, RoundingMode.CEILING));//如果除不尽,这个方法会报错
        System.out.println("余:" + a.remainder(b));
    }
}
​

9.2.3 java.util.Random类

3、java.util.Random类
Random():种子是系统时间
Random(int seed):种子是固定的,根据同一个种子,产生的结果是相同的
​
int nextInt():产生int范围的任意整数
int nextInt(int bounds):产生[0,bounds)范围的任意整数
double nextDouble()
boolean nextBoolean()
...

​
import org.junit.Test;
​
import java.util.Random;
​
public class TestRandom {
    @Test
    public void test1(){
        Random random = new Random();
        System.out.println(random.nextInt());
        System.out.println(random.nextDouble());
        System.out.println(random.nextBoolean());
    }
​
    @Test
    public void test2(){
        Random random = new Random();
        System.out.println(random.nextInt());
        System.out.println(random.nextInt(100));
    }
​
    @Test
    public void test3(){
        Random random = new Random(888);
        System.out.println(random.nextInt());
        System.out.println(random.nextDouble());
        System.out.println(random.nextBoolean());
    }
}
​

9.2.4 java.text.NumberFormat

​
4、java.text.NumberFormat:数字格式化(了解)
NumberFormat.getNumberInstance(国家和地区的语言环境);
NumberFormat.getCurrencyInstance(国家和地区的语言环境);
NumberFormat.getPercentInstance(国家和地区的语言环境);
​
5、java.util.Locale:国家和地区的语言环境

​
import java.text.NumberFormat;
import java.util.Locale;
​
public class TestNumberFormat {
    public static void main(String[] args) {
        double num = 1234.567878951;
        Locale[] locales = {Locale.CHINA, Locale.US, Locale.FRANCE};
        for(int i=0; i<locales.length; i++) {
            System.out.println("国家与地区:" + locales[i]);
            NumberFormat numberFormat = NumberFormat.getNumberInstance(locales[i]);
            System.out.println("数字格式:" + numberFormat.format(num));
​
            NumberFormat currencyNumber = NumberFormat.getCurrencyInstance(locales[i]);
            System.out.println("货币格式:" + currencyNumber.format(num));
​
            NumberFormat percentFormat = NumberFormat.getPercentInstance(locales[i]);
            System.out.println("百分比格式:" + percentFormat.format(num));
        }
    }
}

9.3 日期时间API

9.3.1 第一代

在Java的核心类库中提供了3代不同的API,用于表示日期和时间。
第一代:java.util.Date类为代表
      java.text.SimpleDateFormat类:用于对Date对象进行格式化
    
    new  Date():当前系统时间

SimpleDateFormat用于日期时间的格式化。

  • public final String format(Date date)将一个 Date 格式化为日期/时间字符串。
  • public Date parse(String source)throws ParseException从给定字符串的开始解析文本,以生成一个日期。
import org.junit.Test;
​
import java.text.SimpleDateFormat;
import java.util.Date;
​
public class TestDate {
    @Test
    public void test1(){
        Date now = new Date();
        System.out.println(now);
        //Mon Mar 27 10:17:06 CST 2023
    }
​
    @Test
    public void test2(){
        Date now = new Date();
        SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss SSS毫秒 E,是这一年的第D天");
        String str = sf.format(now);
        System.out.println(str);
    }
​
    @Test
    public void test3(){
        Date today = new Date(2023,3,27);
        SimpleDateFormat sf = new SimpleDateFormat("yyyy年MM月dd日是这一年的第D天");
        String str = sf.format(today);
        System.out.println(str);
    }
​
}

9.3.2 第二代

第二代:java.util.Calender类为代表
     java.util.Locale:国家和地区的语言环境
     java.util.TimeZone:时区
​
    Calendar是一个抽象类,要么new它的子类GregorianCalendar的对象,要么调用Calendar的静态方法getInstance方法获取他子类的对象。
    Calendar 类是一个抽象类,它为特定瞬间与一组诸如  YEARMONTH、DAY_OF_MONTH、HOUR  等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 197011 日的 00:00:00.000,格里高利历)的偏移量。与其他语言环境敏感类一样,Calendar 提供了一个类方法  getInstance,以获得此类型的一个通用的对象。
    修改和获取 YEARMONTH、DAY_OF_MONTH、HOUR  等 日历字段对应的时间值。
        
    TimeZone通常,使用 getDefault 获取 TimeZone,getDefault  基于程序运行所在的时区创建 TimeZone。也可以用 getTimeZone 及时区 ID 获取 TimeZone 。例如美国太平洋时区的时区 ID 是  "America/Los_Angeles"。
    Asia/Shanghai
    UTC
    America/New_York
    America/Los_Angeles
​
    Locale 对象表示了特定的地理、政治和文化地区。需要 Locale  来执行其任务的操作称为语言环境敏感的 操作,它使用 Locale 为用户量身定制信息。
    语言参数是一个有效的 ISO 语言代码。这些代码是由 ISO-639 定义的小写两字母代码。
    国家/地区参数是一个有效的 ISO 国家/地区代码。这些代码是由 ISO-3166 定义的大写两字母代码。
    Locale 类提供了一些方便的常量,可用这些常量为常用的语言环境创建 Locale 对象。

​
import org.junit.Test;
​
import java.util.Calendar;
import java.util.TimeZone;
​
public class TestCalender {
    @Test
    public void test1(){
        Calendar c = Calendar.getInstance();//获取平台默认的语言环境和时区
        System.out.println(c);
​
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH)+1;
        int day = c.get(Calendar.DATE);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);
​
        System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
    }
​
    @Test
    public void test2(){
        TimeZone t = TimeZone.getTimeZone("America/Los_Angeles");
        Calendar c = Calendar.getInstance(t);//获取平台默认的语言环境和时区
​
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH)+1;
        int day = c.get(Calendar.DATE);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);
​
        System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
    }
​
    @Test
    public void test3(){
        Calendar c = Calendar.getInstance();
        int year = c.get(Calendar.YEAR);
        int month = c.get(Calendar.MONTH)+1;
        int day = c.get(Calendar.DATE);
        int hour = c.get(Calendar.HOUR_OF_DAY);
        int minute = c.get(Calendar.MINUTE);
        int second = c.get(Calendar.SECOND);
​
        System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
​
        c.set(Calendar.DATE, 25);
        year = c.get(Calendar.YEAR);
        month = c.get(Calendar.MONTH)+1;
        day = c.get(Calendar.DATE);
         hour = c.get(Calendar.HOUR_OF_DAY);
        minute = c.get(Calendar.MINUTE);
         second = c.get(Calendar.SECOND);
​
        System.out.println(year + "-" + month + "-" + day + " " + hour + ":" + minute + ":" + second);
    }
}
​

9.3.3 第三代

1、本地日期时间

第三代:Java8引入的
    java.time包
​
    LocalDate,LocalDateTime,LocalTime(非常重要)
​
    闰年的判断:
    源码: ((prolepticYear & 3) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0)
    我们: ((prolepticYear % 4) == 0) && ((prolepticYear % 100) != 0 || (prolepticYear % 400) == 0)
​
        prolepticYear的二进制:  xxxxxxxx xxxxxxxx xxxxxxxx xxxxxxxx
                           300000000 00000000 00000000 00000011
                           &----------------------------------------
                               00000000 00000000 00000000 00000000  ==》 0
                               00000000 00000000 00000000 00000001
                               00000000 00000000 00000000 00000010
                               00000000 00000000 00000000 00000011
​
        如果   (prolepticYear & 3) == 0),要求   prolepticYear的二进制的最后两位是00,它们一定是4的整数倍
序号方法描述
1now() / now(ZoneId zone)静态方法,根据当前时间创建对象/指定时区的对象
2of()静态方法,根据指定日期/时间创建对象
3getDayOfMonth()/getDayOfYear()获得月份天数(1-31) /获得年份天数(1-366)
4getDayOfWeek()获得星期几(返回一个 DayOfWeek 枚举值)
5getMonth()获得月份, 返回一个 Month 枚举值
6getMonthValue() / getYear()获得月份(1-12) /获得年份
7getHours()/getMinute()/getSecond()获得当前对象对应的小时、分钟、秒
8withDayOfMonth()/withDayOfYear()/withMonth()/withYear()将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象
9with(TemporalAdjuster t)将当前日期时间设置为校对器指定的日期时间
10plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours()向当前对象添加几天、几周、几个月、几年、几小时
11minusMonths() / minusWeeks()/minusDays()/minusYears()/minusHours()从当前对象减去几月、几周、几天、几年、几小时
12plus(TemporalAmount t)/minus(TemporalAmount t)添加或减少一个 Duration 或 Period
13isBefore()/isAfter()比较两个 LocalDate
14isLeapYear()判断是否是闰年(在LocalDate类中声明)
15format(DateTimeFormatter t)格式化本地日期、时间,返回一个字符串
16parse(Charsequence text)将指定格式的字符串解析为日期、时间
import org.junit.Test;
​
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
​
public class TestLocalDateTime {
    @Test
    public void test1(){
        LocalDate birthday = LocalDate.of(1997,7,1);
        System.out.println("birthday = " + birthday);
    }
    @Test
    public void test2(){
        LocalTime ke = LocalTime.of(8,25,0);
        System.out.println(ke);
    }
​
    @Test
    public void test3(){
        LocalDateTime dt = LocalDateTime.of(2023,3,27,10,39,56);
        System.out.println(dt);
    }
​
    @Test
    public void test4(){
        LocalDate today = LocalDate.now();
        LocalTime now = LocalTime.now();
        LocalDateTime time = LocalDateTime.now();
​
        System.out.println(today);
        System.out.println(now);
        System.out.println(time);
    }
​
    @Test
    public void test5(){
        LocalDate kai = LocalDate.of(2023,3,8);
        LocalDate bi = kai.plusDays(180);
        System.out.println(kai);
        System.out.println(bi);
    }
​
    @Test
    public void test6(){
        LocalDate kai = LocalDate.of(2023,3,8);
​
        System.out.println("年:" + kai.getYear());
        System.out.println("月:" + kai.getMonth());
        System.out.println("月:" + kai.getMonth().getValue());
        System.out.println("日:" + kai.getDayOfMonth());//日期
        System.out.println("星期:" + kai.getDayOfWeek());//WEDNESDAY 星期
        System.out.println("一年中的第几天:" + kai.getDayOfYear());//一年中的第几天
​
    }
​
    @Test
    public void test7(){
        LocalDate kai = LocalDate.of(2023,3,8);
        System.out.println(kai.isLeapYear());
    }
​
    @Test
    public void test8(){
        LocalDate kai = LocalDate.of(2000,3,8);
        System.out.println(kai.isLeapYear());
    }
}
​

2、其他国家和地区的日期时间

    也支持其他国家和时区的日期时间。ZondId和ZonedDateTime。
    本初子午线的日期时间:Instant
package com.atguigu.datetime;
​
import org.junit.Test;
​
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Set;
​
public class TestZoneDateTime {
    @Test
    public void test1(){
        ZonedDateTime current = ZonedDateTime.now();
        System.out.println(current);
        //2023-03-27T10:53:16.198+08:00[Asia/Shanghai]
    }
​
    @Test
    public void test2(){
        ZoneId id = ZoneId.of("America/Los_Angeles");
        ZonedDateTime luo = ZonedDateTime.now(id);
        System.out.println(luo);
        //2023-03-26T19:54:09.470-07:00[America/Los_Angeles]
    }
​
    @Test
    public void test3(){
        Set<String> availableZoneIds = ZoneId.getAvailableZoneIds();
        System.out.println(availableZoneIds);
    }
}
import org.junit.Test;
​
import java.time.Instant;
import java.time.ZonedDateTime;
​
public class TestInstant {
    @Test
    public void test(){
        Instant obj = Instant.now();
        System.out.println(obj);
        //2023-03-27T02:55:45.749Z
    }
​
    @Test
    public void test1(){
        ZonedDateTime current = ZonedDateTime.now();
        System.out.println(current);
        //2023-03-27T10:56:05.894+08:00[Asia/Shanghai]
    }
}
​

3、日期时间间隔

    两个日期或两个时间之间的间隔。
    Period:用于计算两个“日期”间隔
    Duration:用于计算两个“时间”间隔
package com.atguigu.datetime;
​
import org.junit.Test;
​
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalTime;
import java.time.Period;
​
public class TestPeriodAndDuration {
    @Test
    public void test1(){
        LocalDate today = LocalDate.now();
        LocalDate kai = LocalDate.of(2023,3,8);
        Period period = Period.between(kai, today);
        System.out.println(period);//P19D
    }
​
    @Test
    public void test2(){
        LocalDate today = LocalDate.now();
        LocalDate birthday = LocalDate.of(1997,7,1);
        Period period = Period.between(birthday, today);
        System.out.println(period);//P25Y8M26D
    }
​
    @Test
    public void test3(){
        LocalTime now = LocalTime.now();
        LocalTime chi = LocalTime.of(12,0,0);
        Duration d = Duration.between(now,chi);
        System.out.println(d);
    }
​
}
​

4、日期时间格式化

DateTimeFormatter:日期时间格式化
该类提供了三种格式化方法:
​
预定义的标准格式。如:ISO_DATE_TIME;ISO_DATE
​
本地化相关的格式。如:ofLocalizedDate(FormatStyle.MEDIUM)
​
自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
​

​
import org.junit.Test;
​
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
​
public class TestDateTimeFormatter {
    @Test
    public void test1(){
        LocalDate today = LocalDate.now();
        System.out.println(today);
​
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy年MM月dd日");
        System.out.println(df.format(today));
​
        System.out.println(DateTimeFormatter.ISO_DATE.format(today));
    }
​
    @Test
    public void test2(){
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);
​
        DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy年MM月dd日 HH:MM:ss");
        System.out.println(df.format(now));
​
        System.out.println(DateTimeFormatter.ISO_DATE_TIME.format(now));
    }
​
    @Test
    public void test3(){
        LocalDateTime now = LocalDateTime.now();
        System.out.println(now);//2023-03-27T11:04:42.792
​
        DateTimeFormatter d1 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.LONG);
        DateTimeFormatter d2 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
        DateTimeFormatter d3 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM);
        System.out.println(d1.format(now));//2023年3月27日 上午11时04分42秒
        System.out.println(d2.format(now));//23-3-27 上午11:04
        System.out.println(d3.format(now));//2023-3-27 11:04:42
​
        DateTimeFormatter d4 = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL).withZone(ZoneId.of("Asia/Shanghai"));
        System.out.println(d4.format(now));
    }
}
​

9.4 系统相关类

1、java.lang.System类
(1public final static InputStream System.in
(2public final static PrintStream System.out
(3public final static PrintStream System.err
​
在Java层面final修饰的变量是不可修改的。
在Java层面final修饰的成员变量是没有set方法。
​
    private static native void setIn0(InputStream in);
    private static native void setOut0(PrintStream out);
    private static native void setErr0(PrintStream err);
​
(4static Properties getProperties():获取所有系统属性
(5static String getProperties(key):获取一个系统属性
(6static void gc():通知GC过来回收垃圾对象。
​
面试题:finalfinally、finalize的区别(老面试题)
finalize是Object类的一个方法,protected void finalize()throws Throwable
finalize方法是由GC调用,不是程序员手动调用的,当对象称为垃圾对象时,GC来回收它时,
会调用它。finalize方法中用于彻底释放当前对象占用的内存资源。
​
(7static void exit(int status) :退出JVM。
(8static long currentTimeMillis() :获取系统时间的毫秒值
            这个毫秒值是距离1970110:0:0 0毫秒的时间差
​
2、java.lang.Runtime类型:代表当前Java程序的运行时环境。
(1)Runtime是一个单例类,只有唯一的一个实例对象的类。
它的唯一对象需要通过getRuntime()方法获取
(2)方法
Runtime getRuntime()
long totalMemory():总内存
long freeMemory():空闲内存

API演示1

import org.junit.Test;
​
import java.io.IOException;
import java.io.PrintStream;
import java.util.Properties;
import java.util.Scanner;
​
public class TestSystem {
    @Test
    public void test1(){
        PrintStream out = System.out;
        out.println("hello");
        out.println(12);
        out.println(true);
    }
​
    @Test
    public void test2(){
        Scanner input = new Scanner(System.in);
​
        System.out.print("请输入姓名:");
        String name = input.next();
        System.out.println(name);
​
        input.close();
    }
​
    @Test
    public void test3(){
        PrintStream err = System.err;
        err.println("错误信息");
    }
​
    @Test
    public void test4()throws IOException {
        System.setOut(new PrintStream("d:\1.txt"));
    }
​
    @Test
    public void test5(){
        Properties properties = System.getProperties();
        System.out.println(properties);
​
        String value = System.getProperty("file.encoding");
        System.out.println("value = " + value);
​
        String os = System.getProperty("os.name");
        System.out.println("os = " + os);
    }
}

API演示2

public class Demo {
    @Override
    protected void finalize() throws Throwable {
        System.out.println("我悄悄地走了,不带走一段代码!");
    }
}
​
package com.atguigu.system;
​
public class TestFinalize {
    public static void main(String[] args) {
        Demo demo = new Demo();
        demo = null;//demo变量之前引用的对象就成了垃圾对象了
​
        System.gc();//呼叫一下GC工作
​
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}
​

API演示3

public class TestRuntime {
    public static void main(String[] args) {
        Runtime runtime = Runtime.getRuntime();//获取JVM的运行时环境
        long totalMemory = runtime.totalMemory();//获取JVM的总内存
        long freeMemory = runtime.freeMemory();//获取JVM的空闲内存
        System.out.println("totalMemory = " + totalMemory);
        System.out.println("freeMemory = " + freeMemory);
        System.out.println("差:" + (totalMemory-freeMemory));//已用内存
    }
}
​

API演示4

public class TestTimeMemory {
    public static void main(String[] args) {
        long start = System.currentTimeMillis();
        System.out.println("start = " + start);
        String s = "";
        for(int i=1; i<=100000; i++){
            s += i;
        }
​
        long end = System.currentTimeMillis();
        System.out.println("end = " + end);
        System.out.println("时间差:" +( end-start));
​
        Runtime runtime = Runtime.getRuntime();//获取JVM的运行时环境
        long totalMemory = runtime.totalMemory();//获取JVM的总内存
        long freeMemory = runtime.freeMemory();//获取JVM的空闲内存
        System.out.println("totalMemory = " + totalMemory);
        System.out.println("freeMemory = " + freeMemory);
        System.out.println("差:" + (totalMemory-freeMemory));//已用内存
​
    }
}
​

9.5 数组工具方法

9.5.1 数组工具类

1、java.util.Arrays类:有一系列的静态方法,用于操作各种数组。
(1)数组元素拼接
-static String toString(int[] a) :字符串表示形式由数组的元素列表组成,括在方括号("[]")中。相邻元素用字符 ", "(逗号加空格)分隔。形式为:[元素1,元素2,元素3。。。]
-static String toString(Object[] a) :字符串表示形式由数组的元素列表组成,括在方括号("[]")中。相邻元素用字符 ", "(逗号加空格)分隔。元素将自动调用自己从Object继承的toString方法将对象转为字符串进行拼接,如果没有重写,则返回类型@hash值,如果重写则按重写返回的字符串进行拼接。
​
(2)数组排序
- static void sort(int[] a) :将a数组按照从小到大进行排序
- static void sort(int[] a, int fromIndex, int toIndex) :将a数组的[fromIndex, toIndex)部分按照升序排列
​
(3)数组元素的二分查找
- static int binarySearch(int[] a, int key)
如果存在,返回它的下标
如果不存在,返回-插入点-1,插入点是指假设把这个数插入到当前数组中,它应该在哪里。
​
(4)数组的复制
- static int[] copyOf(int[] original, int newLength)  :根据original原数组复制一个长度为newLength的新数组,并返回新数组
- static <T> T[] copyOf(T[] original,int newLength):根据original原数组复制一个长度为newLength的新数组,并返回新数组
- static int[] copyOfRange(int[] original, int from, int to) :复制original原数组的[from,to)构成新数组,并返回新数组
- static <T> T[] copyOfRange(T[] original,int from,int to):复制original原数组的[from,to)构成新数组,并返回新数组
​
(5)比较两个数组是否相等
- static boolean equals(int[] a, int[] a2) :比较两个数组的长度、元素是否完全相同
- static boolean equals(Object[] a,Object[] a2):比较两个数组的长度、元素是否完全相同
​
(6)填充数组
- static void fill(int[] a, int val) :用val值填充整个a数组
- static void fill(Object[] a,Object val):用val对象填充整个a数组
- static void fill(int[] a, int fromIndex, int toIndex, int val):将a数组[fromIndex,toIndex)部分填充为val值
- static void fill(Object[] a, int fromIndex, int toIndex, Object val) :将a数组[fromIndex,toIndex)部分填充为val对象
​
import org.junit.Test;
​
import java.util.Arrays;
​
public class TestArrays {
    @Test
    public void test1() {
        int[] arr = {1, 2, 3, 4, 5};
        System.out.println(arr);//[I@3d82c5f3
​
        System.out.println(Arrays.toString(arr));//[1, 2, 3, 4, 5]
    }
​
    @Test
    public void test2() {
        Student[] all = new Student[3];
        all[0] = new Student(1, "张三", 89);
        all[1] = new Student(2, "李四", 88);
        all[2] = new Student(3, "王五", 63);
​
        System.out.println(Arrays.toString(all));
    }
​
    @Test
    public void test3() {
        int[] arr = {1, 12, 36, 41, 5};
        Arrays.sort(arr);
        System.out.println(Arrays.toString(arr));//[1, 5, 12, 36, 41]
    }
​
    @Test
    public void test4() {
        int[] arr = {1, 12, 36, 41, 5, 7, 2, 90};
        Arrays.sort(arr, 2, 6);//Java中,两个下标,左闭右开[start, end)
        System.out.println(Arrays.toString(arr));//[1, 12, 5, 7, 36, 41, 2, 90]
    }
​
    @Test
    public void test5() {
        int[] arr = {1, 5, 12, 36, 41};
​
        int target = 18;
        int index = Arrays.binarySearch(arr, target);
        System.out.println("index = " + index);//index = -4
        //如果18现在要插入到arr中,它应该插入到arr[3]位置
    }
​
    @Test
    public void test6() {
        int[] arr = {1, 5, 12, 36, 41};
​
//        arr = Arrays.copyOf(arr, (int)(arr.length*1.5));
//        arr = Arrays.copyOf(arr, arr.length + arr.length/2);
        arr = Arrays.copyOf(arr, arr.length + (arr.length >> 1));
        System.out.println(Arrays.toString(arr));//[1, 5, 12, 36, 41, 0, 0]
    }
​
    @Test
    public void test7() {
        int[] arr = {1, 5, 12, 36, 41};
        arr = Arrays.copyOf(arr,3);
​
        System.out.println(Arrays.toString(arr));
    }
​
    @Test
    public void test8(){
        int[] arr = {1, 5, 12, 36, 41};
        int[] nums = {1, 5, 12, 36, 41};
​
        System.out.println(Arrays.equals(arr, nums));//比较数组的长度和元素
​
        System.out.println(arr.equals(nums));//Object类继承的equals  false ,比较地址值
    }
​
    @Test
    public void test9(){
        int[] arr = new int[5];
        Arrays.fill(arr, 8);
        System.out.println(Arrays.toString(arr));
    }
}
​

9.5.2 System.arraycopy

2、java.lang.System类:
static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):
从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。常用于数组的插入和删除
​
解释一下:arraycopy为什么不在Arrays工具类中,而是在System类中?
原因:Arrays工具类是JDK1.2才引入的,在这个之前没有专门的数组工具类,
    但是关于的数组的复制是从JDK1.0就有,非常重要的一个方法。
​
另外,这个方法设计的非常巧妙,形参用的是Object类型,
可以接收任意数组类型,包括元素是基本数据类型的数组,也包含元素是引用数据类型的数组。
​
并且,这个方法功能非常强大,既支持两个不同数组之间的元素“拷贝”,
        也支持同一个数组内部的元素“拷贝”。
​
        如果是两个不同数组之间的“拷贝”,那么按照元素的下标一一对应就可以。
        如果是同一个数组内部的“拷贝”,
                当srcPos > destPos时,往前移动,一般是删除。
                当srcPos < destPos时,往后移动,一般是插入。
​
​
arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
第一个参数:原数组,既从src数组中开始复制元素
第二个参数:原数组的起始下标,表示从左边数的第一个下标,
    相当于从src[srcPos]位置开始取元素
第三个参数:目标数组,既把元素复制到dest数组中
第四个参数:目标数组的起始下标,表示从左边数的第一个下标,
    相当于src[srcPos]位置的元素复制到dest[destPos]位置
第五个参数:一共复制几个元素
import org.junit.Test;
​
public class TestArray {
    @Test
    public void test1(){
        int[] arr = {1,2,3,4,5};
//        method(arr);//报错
        fun(arr);//不会报错,int[]也是引用数据类型
    }
​
    public void method(Object[] arr){
        //....
    }
/*    public void method(int[] arr){
        //....
    }
    public void method(double[] arr){
        //....
    }*/
​
    public void fun(Object arr){
        //....
    }
}
​

​
import org.junit.Test;
​
import java.util.Arrays;
​
public class TestSystemArrayCopy {
    @Test
    public void test1(){
        int[] arr = {1,2,3,4,5};
        int[] nums = new int[10];
​
        /*
        第一个参数:原数组,既从src数组中开始复制元素
        第二个参数:原数组的起始下标,表示从左边数的第一个下标,
            相当于从src[srcPos]位置开始取元素
        第三个参数:目标数组,既把元素复制到dest数组中
        第四个参数:目标数组的起始下标,表示从左边数的第一个下标,
            相当于src[srcPos]位置的元素复制到dest[destPos]位置
        第五个参数:一共复制几个元素
         */
        System.arraycopy(arr, 0,nums, 0, 3);
​
        System.out.println(Arrays.toString(arr));
        System.out.println(Arrays.toString(nums));
    }
​
    @Test
    public void test2(){
        int[] arr = {1,2,3,4,5};
        int[] nums = new int[10];
​
        /*
        第一个参数:原数组,既从src数组中开始复制元素
        第二个参数:原数组的起始下标,表示从左边数的第一个下标,
            相当于从src[srcPos]位置开始取元素
        第三个参数:目标数组,既把元素复制到dest数组中
        第四个参数:目标数组的起始下标,表示从左边数的第一个下标,
            相当于src[srcPos]位置的元素复制到dest[destPos]位置
        第五个参数:一共复制几个元素
         */
        System.arraycopy(arr, 0,nums, 3, 3);
​
        System.out.println(Arrays.toString(arr));
        System.out.println(Arrays.toString(nums));
    }
​
    @Test
    public void test3(){
        int[] arr = {1,2,3,4,5};
        /*
        一共复制4个元素
        arr[3] -> arr[4]
        arr[2] -> arr[3]
        arr[1] -> arr[2]
        arr[0] -> arr[1]
​
         */
        System.arraycopy(arr, 0, arr, 1, 4);
        System.out.println(Arrays.toString(arr));//[1, 1, 2, 3, 4]
    }
​
    @Test
    public void test4() {
        int[] arr = {1, 2, 3, 4, 5};
        //插入元素6到1和2之间
        arr = Arrays.copyOf(arr, arr.length + 1);
        System.arraycopy(arr, 1, arr, 2,4);
        System.out.println(Arrays.toString(arr));//[1, 2, 2, 3, 4, 5]
        arr[1] = 6;
        System.out.println(Arrays.toString(arr));//[1, 6, 2, 3, 4, 5]
    }
​
    @Test
    public void test5(){
        int[] arr = {1, 2, 3, 4, 5};
        System.arraycopy(arr, 2, arr, 1,3);
        /*
        复制3个
        arr[2]  --> arr[1]
        arr[3]  --> arr[2]
        arr[4]  --> arr[3]
         */
        System.out.println(Arrays.toString(arr));//[1, 3, 4, 5, 5]
    }
​
    @Test
    public void test6(){
        int[] arr = {1, 2, 3, 4, 5};
        //删除元素2
        System.arraycopy(arr, 2, arr, 1,3);
        arr = Arrays.copyOf(arr, arr.length-1);
        System.out.println(Arrays.toString(arr));
    }
​
}
​

9.5.3 自定义动态数组(节选)


​
import java.util.Arrays;
​
/*
动态数组:后面有现成的类,现在自定义一个,为了捋清楚一些思路,顺便练习一下API
MyArrayList类的对象相当于是一个容器,可以用来装任意个对象的容器。
 */
public class MyArrayList {//implements Iterable{
    private Object[] arr = new Object[5];//先准备5个,不够了再加
    private int size;//实际存入数组的元素的个数
​
    public void add(Object element){
        grow();
        arr[size++] = element;
        //有效元素的下标范围:[0, size-1]
​
    }
​
    //抽取一段代码生成一个新方法:Ctrl + Alt+ M
    private void grow() {
        if(size>=arr.length){
          /*  arr = Arrays.copyOf(arr, arr.length+1);//多1个  优点:不会浪费,缺点,扩容频繁
            arr = Arrays.copyOf(arr, arr.length<<1);//2倍   优点:扩容频率低,可能会浪费*/
            arr = Arrays.copyOf(arr, arr.length + (arr.length>>1));//1.5倍 相对居中
        }
    }
​
    //把新元素插入到index位置
    public void add(int index, Object element){
        //有效元素的范围[0, size-1]
        //正确的插入位置[0, size]
        checkIndex(index, index > size);
​
        grow();
​
​
        /*
        假设 arr.length = 10,size=7, index= 3
        有效元素范围[0,6]
        arr[6]~arr[7]
        arr[5]~arr[6]
        arr[4]~arr[5]
        arr[3]~arr[4]
        移动元素个数:size-index
         */
        System.arraycopy(arr, index, arr, index+1, size-index);
        //把element放到arr[index]
        arr[index] = element;
        size++;
    }
​
    public void remove(int index){
        //有效元素的范围[0, size-1]
        //正确的删除位置[0, size-1]
        //检查index位置
        checkIndex(index, index >= size);
​
        /*
        假设 arr.length = 10,size=7, index= 3
        有效元素范围[0,6]
        arr[4] -> arr[3]
        arr[5] -> arr[4]
        arr[6] -> arr[5]
        一共移动了3个元素  size-index-1
         */
        System.arraycopy(arr, index+1, arr, index,size-index-1);
        //末尾位置处理
      /*  arr[size-1] = null;
        size--;*/
        arr[--size]=null;
    }
​
    private void checkIndex(int index, boolean index1) {
        if(index <0 || index1){
            throw new IndexOutOfBoundsException("插入位置不合理");
        }
    }
​
    public Object[] getAll(){
//        return arr;//不够完美
        //返回size个元素
        return Arrays.copyOf(arr, size);
    }
​
    /*@Override
    public Iterator iterator() {
        return new Itr();
    }
​
    private class Itr implements Iterator{
        private int index;
​
        @Override
        public boolean hasNext() {
            return index < size;
        }
​
        @Override
        public Object next() {
            return arr[index++];
        }
    }*/
}
​

​
import org.junit.Test;
​
public class TestMyArrayList {
    @Test
    public void test1(){
        MyArrayList my = new MyArrayList();
        my.add("hello");
        my.add("java");
        my.add("world");
        my.add("C");
        my.add("atguigu");
        my.add(0,"chai");
        my.add(2,"xixi");
        my.add("haha");
        my.add(3,"hehe");
        my.add("heihei");
        my.add("lala");
​
        Object[] all = my.getAll();
        for (int i = 0; i < all.length; i++) {
            System.out.println(all[i]);
        }
​
        /*Iterator iterator = my.iterator();
        while(iterator.hasNext()){
            System.out.println(iterator.next());
        }*/
​
        System.out.println("---------------");
        my.remove(1);
        my.remove(5);
        all = my.getAll();
        for (int i = 0; i < all.length; i++) {
            System.out.println(all[i]);
        }
​
    }
}
​

9.6 比较器

1、java.lang.Comparable接口:自然排序接口,自然比较接口,内部比较接口
抽象方法:int compareTo(Object obj)
比较运算符:>,<,>=,<=,==,!=
   其中==,!=对于对象来说,是比较地址值。
      >,<,>=,<=对于对象来说,不支持。
 为了统一所有类型的对象比较大小的标准,设计了比较器接口,例如:Comparable接口。
 并且规定,要比较大小的对象的类型必须重写int compareTo(Object obj),
 在该方法中,指明this对象和obj对象如何比较大小,
 结果有3种:
    正整数:意味着 this对象  大于 obj对象
    负整数:意味着 this对象  小于 obj对象
    零:   意味着 this对象  等于 obj对象
​
结论:
    谁的对象要比较大小或排序,谁就实现java.lang.Comparable接口。
​
2、java.util.Comparator接口 :定制比较器,外部比较器
抽象方法:int compare(Object o1, Object o2)
结果有3种:
    正整数:意味着 o1对象  大于 o2对象
    负整数:意味着 o1对象  小于 o2对象
    零:   意味着 o1对象  等于 o2对象
​
结论:
    需要“单独编写”一个类,实现Comparator接口,比较某个类的两个对象的大小。
    又通常因为这个比较器的代码不会很复杂,很多时候使用匿名内部类来实现Comparator接口。
​

9.6.1 自然比较器


​
import java.util.Comparator;
​
public class MyArrays {
    public static void sort(Object[] arr){
        for(int i=0; i<arr.length-1; i++){
            for(int j=0; j<arr.length-1-i; j++){
                if(((Comparable)arr[j]).compareTo(arr[j+1]) > 0){
                    Object temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
​
    /*public static void sort(Object[] arr){
        for(int i=0; i<arr.length-1; i++){
            for(int j=0; j<arr.length-1-i; j++){
                if(arr[j] > arr[j+1]){//错误,因为两个对象无法直接比较大小
                    Object temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }*/
}
​
package com.atguigu.compare;
​
public class Circle implements Comparable{
    private double radius;
​
    public Circle(double radius) {
        this.radius = radius;
    }
​
    public double getRadius() {
        return radius;
    }
​
    public void setRadius(double radius) {
        this.radius = radius;
    }
​
    @Override
    public String toString() {
        return "Circle{" +
                "radius=" + radius +
                '}';
    }
​
    @Override
    public int compareTo(Object o) {
        //o此时的编译时类型是Object类型,无法调用子类Circle的radius属性
        //需要向下转型
        Circle other = (Circle) o;
        //告诉它this对象和o对象如何比较大小?例如:按照半径比较大小
/*        if( this.radius > other.radius){
            return 1;//只要是正整数就行,什么值不重要
        }else if(this.radius < other.radius){
            return -1;
        }
        return 0;*///对//        return (int) (this.radius - other.radius);//不是很准确  5.2  5.8
        return Double.compare(this.radius, other.radius);   //使用现有的包装类的compare方法完成比较两个double值的大小
    }
}
​
import java.util.Objects;
​
public class Student implements Comparable {
    private int id;
    private String name;
    private int score;
​
    private int age;
​
    public Student(int id, String name, int score) {
        this.id = id;
        this.name = name;
        this.score = score;
​
    }
​
    public Student(int id, String name, int score, int age) {
        this.id = id;
        this.name = name;
        this.score = score;
        this.age = age;
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    public String getName() {
        return name;
    }
​
    public void setName(String name) {
        this.name = name;
    }
​
    public int getScore() {
        return score;
    }
​
    public void setScore(int score) {
        this.score = score;
    }
​
    public int getAge() {
        return age;
    }
​
    public void setAge(int age) {
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + ''' +
                ", score=" + score +
                ", age=" + age +
                '}';
    }
​
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
​
        Student student = (Student) o;
​
        if (id != student.id) return false;
        if (score != student.score) return false;
        return Objects.equals(name, student.name);
    }
​
    @Override
    public int hashCode() {//这个方法先忽略
        int result = id;
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + score;
        return result;
    }
​
    @Override
    public int compareTo(Object o) {
        //假设,这里要求按照学生的成绩比较大小,如果成绩相同,按照学号比较大小
        Student other = (Student) o;
        int result = this.score - other.score;
        return result == 0 ? this.id - other.id: result;
    }
​
}
​

​
import org.junit.Test;
​
import java.util.Comparator;
​
public class TestCompare {
    @Test
    public void test1(){
        Circle c1 = new Circle(1.2);
        Circle c2 = new Circle(2.2);
​
        //比较c1和c2两个对象的大小
//        System.out.println(c1 > c2);//错误,无法直接比较大小
        System.out.println(c1.getRadius() > c2.getRadius());
    }
​
    @Test
    public void test2(){
        Circle[] arr = new Circle[3];
        arr[0] = new Circle(2.2);
        arr[1] = new Circle(1.2);
        arr[2] = new Circle(3.2);
​
        MyArrays.sort(arr);
​
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
​
    }
​
    @Test
    public void test3(){
        Student[] all = new Student[3];
        all[0] = new Student(1,"张三",75);
        all[1] = new Student(2,"李四",96);
        all[2] = new Student(3,"王五",75);
​
        MyArrays.sort(all);//按照成绩比较大小
​
        for (int i = 0; i < all.length; i++) {
            System.out.println(all[i]);
        }
​
    }
​
}
​

9.6.2 定制比较器


​
import java.util.Comparator;
​
public class MyArrays {
    public static void sort(Object[] arr){
        for(int i=0; i<arr.length-1; i++){
            for(int j=0; j<arr.length-1-i; j++){
                if(((Comparable)arr[j]).compareTo(arr[j+1]) > 0){
                    Object temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
​
    public static void sort(Object[] arr, Comparator c){
        for(int i=0; i<arr.length-1; i++){
            for(int j=0; j<arr.length-1-i; j++){
                if(c.compare(arr[j], arr[j+1])> 0){
                    Object temp = arr[j];
                    arr[j] = arr[j+1];
                    arr[j+1] = temp;
                }
            }
        }
    }
​
}
​
import java.util.Comparator;
​
/*
在Student类的外部实现的比较器接口
 */
public class StudentAgeComparator implements Comparator {
    @Override
    public int compare(Object o1, Object o2) {
        //年龄相同,再按学号比较
        Student s1 = (Student) o1;
        Student s2 = (Student) o2;
        int result = s1.getAge() - s2.getAge();
        return result == 0? s1.getId() - s2.getId() : result;
    }
}
​
    @Test
    public void test4(){
        Student[] all = new Student[3];
        all[0] = new Student(1,"张三",75,23);
        all[1] = new Student(2,"李四",96,22);
        all[2] = new Student(3,"王五",75,25);
​
        StudentAgeComparator sac = new StudentAgeComparator();//定制比较器对象
        MyArrays.sort(all,sac);//按照年龄比较排序
​
        for (int i = 0; i < all.length; i++) {
            System.out.println(all[i]);
        }
​
    }
​
    @Test
    public void test5(){
        Student[] all = new Student[3];
        all[0] = new Student(1,"张三",75,23);
        all[1] = new Student(2,"李四",96,22);
        all[2] = new Student(3,"王五",75,25);
​
        MyArrays.sort(all, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                //年龄相同,再按学号比较
                Student s1 = (Student) o1;
                Student s2 = (Student) o2;
                int result = s1.getAge() - s2.getAge();
                return result == 0? s1.getId() - s2.getId() : result;
            }
        });//按照年龄比较排序 , 匿名内部类实现Comparator接口
​
        for (int i = 0; i < all.length; i++) {
            System.out.println(all[i]);
        }
​
    }