Java常用类
String类
- 概述
- String类:代表字符串。Java程序中的所有字符串字面值(如:”abc“)都作为子类的实例实现
- String是一个final类,代表不可变的字符序列
- 字符串是常量,用双引号引起来表示。他们的值在创建之后不能更改
- String对象的字符内容是存储在一个字符数组value[]中的
public final class String
implements java.io.Serializable,Comparable<String>,CharSequence{
/** The value is used for character storage*/
private final char value[]; //String 的底层就是放在char型数组当中(字符构成的串) //final:value是引用类型 其指向的地址不可以被修改
/*Cache the hash code for the string*/
private int hash; //Default to 0
}
/*
String:字符串:使用一对“”引起来表示
1. String声明为final的,不可被继承
2. String
实现了Serializable接口:表示字符串是可序列化的
(对象默认不可以通过网络传输,但是如果是可序列化的,那么就可以通过网络传输给对方 IO流部分知识)
实现了Comparable接口,表示String是可以比较大小的
3. String在内部定义了final的char型数组:final char value[] value用与存储字符串数据
4. 通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
5. 字符串常量池中是不会存储相同内容的字符串的
*/
- String不可变性
- 说明以及代码
/*4. final:数组引用变量不能在指向别的数组,且数组对象内的元素也不能改变
即const int* const p; p是常量指针,且不能通过p对所指向的变量进行修改
体现
1)当对字符串重新赋值是,需要重写指定内存区域赋值,不能使用原有的value进行赋值
2) 当对现有的字符串进行连接操作时,也需要重新制定内存区域赋值,不能使用原有的字符串*/
@Test
public void test(){
String s1 = "abc";//字面量的定义方式
String s2 = "abc";
System.out.println(s1==s2);//true
// s1="hello";
String s3 = "abc";
s3+="def";//并没有改变“abc” 而是新造了一个
System.out.println(s3); //abcdef 并没有改变“abc” 而是新造了一个
System.out.println(s2);//abc
System.out.println("******************");
String s4 = "abc";
String s5 = s4.replace('a','z');
System.out.println(s5);
System.out.println(s4);
System.out.println(s2);
}
//String 实例化的方式
// 方式一:通过字面量定义的方式
// 方式二:通过new+构造器的方式
@Test
public void test2(){
//通过字面量的方式 这个abc声明在方法区的字符串常量池种
String s1 = "abc";
String s2 = "abc";
//通过new+构造器的方式:此时的s3,s4保存的地址值,是数据在堆空间中开辟空间以后堆空间中地址值
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1==s2); //true
System.out.println(s1==s3); //false
System.out.println(s3==s2); //false
System.out.println("********************");
Person p1 = new Person("shc");
Person p2 = new Person("shc");
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name==p2.name);//true 因为在Person的对象中,生成String字符串的方式也是通过字面量 this.name="shc"
//如果在Peron的构造器中用this.name=new String("shc"); 的方式,那么就是false
}
面试题:
面试题:!!!常考 String s = new String("abc"); 方式创建对象,在内存中创建了几个对象 两个:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:"abc";
- 字符串拼接方式的对比
/*
1. 常量与与常量的拼接结果在常量池中,且常量池中不会存在相同内容的常量
2. 只要其中有一个是变量,结果就在堆中
3. 如果拼接的结果调用intern()方法,返回值就在常量池中
*/
@Test
public void test3(){
String s1 = "abc";
String s2 = "hhh";
String s3 = "abchhh"; //字面量
String s4 = "abc"+"hhh"; //两个字面量的连接 还是字面量 在常量池中
String s5 = s1+"hhh";
String s6 = "abc" + s2;
String s7 = s1+s2;
System.out.println(s3==s4); //true
System.out.println(s3==s5); //false
System.out.println(s3==s6); //false
System.out.println(s3==s7); //false
System.out.println(s5==s6); //false
System.out.println(s5==s7); //false
System.out.println(s6==s7); //false
String s = s5.intern();
System.out.println(s==s3);//true
}
- String用方法
/**
* int length():返回字符串的长度: return value.length
* char charAt(int index): 返回某索引处的字符return value[index]
* boolean isEmpty():判断是否是空字符串:return value.length == 0
* String toLowerCase():使用默认语言环境,将 String 中的所有字符转换为小写
* String toUpperCase():使用默认语言环境,将 String 中的所有字符转换为大写
* String trim():返回字符串的副本,忽略前导空白和尾部空白
* boolean equals(Object obj):比较字符串的内容是否相同
* boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
* String concat(String str):将指定字符串连接到此字符串的结尾。 等价于用“+”
* int compareTo(String anotherString):比较两个字符串的大小
* String substring(int beginIndex):返回一个新的字符串,它是此字符串的从
* beginIndex开始截取到最后的一个子字符串。
* String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字
* 符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
*
* boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束
* boolean startsWith(String prefix):测试此字符串是否以指定的前缀开始
* boolean startsWith(String prefix, int toffset):测试此字符串从指定索引开始的
* 子字符串是否以指定前缀开始
*
* boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true
* int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
* int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出
* 现处的索引,从指定的索引开始
* int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
* int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
* 注:indexOf和lastIndexOf方法如果未找到都是返回-1
*
* String replace(char oldChar, char newChar):返回一个新的字符串,它是
* 通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
* String replace(CharSequence target, CharSequence replacement):使
* 用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
* String replaceAll(String regex, String replacement) : 使 用 给 定 的
* replacement 替换此字符串所有匹配给定的正则表达式的子字符串。
* String replaceFirst(String regex, String replacement) : 使 用 给 定 的
* replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
*
* boolean matches(String regex):告知此字符串是否匹配给定的正则表达式
*
* String[] split(String regex):根据给定正则表达式的匹配拆分此字符串。
* String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此
* 字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。
* @author shc
* @create 2021-05-20 15:06
*/
- String与其他结构的转换
- 与基本数据类型,包装类之间的转换
/*
String与基本数据类型,包装类之间的转换
String --> 基本数据类型,包装类 :调用基本数据类型的 parseXxx(str);
基本数据类型,包装类 ---> String :调用String类重载的valueOf(xxx); 或者直接+""
*/
@Test
public void test(){
String str = "123";
// int num = (int) str; //必须是子父类的关系才可以强转
int num = Integer.parseInt(str); //注意str中不能有数字 否则NumberFormatException
System.out.println(num);
String str1 = String.valueOf(num);
String str2 = num+"";
System.out.println(str1+" "+str2);
}
String与字符数组之间的转换
/*
String与char[]之间的转换
String -->char[] 调用String的toCharArray()
char[] -->String 调用String的构造器
*/
@Test
public void test2(){
String str1 = "abc123";
char[] charArray = str1.toCharArray();
for(int i=0;i<charArray.length;i++){
System.out.print(charArray[i]+" ");
}
char[] arr = new char[]{'h','e','l','l','o'};
String str = new String(arr);
System.out.println(str);
}
String与字节数组之间的转换
/*
String与byte[]之间的转换
编码:String --> byte[]:调用String的getBytes()
解码:byte[] --> String
编码:字符串 --> 字节 (看得懂 --> 看不懂)
解码:编码的逆过程 字节 --> 字符串 (看不懂的二进制 --> 看得懂)
说明:要求编码时使用的字符集和解码时使用的字符集必须一致
*/
@Test
public void test3() throws UnsupportedEncodingException {
String str1 = "abc123中国";
byte[] bytes = str1.getBytes();//使用默认的字符集。进行转换
System.out.println(Arrays.toString(bytes));
byte[] gbks = str1.getBytes("gbk");//使用gbk字符集进行编码
System.out.println(str1);
System.out.println(Arrays.toString(gbks));
System.out.println("****************");
String str2 = new String(bytes);//使用默认字符集进行解码
System.out.println(str2);
String gbks1 = new String(gbks);
System.out.println(gbks1);//乱码
}
与StringBuilder,StringBuffer之间的转换
String --> StringBuffer、StringBuilder:调用StringBuffer、StringBuilder构造器
StringBuffer、StringBuilder --> String:
①调用String构造器
②StringBuffer、StringBuilder的toString()
/*
String、StringBuilder、StringBuffer三者异同?
String:不可变的字符序列 ,char型数组存储
StringBuffer:可变的字符序列:线程安全,效率偏低,char型数组存储
StringBuilder:可变的字符序列:jdk5.0新增 线程不安全,效率高,char型数组存储
三者效率:StringBuilder > StringBuffer > String
源码分析:
String str = new String(); //char[] value = new char[0];
String str1 = new String("abc);//char[] value = new char[]={'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];//底层创建了一个长度为16的字符串数组
sb1.append('a');//value[0]='a';
sb1.append('b');//value[1]='b';
StringBuffer sb2 = new String("abc"); //char[] value = new char["abc".length()+16];
QUESTION 1:sout(sb2.length()); //"abc".length;
2:扩容问题:如果要添加的数据底层数组撑不下了,就要扩容底层的数组
默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。
指导意义:开发中建议大家使用:StringBuffer(int capacity)或者(StringBuilder(int capacity) 尽量避免扩容,影响效率
*/
@Test
public void test(){
StringBuffer str1 = new StringBuffer("abc");
str1.setCharAt(0,'n');
System.out.println(str1);
}
JVM中字符常量池存放位置说明:
- jdk 1.6(jdk 6.0,java 6.0):字符串常量池储存在方法区(永久区)
- jdk 1.7:字符串常量池存储在堆空间
- jdk 1.8:字符
StringBuilder,StringBuffer
public class StringBuilderBufferTest {
/*
String、StringBuilder、StringBuffer三者异同?
String:不可变的字符序列 ,char型数组存储
StringBuffer:可变的字符序列:线程安全,效率偏低,char型数组存储
StringBuilder:可变的字符序列:jdk5.0新增 线程不安全,效率高,char型数组存储
三者效率:StringBuilder > StringBuffer > String
源码分析:
String str = new String(); //char[] value = new char[0];
String str1 = new String("abc);//char[] value = new char[]={'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char[] value = new char[16];//底层创建了一个长度为16的字符串数组
sb1.append('a');//value[0]='a';
sb1.append('b');//value[1]='b';
StringBuffer sb2 = new String("abc"); //char[] value = new char["abc".length()+16];
QUESTION 1:sout(sb2.length()); //"abc".length;
2:扩容问题:如果要添加的数据底层数组撑不下了,就要扩容底层的数组
默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。
指导意义:开发中建议大家使用:StringBuffer(int capacity)或者(StringBuilder(int capacity) 尽量避免扩容,影响效率
*/
@Test
public void test(){
StringBuffer str1 = new StringBuffer("abc");
str1.setCharAt(0,'n');
System.out.println(str1);
}
}
/*
* StringBuffer类不同于String,其对象必须使用构造器生成。有三个构造器:
StringBuffer():初始容量为16的字符串缓冲区
StringBuffer(int size):构造指定容量的字符串缓冲区
StringBuffer(String str):将内容初始化为指定字符串内容
常用方法
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 int indexOf(String str)
public String substring(int start,int end)
public int length()
public char charAt(int n )
public void setCharAt(int n ,char ch)
*
* 总结
* 增 append(x)
* 删 delete(int start,int end)
* 改 setCharAt(int n,char ch) / repalce(int start,int end,String str)
* 查 charAt(int n)
* 插 insert(int offset,xxx)
* 长度 length()
* 遍历 for()+charAt() / toString()
*
*/
面试题
JDK8之前的时间API
获取当前系统时间java.lang.System类中的currentTimeMillis()
long time = System.currentTimeMillis();
//返回时间为当前时间与1970年1月1日00:00之间以ms为单位的时间差,称为时间戳
System.out.println(time);
//1621602510493
java.util.Date
与java.sql.Date
java.sql.Date extends java.util.Date
/*
2. java.util.Date类
① 两个构造器的使用
>构造器一:Date()创建一个对应当前时间的Date对象
>构造器二:创建指定毫秒数(指定时间戳)的Date对象
② 两个方法的使用
>toString():显示当前的年、月、日、时、分、秒
>getTime();获取当前Date对象的时间戳
③ java.sql.Date类 extends java.util.Date
>如何实例化
>如何将java.util.Date对象转化为java.sql.Date对象
*/
@Test
public void test2(){
//构造器一:Date()创建一个对应当前时间的Date对象
Date date1 = new Date();
System.out.println(date1.toString());//Fri May 21 21:07:33 CST 2021
System.out.println(date1.getTime());//1621602495849
//构造器二:创建指定毫秒数的Date对象
Date date2 = new Date(1621602495849L);
System.out.println(date2.toString());//FriMay 21 21:08:15 CST 2021
//或者直接date2也一样,因为sout就是会调用toString啊。
//这可不是把Date类对象转化成String类对象了!!!!!!!
System.out.println("*****************");
//创建java.sql.Date对象
java.sql.Date date3 = new java.sql.Date(323156136L);
System.out.println(date3);//1970-01-05
//如何将java.util.Date对象转化为java.sql.Date对象
//情况1:(Java多态)
Date date4 = new java.sql.Date(1235346456L);
java.sql.Date date5 = (java.sql.Date)date4;
//情况2:
Date date6 = new Date();
java.sql.Date date7 = new java.sql.Date(date6.getTime());
//而不能是java.sql.Date date7 = (java.sql.Date)date6;
}
java.text.SimpleDateFormat
类
用处:SimpleDateFormat对日期Date类的 格式化和 解析(Date里还有很多方法被@Deprecated了)(JDK8建议用Calendar)
- (1)两个操作
- 1.1: 格式化:日期(Date) --> 字符串(String)
- 1.2: 解析:格式化的逆过程:字符串(String) --> 日期(Date)
- (2)SimpleDateFormat的实例化:new+构造器.
- 基本操作
//1. 实例化SimpleDateFormat
SimpleDateFormat sdf = new SimpleDateFormat();
//2. 格式化:日期 (Date)--> 字符串(String)
Date date = new Date(); //Date()创建一个对应当前时间的Date对象
System.out.println(date);// Sat May 22 19:50:32 CST 2021
String format = sdf.format(date); // SimpleDateFormat对Date进行解析,获得字符串:21-5-22 下午7:50
System.out.println(format); // 输出解析后得到的字符串 21-5-22 下午7:50
//解析:格式化的逆过程。字符串(String) ---> 日期(Date)
String str = "21-5-22 下午7:49";
Date date1 = sdf.parse(str);//可能导致编译异常原因:字符串格式不对
System.out.println(date1);//Sat May 22 19:49:00 CST 2021
(3)以下为开发中主要方式 --> 按照指定方式格式化和解析 :调用带参构造器
//开发中通常不用默认构造器,而是用指定的构造器来确定格式化方式
//SimpleDateFormat sdf2 = new SimpleDateFormat("yyyyy.MMMMM.dd GGG hh:mm aaa");
//年 yyyy -- 月 MM (大写是为了和分钟mm区分开) -- 天 dd -- 时 hh -- 分钟 mm -- 秒 ss
//1. 实例化
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd ---- hh:mm:ss");
//2. 格式化
String format2 = sdf2.format(date);//以我们制定的yyyy-MM-dd ---- hh:mm:ss格式来进行转化
System.out.println(format2);//2021-05-23 ---- 01:22:21
//3. 解析:
//要求字符串必须是符合SimpleDateFormat识别的格式(通过构造器参数体现),否则就会抛出异常
Date date2 = sdf2.parse("2021-05-23 ---- 01:22:21");
System.out.println(date2);//Sun May 23 01:22:21 CST 2021
Calendar类:日历类,抽象类
/*
Calendar日历类(抽象类)的使用
*/
@Test
public void testCalendar(){
//1.实例化
//方式一:创建其子类(GregorianCalendar)的对象
//方式二:调用其静态方法getInstance();
Calendar calendar = Calendar.getInstance();
System.out.println(calendar.getClass());//class java.util.GregorianCalendar
//2.常用方法
//get()
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//23
System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//143
//set()
//Calendar劣势:可变性
calendar.set(Calendar.DAY_OF_MONTH,7);//void set() 把Calendar本身给改了
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//7
//add()
calendar.add(Calendar.DAY_OF_MONTH,-3);//4
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));
//getTime():日历类 ---> Date
Date date = calendar.getTime();
System.out.println(date);//Tue May 04 13:45:07 CST 2021
System.out.println("****************");
//setTime():Date --> 日历类
Date date1 = new Date();
calendar.setTime(date1);
System.out.println(calendar.get(Calendar.DAY_OF_MONTH));//23
- JDK8中新的API
- 日期时间API的迭代
- 第一代:jdk 1.0 Date类
- 第二代:jdk 1.1 Calendar类,一定程度上替换Date类
- 第三代:jdk1.8提出了新的一套API(最终版)
- 前两代存在的问题
- 可变性:像日期和时间这样的类应该是不可变的。
- 偏移性:Date中的年份是从1900开始的,而月份都从0开始。
- 格式化:格式化只对Date有用,Calendar则不行。
- 此外,它们也不是线程安全的;不能处理闰秒等。
本地日期、本地时间、本地日期时间的使用:LocalDate、LocalTime、LocalDateTime
- 说明:
- LocalDate代表IOS格式(yyyy-MM-dd)的日期,可以存储 生日、纪念日等日期。
- LocalTime表示一个时间,而不是日期。
- LocalDateTime是用来表示日期和时间的,这是一个最常用的类之一。
- 常用方法:
时间点:Instant
- 说明:
- Instant表示时间线上的一点,而不需要任何上下文信息,例如,时区。 概念上讲,它只是简单的表示自1970年1月1日0时0分0秒(UTC)开始的秒 数。
- 类似于java.util.Date类
- 常用方法
- 日期时间格式化类:DateTimeFormatter
说明
- 格式化、解析日期,时间
- 类似于SimpleDateFormat
常用方法
- 实例化方法
- 预定义的标准格式。如: ISO_LOCAL_DATE_TIME;ISO_LOCAL_DATE;ISO_LOCAL_TIME
- 本地化相关的格式。如:ofLocalizedDateTime(FormatStyle.LONG)
- 自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
- 常用方法:
特别的,自定义格式,如:如:ofPattern(“yyyy-MM-dd hh:mm:ss”)*
//方式三:自定义的格式。如:ofPattern(“yyyy-MM-dd hh:mm:ss”)
DateTimeFormatter formatter3 = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//格式化
String str4 = formatter3.format(LocalDateTime.now());
System.out.println(str4);//2021-05-22 11:07:16
//解析:
TemporalAccessor accessor = formatter3.parse("2021-05-22 03:06:09");
System.out.println(accessor);
//{NanoOfSecond=0, MilliOfSecond=0, MinuteOfHour=6, SecondOfMinute=9, MicroOfSecond=0, HourOfAmPm=3},ISO resolved to 2021-05-22
}
其他常用类
package com.shc.java1;
import org.junit.Test;
import java.math.BigDecimal;
import java.math.BigInteger;
/**
* 1. System
* 2. Math
* 3. BigInteger BigDecimal
* @author shc
* @create 2021-05-23 12:29
*/
public class OtherTest {
@Test
public void test1(){
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);
}
@Test
public void test2(){
BigInteger bi = new BigInteger("12433241123");
BigDecimal bd = new BigDecimal("12435.351");
BigDecimal bd2 = new BigDecimal("10");
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, 20, BigDecimal.ROUND_HALF_UP)); //scale:小数位位数 支持任意精度的小数位
}
}
Java比较器·
引入
* 说明:Java中的对象中,正常情况下,只能进行比较:== 或者 != 不能使用>或者<的
* 但是在开发场景中,我们需要对多个对象进行排序,言外之意,就是要比较对象的大小
* 如何实现? 使用两个接口中的任何一个:Comparable 或 Compare任意一个
自然排序Comparable
说明
/*
Comparable接口使用举例:自然排序
1. 像String、包装类等实现了Comparable接口,重写compareTo()方法,给出比较两个对象大小的方式
2. 像String、包装类重写了compareTo方法以后,进行了从小到大的排列
3. 重写compareTo()的规则
如果当前对象this大于形参对象obj,则返回正整数,
如果当前对象this小于形参对象obj,则返回负整数,
如果当前对象this等于形参对象obj,则返回零。
4. 对于自定义类来说,如果需要排序,我们可以自定义类实现Comparable接口,重写compareTo方法,
在compareTo(obj)指明如何排序。
*/
代码举例
/**
* 商品类
* @author shc
* @create 2021-05-23 10:57
*/
public class Goods implements Comparable{
private String name;
private double price;
//指明商品比较方式,先按照价格递增,再按照名字递增
@Override
public int compareTo(Object o){
System.out.println("==================");
if(o instanceof Goods){
Goods good = (Goods) o;
if(good.price<this.price){
return 1;
}else if(good.price>this.price){
return -1;
}else{
return this.name.compareTo(good.name); //再按照名字排序
// return 0;
}
//方式二
// return Double.compare(this.price,((Goods)o).price);
}
throw new RuntimeException("传入数据类型不一致错误");
}
}
@Test
public void test2(){
Goods[] goods = new Goods[5];
int x = goods.length;
System.out.println(goods.length);//5 是数组本身的长度
goods[0] = new Goods("shubiao",12);
goods[1] = new Goods("diannao",78);
goods[2] = new Goods("erji",10);
goods[3] = new Goods("xianshiqi",1);
goods[4] = new Goods("xian",1);
Arrays.sort(goods,0,goods.length);
for(int i=0;i<goods.length;i++){
System.out.println(goods[i]);
}
}
/*sort方法时回调用compareTo*/
==================
==================
==================
==================
==================
==================
==================
==================
==================
Goods{name='xian', price=1.0}
Goods{name='xianshiqi', price=1.0}
Goods{name='erji', price=10.0}
Goods{name='shubiao', price=12.0}
Goods{name='diannao', price=78.0}
定制排序 Comparator
引入
- 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码, 或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序,强行对多个对象进行整体排 序的比较。
- 重写compare(Object o1,Object o2)方法,比较o1和o2的大小:如果方法返 回正整数,则表示o1大于o2;如果返回0,表示相等;返回负整数,表示 o1小于o2。 l 可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort), 从而允许在排序顺序上实现精确控制。
- 还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的 顺序,或者为那些没有自然顺序的对象 collection 提供排序。
- 代码
Arrays.sort(goods,new Comparator(){//接口可以new吗?
@Override
public int compare(Object o1,Object o2){
if(o1 instanceof Goods && o2 instanceof Goods){
Goods g1 = (Goods) o1;
Goods g2 = (Goods) o2;
if(g1.getName().equals(g2.getName())){//名字相同时 按照价格递减
return -Double.compare(g1.getPrice(),g2.getPrice());
}else{
return g1.getName().compareTo(g2.getName());
}
}
throw new RuntimeException(o1+"输入数据类型错误");
//如果有一个数组元素为空的话也会走到这里 因为null instanceof Goods 为false 不会进入if
//如果用的是o1.toString()的话则会是NullPointerException 因为在throwRuntimeException的时候会走到toString()这一步 而null调用toString()则是空指针异常
}
});
两种排序方式对比
/* 二、Comparable接口与Comparator的使用的对比
* Comparable接口的方式一旦设定,保证了Comparable接口实现类的对象在任意位置都可以比较大小
* Comparator接口属于临时性的比较
*/
每日一考
画出如下几行代码的内容结构
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
s1+="world"; <---> s1 = s1+"hello"; 右则有变量s1参与,所以拼接结果在堆中
- 如何理解String类的不可变性
- String类是否可以被继承?为什么?
- String、StringBuffer、StringBuilder三者对比
- String的常用方法有哪些?(至少7个)
length()/charAt()/equals()/compareTo()...
- 每日一考将字符串“2017-08-16”转化为对应的java.sql.Date类的对象(把页面传入的字符串存入数据库中)(是一个解析过程) //其实也可以直接塞进去(但我们一定要会手动转化)
- 字符串-->java.util.Date date --> longms时间戳- -->java.sql.Date
SimpleDateFormat
SimpleDateFormat sdf = new SimpleDateFormat("yyyy--MM--dd");
// 解析(字符串String-->日期Date):
java.util.Date utilDate = sdf.parse("2021-02-23");
// 再用date来getTime()(返回的是longms),再放入构造器中
java.sql.Date sqlDate = new java.sql.Date(utilDate.getTime());
DateTimeFormatter
DateTimeFormatterdtf = DateTimeFormatter.ofPattern("yyyy-MM-dd");
..............
实例化方式:
new +构造器
单例模式(private构造器)
Calendar.getInstance()//Calendar是一个抽象类,获取的是他的子类(private构造器)
解释何为编码?解码?何为日期时间的格式化,解析?
编码:字符串 -> 字节
解码:字节 -> 字符串
格式化(format):日期 ->字符串
解析(parse):字符串 -> 日期
自定义Person类如下,如何实现自然排序?(按照名字从小到大)
class Person implements Comparable{
private String name;
@Override
public int compareTo(Object o){
if(o instanceof Person){
Person p = (Person) o;
return this.name.compareTo(p.name);
}
throw new Exception("");
}
}
提供定制排序涉及到的接口的实现类对象,并按Person类的年龄从大到小排序
Comparator cp = new Comparator(){
@Override
public int compare(Object obj1,Object obj2){
if(..)
}
}
JDK8 之前和 JDK8 中与日期、时间相关的类分别有哪些?
JDK8之前 JDK8
java.util.Date 和 java.sql.Date ---> instant (本初子午线的时间)
SimpleDateFormat --->DateTimeFormatter
Calendar --->LocalDate,LocalTime,LocalDateTime
IDEA常识
- 如何删除Module?
- Remove ---然后-- > Delete
- 如何导入Module?
- File--->ProjectStructure--->'+'--->导入
- IDEA生成构造器
- Alt+insert
- 快速查询当前类中某个方法
- ctrl+F12 再输入方法名
- 快速查询某个类
- double shift
总结
这篇文章就到这里了,希望能给大家带来帮助,也希望您能多多关注三水点靠木的更多内容!
Java常用工具类汇总 附示例代码
- Author -
咕噜辰声明:登载此文出于传递更多信息之目的,并不意味着赞同其观点或证实其描述。
Reply on: @reply_date@
@reply_contents@