**String****类:代表字符串。**Java 程序中的所有字符串字面值(如 “abc” )都作
为此类的实例实现。
String是一个final类,代表不可变的字符序列。
字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
https://i.loli.net/2021/06/12/Ps7AnfxNqwKQc8h.png
String对象的字符内容是存储在一个字符数组value[]中的。
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
以上可见,在String类里,我们实现里两个接口,Serializable:这表示字符串是可以序列化的,Comparable:表示字符串是可以比较的
package com.hyb.usualClass;
import org.junit.Test;
/**
* @program: StringTest
* @description:常用类,String
*
*
* @author: Huang Yubin
* @create: 2021-06-08 12:35
**/
public class StringTest {
@Test
public void test1(){
// 字面量赋值
String s1="abc";
s1+="1";
System.out.println(s1);
/*可见我们可以给字符串更改值,但是从内存结构来讲,abc是没有被改变的,只是将abc1这个值赋值给了s1
* 但是abc1从哪来的呢?只是从常量池里找来的,并不是在原来的abc上加过来的*/
/*--------------------------------*/
String s2="abc";
String s3=s2.replace("a","c");
System.out.println(s3);
// cbc
/*在这里原理也是一样,我们将a用c代替,只是创造了一个新的常亮cbc,而不是将原来abc修改了*/
/*在这里我们便能总结出一个道理:
* 字符串本质上是不可变的 */
}
}
@Test
public void test2(){
String s1="abc";
String s2="abc";
String s3=new String("abc");
String s4=new String("abc");
System.out.println(s1==s2);//true,因为常量值是一定的,不可改变,当然,地址可能不一样
System.out.println(s1==s3);//false,对象存储在堆中,abc存在常量池中,地址可能改变
System.out.println(s3 == s4);//false,对象比较是地址
System.out.println(s1 == s4);//false
/*但是这里可说明一点,当我们用同一个类new两个对象比较两个相等的字符串时,==符号便可以比较的
* 因为我们new了两个对象在堆空间中造了两个地址,但是这两个相等的字符串是在常量池里的,不可改变*/
/*---------------*/
/*面试题里,一般都会问String s3=new String("abc");创建了几个对象?
* 可知,有两个。
* 一个是堆空间里的,一个是常量池里的*/
}
https://i.loli.net/2021/06/12/ONm7hq2HW1I6uAY.png
https://i.loli.net/2021/06/12/jreEBhJbDmH62lC.png
https://i.loli.net/2021/06/12/VQms7Nonctwhqpv.png
@Test
public void test3(){
String s1="abc";
String s2="abc";
String s3=s1+s2;
String s4="abcabc";
String s5=s1+"abc";
System.out.println(s1 == s2);//true常量池的常量不可变
System.out.println(s1 == s3);//false内容都不等
System.out.println(s3 == s4);//false s4在常量池里,而s3在堆里创建了一个对象,让s1+s2
System.out.println(s4 == s5);//false 也一样
String s6=(s3).intern();
System.out.println(s6==s4);//ture,intern()返回常量池
/*我们就此可以总结出:
* 1.常亮与常亮的拼接是返回常亮池的,且常量池里没有相同的常亮
* 2.只要其中有一个是变量,结果就在堆中
* 3.如果用intern方法,结果会返回常量池*/
}
}
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-yMdbNMLb-1647786099625)(C:\Users\黄渝斌\Desktop\5.png)]
package com.hyb.usualClass;
/**
* @program: InterviewProblem
* @description:
* @author: Huang Yubin
* @create: 2021-06-08 13:43
**/
public class InterviewProblem1 {
String str = new String("good");
char[] ch = { 't', 'e', 's', 't' };
public void change(String str, char ch[]) {
str = "test ok";
ch[0] = 'b';
}
public static void main(String[] args) {
InterviewProblem1 ex = new InterviewProblem1();
ex.change(ex.str, ex.ch);
System.out.println(ex.str);//good
System.out.println(ex.ch);//best
}
/*good是一个字符串,字符串是无法改变的,所以输出good,也可以这样理解,java是值传递的,改变不了str
* ch是一个数组,数组是可变的,自然可以改变*/
}
https://i.loli.net/2021/06/12/bS7ZalCqFNMjOnG.png
https://i.loli.net/2021/06/12/MnAPZ5Rgu3TbUla.png
https://i.loli.net/2021/06/12/AluWXjTYt7KLiI3.png
字符串 -> 基本数据类型、包装类
Integer包装类的public static int parseInt(String s):可以将由“数字”字
符组成的字符串转换为整型。
类似地,使用java.lang包中的Byte、Short、Long、Float、Double类调相应
的类方法可以将由“数字”字符组成的字符串,转化为相应的基本数据类型。
基本数据类型、包装类 -> 字符串
调用String类的public String **valueOf(int n)**可将int型转换为字符串
相应的valueOf(byte b)、valueOf(long l)、valueOf(float f)、valueOf(double
d)、valueOf(boolean b)可由参数的相应类型到字符串的转换
字符数组 -> 字符串
String 类的构造器:String(char[]) 和 String(char[],int offset,int
length) 分别用字符数组中的全部字符和部分字符创建字符串对象。
String s2=new String(Arry);
System.out.println(s2);//abc
字符串->转为为字符数组
**public char[] toCharArray()**将字符串中的全部字符存放在一个字符数组
中的方法。
public void getChars(int srcBegin, int srcEnd, char[] dst,
**int dstBegin)**提供了将指定索引范围内的字符串存放到数组中的方法。
String s1="abc";
char[] Arry=s1.toCharArray();
for (int i = 0; i < s1.length(); i++) {
System.out.println(Arry[i]);
}
字符串->字符数组
public byte[] getBytes() **:**使用平台的默认字符集将此 String 编码为
byte 序列,并将结果存储到一个新的 byte 数组中。
public byte[] getBytes(String charsetName) **:**使用指定的字符集将
此 String 编码到 byte 序列,并将结果存储到新的 byte 数组。
String s1="abc中国";
byte[] s2=s1.getBytes();
字节数组 -> 字符串
String(byte[],int offset,**int length) **用指定的字节数组的一部分,
即从数组起始位置offset开始取length个字节构造一个字符串对象。
String(byte[],int offset,int length) 用指定的字节数组的一部分,
即从数组起始位置offset开始取length个字节构造一个字符串对象。
String s = new String(s2);
@Test
public void test5() throws UnsupportedEncodingException {
// 编码
String s1="abc中国";
byte[] s2=s1.getBytes();
System.out.println(Arrays.toString(s2));
// [97, 98, 99, -28, -72, -83, -27, -101, -67]UTF_8
byte[] s3=s1.getBytes("gbk");
System.out.println(Arrays.toString(s3));
// [97, 98, 99, -42, -48, -71, -6]jbk
// 解码
String s = new String(s2);
System.out.println(s);
// abc中国
String gbk = new String(s3, "gbk");
System.out.println(gbk);
// abc中国
}
}
//API
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
String s = new String("我喜欢学习");
StringBuffer buffer = new StringBuffer("我喜欢学习");
buffer.append("数学");
//我喜欢学习数学
https://i.loli.net/2021/06/12/mT6SBo4LcyHfCFN.png
JDK1.0中声明,可以对字符
串内容进行增删,此时不会产生新的对象。
很多方法与String相同。
作为参数传递时,方法内部可以改变值。
StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接
StringBuffer delete(int start,int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx
StringBuffer reverse() :把当前字符序列逆转
public String substring(int start,int end):把[start,end)位置替换为str
public void setCharAt(int n ,char ch):将指定位置字符改变
public char charAt(int n ):获取某一个位置字符
增:append(xxx)
删: delete(int start,int end)
改: replace(int start, int end, String str):把[start,end)位置替换为str。
substring(int start,int end):把[start,end)位置替换为str
setCharAt(int n ,char ch):将指定位置字符改变
查:charAt(int n ):获取某一个位置字符
插: insert(int offset, xxx):在指定位置插入xxx
长度:length()
遍历:for+查
StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且
提供相关功能的方法也一样
String(JDK1.0):不可变字符序列
StringBuffer(JDK1.0):可变字符序列、效率低、线程安全
StringBuilder(JDK 5.0):可变字符序列、效率高、线程不安全
作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder
会改变其值。
底层都使用char数组存储。
String S1=new String();//value =new char[0]
String s1=new String("abc")//value new char[]{'a','b','c'}
StringBuffer s1=new StringBuffer();//value =new char[16]底层创建了一个长度为16的数组
s1.append('a');//value[0]='a';
StringBuffer s1=new StringBuffer("abc")//value =new char["abc".length()+16]扩容
输出三者的长度时:
String:就是当前length
StringBuffer:也是当前length,虽然底层创建了16长度的数组,但是返回的length是根据当前length返回的
StingBuffer都一样。
扩容问题:
如果添加的数据底层装不下,那么需要将底层的数组扩容,默认下,每次扩容两倍,将原来的数组赋值到新的数组里
**StringBuffer(int)**可指定底层数组容量
关于三者执行时间的比较:StringBuilder
long startTime = 0L;
long endTime = 0L;
String text = "";
StringBuffer buffer = new StringBuffer("");
StringBuilder builder = new StringBuilder("");
//开始对比
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
buffer.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuffer的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
builder.append(String.valueOf(i));
}
endTime = System.currentTimeMillis();
System.out.println("StringBuilder的执行时间:" + (endTime - startTime));
startTime = System.currentTimeMillis();
for (int i = 0; i < 20000; i++) {
text = text + i; }
endTime = System.currentTimeMillis();
System.out.println("String的执行时间:" + (endTime - startTime));
点击图片链接:https://i.loli.net/2021/06/12/7kdIqz4jSFRX325.png
System类提供的public static long currentTimeMillis()用来返回当前时
间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差,俗称时间戳。
计算世界时间的主要标准有:
UTC(Coordinated Universal Time)
GMT(Greenwich Mean Time)
CST(Central Standard Time)
表示特定的瞬间,精确到毫秒
**Date()**使用无参构造器创建的对象可以获取本地当前时间。
Date(long date)
**getTime()*返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象
表示的毫秒数。
**toString()*把此 Date 对象转换为以下形式的 String: dow mon dd
hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue,
Wed, Thu, Fri, Sat),zzz是时间标准。
其它很多方法都过时了。
import java.util.Date;
Date date = new Date();
System.out.println(date);
System.out.println(System.currentTimeMillis());
System.out.println(date.getTime());
Date date1 = new Date(date.getTime());
System.out.println(date1.getTime());
System.out.println(date1.toString());
子类java.sql.Date,一般方法如父类一样。
其子类转化为父类,直接强转,多态便可以进行
但是父类转化为子类,要用到中间值,也就是时间戳(毫秒数)。
Date date=new Date();
java.sql.Date date1=new java.sql.Date(date.getTime());
Date类的API不易于国际化,大部分被废弃了,java.text.SimpleDateFormat
类是一个不与语言环境有关的方式来格式化和解析日期的具体类。
格式化:将一个日期转化为字符串
SimpleDateFormat() :默认的模式和语言环境创建对象
**public SimpleDateFormat(String pattern)**该构造方法可以用参数pattern
指定的格式创建一个对象,该对象调用:
**public String format(Date date)**方法格式化时间对象date
package com.hyb.usualClass;
import javafx.scene.input.DataFormat;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @program: StringBuffter
* @description:
* @author: Huang Yubin
* @create: 2021-06-08 14:46
**/
public class DateTest {
@Test
public void test1() throws ParseException {
Date date = new Date();
/*默认格式化*/
SimpleDateFormat sdf1 = new SimpleDateFormat();
System.out.println(sdf1.format(date));
// 21-6-8 下午4:27
/*解析*/
System.out.println(sdf1.parse("21-6-8 下午4:27"));
// Tue Jun 08 16:27:00 CST 2021
/*API自定义格式化*/
SimpleDateFormat syf2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
System.out.println(syf2.format(date));
// 2021-06-08 04:32:57
/*解析*/
System.out.println(syf2.parse("2021-06-08 04:32:57"));
// Tue Jun 08 04:32:57 CST 2021
}
}
抽象类,无法直接实例化
使用子类GregorianCalendar实例化,或者调用方法用Calendar.getInstance()
常用方法
通过get(int field)方法来取得想
要的时间信息。比如YEAR、MONTH、DAY_OF_WEEK、HOUR_OF_DAY 、
MINUTE、SECOND
public void set(int field,int value)
public void add(int field,int amount)
public final Date getTime()
public final void setTime(Date date)
package com.hyb.usualClass;
import javafx.scene.input.DataFormat;
import org.junit.Test;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
/**
* @program: StringBuffter
* @description:
* @author: Huang Yubin
* @create: 2021-06-08 14:46
**/
public class DateTest {
@Test
public void test2(){
GregorianCalendar date1 = new GregorianCalendar();
// get,获取日历信息
System.out.println(date1.get(Calendar.DAY_OF_MONTH));//六月份第八天
// set改变时间
date1.set(Calendar.DAY_OF_MONTH,9);
System.out.println(date1.get(Calendar.DAY_OF_MONTH));//变成六月份第九天
// getTime
System.out.println(date1.getTime());//Wed Jun 09 17:04:37 CST 2021
// setTime
Date date = new Date();
date1.setTime(date);
System.out.println(date1.get(Calendar.DAY_OF_MONTH));//这个月第八天
}
}
获取月份时:一月是0,二月是1,以此类推,12月是11
获取星期时:周日是1,周二是2 , 。。。。周六是7
如果我们可以跟别人说:“我们在1502643933071见面,别晚了!”那么就再简单不
过了。但是我们希望时间与昼夜和四季有关,于是事情就变复杂了。JDK 1.0中包含了
一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用
了。而Calendar并不比Date好多少。它们面临的问题是:
可变性:像日期和时间这样的类应该是不可变的。
偏移性:Date中的年份是从1900开始的,而月份都从0开始。
格式化:格式化只对Date有用,Calendar则不行。
此外,它们也不是线程安全的;不能处理闰秒等。
总结:对日期和时间的操作一直是Java程序员最痛苦的地方之一。
java.time – 包含值对象的基础包
java.time.chrono – 提供对不同的日历系统的访问
java.time.format – 格式化和解析时间和日期
java.time.temporal – 包括底层框架和扩展特性
java.time.zone – 包含时区支持的类
说明:大多数开发者只会用到基础包和format包,也可能会用到temporal包。因此,尽
管有68个新的公开类型,大多数开发者,大概将只会用到其中的三分之一。
LocalDate、LocalTime、LocalDateTime 类是其中较重要的几个类,它们的实例
是不可变的对象,分别表示使用 ISO-8601日历系统的日期、时间、日期和时间。
它们提供了简单的本地日期或时间,并不包含当前的时间信息,也不包含与时区
相关的信息。
LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
LocalTime表示一个时间,而不是日期。
LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
now() / * now(ZoneId zone) 静态方法,根据当前时间创建对象/指定时区的对象
LocalDateTime now = LocalDateTime.now();//不可变
of() 静态方法,根据指定日期/时间创建对象,无偏移量
LocalDateTime of=LocalDateTime.of(2021,6,8,19,15);
System.out.println(of);
// 021-06-08T19:15
getDayOfMonth()/getDayOfYear() 获得月份天数(1-31) /获得年份天数(1-366)
getDayOfWeek() 获得星期几(返回一个 DayOfWeek 枚举值)
getMonth() 获得月份, 返回一个 Month 枚举值
getMonthValue() / getYear() 获得月份(1-12) /获得年份
getHour()/getMinute()/getSecond() 获得当前对象对应的小时、分钟、秒
withDayOfMonth()/withDayOfYear()/
withMonth()/withYear()
将月份天数、年份天数、月份、年份修改为指定的值并返回新的对象
plusDays(), plusWeeks(),
plusMonths(), plusYears(),plusHours()
向当前对象添加几天、几周、几个月、几年、几小时
时间线上的一个瞬时点。 这可能被用来记录应用程序中的事件时间
戳。
(1 ns = 10-9 s) 1秒 = 1000毫秒 =106微秒=109纳秒
now() 静态方法,返回默认UTC时区的Instant类的对象
Instant now = Instant.now();
System.out.println(now);
// 2021-06-08T11:22:25.183Z伦敦时间
可见我们得到的是伦敦时间,那么就要转变为北京时间,得了解世界的时区分布。
https://i.loli.net/2021/06/12/FlLirNt8xk6n1Oh.png
我们在东八区,那么就要将偏移量算上去。
atOffset(ZoneOffset offset) 结合即时的偏移来创建一个 OffsetDateTime
OffsetDateTime offsetDateTime = now.atOffset(ZoneOffset.ofHours(8));
System.out.println(offsetDateTime);
// 2021-06-08T11:28:57.438Z
// 2021-06-08T19:28:57.438+08:00
ofEpochMilli(long epochMilli) 静态方法,返回在1970-01-01 00:00:00基础上加上指定毫秒数之后的Instant类的对象
Instant instant = now.ofEpochMilli(100002L);
System.out.println(instant);
// 1970-01-01T00:01:40.002Z
toEpochMilli() 返回1970-01-01 00:00:00到当前时间的毫秒数,即为时间戳
System.out.println(now.toEpochMilli());
// 1623152010594
该类提供三种格式化:
预定义的标准格式。如:ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
该定义不会改变原来LocalDate、LocalTime、LocalDateTime的格式,只是一个标准格式,改成了字符串类型而已。
DateTimeFormatter formater=DateTimeFormatter.ISO_DATE_TIME;
LocalDateTime now = LocalDateTime.now();
// 格式化
System.out.println(now);
System.out.println(formater.format(now));
// 2021-06-08T19:45:13.776
// 2021-06-08T19:45:13.776
// 解析
System.out.println(formater.parse("2021-06-08T19:45:13.776"));
// {},ISO resolved to 2021-06-08T19:45:13.776
本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)(重点)
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
System.out.println(dateTimeFormatter.format(LocalDateTime.now()));
// 2021-06-08 07:59:00
请点击链接查看图片:https://i.loli.net/2021/06/12/VyqMbuYwozEZspG.png
ZoneId**:**该类中包含了所有的时区信息,一个时区的ID,如 Europe/Paris
ZonedDateTime**:**一个在ISO-8601日历系统时区的日期时间,如 2007-12-03T10:15:30+01:00 Europe/Paris。 其中每个时区都对应着ID,地区ID都为“{区域}/{城市}”的格式,例如:Asia/Shanghai等
Clock**:**使用时区提供对当前即时、日期和时间的访问的时钟。
持续时间:Duration,用于计算两个“时间”间隔
日期间隔:Period,用于计算两个“日期”间隔
TemporalAdjuster : 时间校正器。有时我们可能需要获取例如:将日期调整到“下一个工作日”等操作。
TemporalAdjusters : 该类通过静态方法(firstDayOfXxx()/lastDayOfXxx()/nextXxx())提供了大量的常用TemporalAdjuster 的实现。
//ZoneId:类中包含了所有的时区信息
// ZoneId的getAvailableZoneIds():获取所有的ZoneId
Set<String> zoneIds = ZoneId.getAvailableZoneIds();
for (String s : zoneIds) {
System.out.println(s);
}
// ZoneId的of():获取指定时区的时间
LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(localDateTime);
//ZonedDateTime:带时区的日期时间
// ZonedDateTime的now():获取本时区的ZonedDateTime对象
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println(zonedDateTime);
// ZonedDateTime的now(ZoneId id):获取指定时区的ZonedDateTime对象
ZonedDateTime zonedDateTime1 = ZonedDateTime.now(ZoneId.of("Asia/Tokyo"));
System.out.println(zonedDateTime1);
//9.3 JDK8中新日期时间API
//Duration:用于计算两个“时间”间隔,以秒和纳秒为基准
LocalTime localTime = LocalTime.now();
LocalTime localTime1 = LocalTime.of(15, 23, 32);
//between():静态方法,返回Duration对象,表示两个时间的间隔
Duration duration = Duration.between(localTime1, localTime);
System.out.println(duration);
System.out.println(duration.getSeconds());
System.out.println(duration.getNano());
LocalDateTime localDateTime = LocalDateTime.of(2016, 6, 12, 15, 23, 32);
LocalDateTime localDateTime1 = LocalDateTime.of(2017, 6, 12, 15, 23, 32);
Duration duration1 = Duration.between(localDateTime1, localDateTime);
System.out.println(duration1.toDays());
//Period:用于计算两个“日期”间隔,以年、月、日衡量
LocalDate localDate = LocalDate.now();
LocalDate localDate1 = LocalDate.of(2028, 3, 18);
Period period = Period.between(localDate, localDate1);
System.out.println(period);
System.out.println(period.getYears());
System.out.println(period.getMonths());
System.out.println(period.getDays());
Period period1 = period.withYears(2);
System.out.println(period1)
// TemporalAdjuster:时间校正器
// 获取当前日期的下一个周日是哪天?
TemporalAdjuster temporalAdjuster = TemporalAdjusters.next(DayOfWeek.SUNDAY);
LocalDateTime localDateTime = LocalDateTime.now().with(temporalAdjuster);
System.out.println(localDateTime);
// 获取下一个工作日是哪天?
LocalDate localDate = LocalDate.now().with(new TemporalAdjuster() {
@Override
public Temporal adjustInto(Temporal temporal) {
LocalDate date = (LocalDate) temporal;
if (date.getDayOfWeek().equals(DayOfWeek.FRIDAY)) {
return date.plusDays(3);
} else if (date.getDayOfWeek().equals(DayOfWeek.SATURDAY)) {
return date.plusDays(2);
} else {
return date.plusDays(1);
} }
});
System.out.println("下一个工作日是:" + localDate);
}
请点击链接:https://i.loli.net/2021/06/12/5FUdwORe1jMv7iY.png
Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称
为类的自然排序。
实现 Comparable 的类必须实现 compareTo(Object obj) 方法,两个对象即
通过 compareTo(Object obj) 方法的返回值来比较大小。如果当前对象this大
于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回
负整数,如果当前对象this等于形参对象obj,则返回零。
实现Comparable接口的对象列表(和数组)可以通过 Collections.sort 或
Arrays.sort进行自动排序。实现此接口的对象可以用作有序映射中的键或有
序集合中的元素,无需指定比较器。
对于类 C 的每一个 e1 和 e2 来说,当且仅当 e1.compareTo(e2) == 0 与
e1.equals(e2) 具有相同的 boolean 值时,类 C 的自然排序才叫做与 equals
一致。建议(虽然不是必需的)最好使自然排序与 equals 一致。
Comparable 的典型实现:(默认都是从小到大排列的) :
String:按照字符串中字符的Unicode值进行比较
Character:按照字符的Unicode值来进行比较
数值类型对应的包装类以及BigInteger、BigDecimal:按照它们对应的数值
大小进行比较
Boolean:true 对应的包装类实例大于 false 对应的包装类实例
Date、Time等:后面的日期时间比前面的日期时间大
class Goods implements Comparable {
private String name;
private double price;
//按照价格,比较商品的大小
@Override
public int compareTo(Object o) {
if(o instanceof Goods) {
Goods other = (Goods) o;
if (this.price > other.price) {
return 1;
} else if (this.price < other.price) {
return -1;
}
return 0;
}
throw new RuntimeException("输入的数据类型不一致");
}
//构造器、getter、setter、toString()方法略
}
public class ComparableTest{
public static void main(String[] args) {
Goods[] all = new Goods[4];
all[0] = new Goods("《红楼梦》", 100);
all[1] = new Goods("《西游记》", 80);
all[2] = new Goods("《三国演义》", 140);
all[3] = new Goods("《水浒传》", 120);
Arrays.sort(all);
System.out.println(Arrays.toString(all));
}
}
当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,
或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那
么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排
序的比较。
重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返
回正整数,则表示o1大于o2**;如果返回0,表示相等;返回负整数,表示**
o1小于o2。
可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),
从而允许在排序顺序上实现精确控制。
还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的
顺序,或者为那些没有自然顺序的对象 collection 提供排序。
Goods[] all = new Goods[4];
all[0] = new Goods("War and Peace", 100);
all[1] = new Goods("Childhood", 80);
all[2] = new Goods("Scarlet and Black", 140);
all[3] = new Goods("Notre Dame de Paris", 120);
Arrays.sort(all, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Goods g1 = (Goods) o1;
Goods g2 = (Goods) o2;
return g1.getName().compareTo(g2.getName());
}
});
System.out.println(Arrays.toString(all));
System类代表系统,系统级的很多属性和控制方法都放置在该类的内部。
该类位于java.lang包。
由于该类的构造器是private的,所以无法创建该类的对象,也就是无法实
例化该类。其内部的成员变量和成员方法都是static的,所以也可以很方便
的进行调用。
成员变量:
System类内部包含in、out和err三个成员变量,分别代表标准输入流
(键盘输入),标准输出流(显示器)和标准错误输出流(显示器)。
成员方法:
native long currentTimeMillis():该方法的作用是返回当前的计算机时间,时间的表达格式为当前计算机时
间和GMT时间(格林威治时间)1970年1月1号0时0分0秒所差的毫秒数。
void exit(int status):该方法的作用是退出程序。其中status的值为0代表正常退出,非零代表
异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等。
void gc():该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,则
取决于系统中垃圾回收算法的实现以及系统执行时的情况。
String getProperty(String key)
该方法的作用是获得系统中属性名为key的属性对应的值。系统中常见
的属性名以及属性的作用如下表所示:
https://i.loli.net/2021/06/12/tHanPeMzOKCAoSd.png
String javaVersion = System.getProperty("java.version");
System.out.println("java的version:" + javaVersion);
String javaHome = System.getProperty("java.home");
System.out.println("java的home:" + javaHome);
String osName = System.getProperty("os.name");
System.out.println("os的name:" + osName);
String osVersion = System.getProperty("os.version");
System.out.println("os的version:" + osVersion);
String userName = System.getProperty("user.name");
System.out.println("user的name:" + userName);
String userHome = System.getProperty("user.home");
System.out.println("user的home:" + userHome);
String userDir = System.getProperty("user.dir");
System.out.println("user的dir:" + userDir);
java.lang.Math提供了一系列静态方法用于科学计算。其方法的参数和返回
值类型一般为double型。
abs 绝对值
acos,asin,atan,cos,sin,tan 三角函数
sqrt 平方根
pow(double a,doble b) a的b次幂
log 自然对数
exp e为底指数
max(double a,double b)
min(double a,double b)
random() 返回0.0到*1.0的随机数
long round(double a) double型数据a转换为long型(四舍五入)
toDegrees(double angrad) 弧度—>角度
toRadians(double angdeg) 角度—>弧度
Integer类作为int的包装类,能存储的最大整型值为2 31-1,Long类也是有限的,
最大为2 63-1。如果要表示再大的整数,不管是基本数据类型还是他们的包装类
都无能为力,更不用说进行运算了。
java.math包的BigInteger****可以表示不可变的任意精度的整数。BigInteger 提供
所有 Java 的基本整数操作符的对应物,并提供 java.lang.Math 的所有相关方法。
另外,BigInteger 还提供以下运算:模算术、GCD 计算、质数测试、素数生成、
位操作以及一些其他操作。
构造器 BigInteger(String val):根据字符串构建BigInteger对象
常用方法:
public BigInteger abs():返回此 BigInteger 的绝对值的 BigInteger。
BigInteger add(BigInteger val) :返回其值为 (this + val) 的 BigInteger
BigInteger subtract(BigInteger val) :返回其值为 (this - val) 的 BigInteger
BigInteger multiply(BigInteger val) :返回其值为 (this * val) 的 BigInteger
BigInteger divide(BigInteger val) :返回其值为 (this / val) 的 BigInteger。整数
相除只保留整数部分。
BigInteger remainder(BigInteger val) :返回其值为 (this % val) 的 BigInteger。
BigInteger[] divideAndRemainder(BigInteger val):返回包含 (this / val) 后跟
(this % val) 的两个 BigInteger 的数组。
BigInteger pow(int exponent) :返回其值为 (thisexponent) 的 BigInteger。
一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,
要求数字精度比较高,故用到java.math.BigDecimal类。
BigDecimal类支持不可变的、任意精度的有符号十进制定点数。
构造器
public BigDecimal(double val)
public BigDecimal(String val)
常用方法
public BigDecimal add(BigDecimal augend)
public BigDecimal subtract(BigDecimal subtrahend)
public BigDecimal multiply(BigDecimal multiplicand)
public BigDecimal divide(BigDecimal divisor, int scale, int roundingMode)
public void testBigInteger() {
BigInteger bi = new BigInteger("12433241123");
BigDecimal bd = new BigDecimal("12435.351");
BigDecimal bd2 = new BigDecimal("11");
System.out.println(bi);
// System.out.println(bd.divide(bd2));
System.out.println(bd.divide(bd2, BigDecimal.ROUND_HALF_UP));
System.out.println(bd.divide(bd2, 15, BigDecimal.ROUND_HALF_UP));
}