9.2 和数学相关API
9.2.1 java.lang.Math类
1、java.lang.Math类
Math 类包含用于执行基本数学运算的方法,如初等指数、对数、平方根和三角函数。
Math类是final修饰的,不能被继承,构造器private,不能在外面直接创建对象。
全部都是静态方法,静态常量。
(1)double Math.random():产生[0,1)范围的double值
(2)double Math.sqrt(double x):求平方根
(3)double Math.PI:常量,圆周率
(4)xx Math.abs(xx):求xx的绝对值,支持多种数据类型
(5)double Math.ceil(xx):向上取整
(6)double Math.floor(xx):向下取整
(7)long Math.round(xx):四舍五入取整
(8)xx Math.max(xx x, xx y):取最大值,支持多种数据类型
(9)xx Math.min(xx x, xx y):取最小值,支持多种数据类型
(10)double 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 类是一个抽象类,它为特定瞬间与一组诸如 YEAR、MONTH、DAY_OF_MONTH、HOUR 等 日历字段之间的转换提供了一些方法,并为操作日历字段(例如获得下星期的日期)提供了一些方法。瞬间可用毫秒值来表示,它是距历元(即格林威治标准时间 1970 年 1 月 1 日的 00:00:00.000,格里高利历)的偏移量。与其他语言环境敏感类一样,Calendar 提供了一个类方法 getInstance,以获得此类型的一个通用的对象。
修改和获取 YEAR、MONTH、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
3: 00000000 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的整数倍
| 序号 | 方法 | 描述 |
|---|---|---|
| 1 | now() / now(ZoneId zone) | 静态方法,根据当前时间创建对象/指定时区的对象 |
| 2 | of() | 静态方法,根据指定日期/时间创建对象 |
| 3 | getDayOfMonth()/getDayOfYear() | 获得月份天数(1-31) /获得年份天数(1-366) |
| 4 | getDayOfWeek() | 获得星期几(返回一个 DayOfWeek 枚举值) |
| 5 | getMonth() | 获得月份, 返回一个 Month 枚举值 |
| 6 | getMonthValue() / getYear() | 获得月份(1-12) /获得年份 |
| 7 | getHours()/getMinute()/getSecond() | 获得当前对象对应的小时、分钟、秒 |
| 8 | withDayOfMonth()/withDayOfYear()/withMonth()/withYear() | 将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象 |
| 9 | with(TemporalAdjuster t) | 将当前日期时间设置为校对器指定的日期时间 |
| 10 | plusDays(), plusWeeks(), plusMonths(), plusYears(),plusHours() | 向当前对象添加几天、几周、几个月、几年、几小时 |
| 11 | minusMonths() / minusWeeks()/minusDays()/minusYears()/minusHours() | 从当前对象减去几月、几周、几天、几年、几小时 |
| 12 | plus(TemporalAmount t)/minus(TemporalAmount t) | 添加或减少一个 Duration 或 Period |
| 13 | isBefore()/isAfter() | 比较两个 LocalDate |
| 14 | isLeapYear() | 判断是否是闰年(在LocalDate类中声明) |
| 15 | format(DateTimeFormatter t) | 格式化本地日期、时间,返回一个字符串 |
| 16 | parse(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类
(1)public final static InputStream System.in
(2)public final static PrintStream System.out
(3)public 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);
(4)static Properties getProperties():获取所有系统属性
(5)static String getProperties(key):获取一个系统属性
(6)static void gc():通知GC过来回收垃圾对象。
面试题:final、finally、finalize的区别(老面试题)
finalize是Object类的一个方法,protected void finalize()throws Throwable
finalize方法是由GC调用,不是程序员手动调用的,当对象称为垃圾对象时,GC来回收它时,
会调用它。finalize方法中用于彻底释放当前对象占用的内存资源。
(7)static void exit(int status) :退出JVM。
(8)static long currentTimeMillis() :获取系统时间的毫秒值
这个毫秒值是距离1970年1月1日 0: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]);
}
}