字符串常量池
深入了解字符串常量池
字符串常量池中存在一个StringTable,是一个HashTable,key是根据String实例的值和长度计算生成的hash,value存放了对String实例的引用,注意,是引用,而不是实例,StringTable中只有引用
String的不可变性
很多人只答String的存值是用private final byte[] value,这样是不够的,因为只是引用型变量value指向的数组首地址被固定,不允许它指向其他地址,数组内的内容可以变呀。所以应当加上下述:
- 首先,byte数组是private的,并且 String类没有对外提供修改这个数组的方法,所以它初始化之后外界没有有效的手段去改变它
- 其次,String类被final修饰的,也就是不可继承,避免被他人继承后破坏
- 最重要的是因为Java作者在String的所有方法里面,都很小心地避免去修改了byte数组中的数据,涉及到对byte数组中数据进行修改的操作全部都会重新创建一个String对象
为什么String设计成不可变的
- 从内存角度,对于某个常量池中已有的字符串,多个引用变量指向它时,如果是可变的,改变一个就会导致其他引用值的错误,这是很危险的
- String不可变保证了hashcode的相同,因此对于某些集合比如HashSet、HashMap等就可以直接比较hashcode而不是调用equals方法
- 方便其他类的使用,如Set等
- 不可变保证了线程安全,令String可以在多个线程间自由共享
String常用方法
String和StringBuilder和StringBuffer区别
String拼接
public class Test {
public static void main(String[] args) {
String s1 = "s1";
String s2 = "s2";
String s3 = "s1s2";
String s4 = "s1" + "s2";
String s5 = s1 + "s2";
String s6 = "s1" + s2;
System.out.println(s3 == s4); // true
System.out.println(s3 == s5); // false
System.out.println(s3 == s6); // false
System.out.println(s5 == s6); // false
}
}
intern案例
//案例1
public class Test {
public static void main(String[] args) {
String s1 = "s1";
String s2 = s1 + "s2";
String s3 = "s1s2";
System.out.println(s2 == s2.intern());
}
}
//案例2
public class Test {
public static void main(String[] args) {
String s1 = "s1";
String s2 = s1 + "s2";
System.out.println(s2 == s2.intern());
String s3 = "s1s2";
}
}
String和StringBuilder和StringBuffer区别
- String:不可变字符序列
- StringBuffer:线程安全的可变字符序列,内部使用同步方法,效率不如StringBuilder
- StringBuilder:线程不安全的可变字符序列
常用时间API
JDK8之前
SimpleDateFormat
SimpleDateFormat date=new SimpleDateFormat("yyyy-mm-dd hh:mm:ss");
System.out.println(date.format(new Date()));//格式化DATE为字符串
System.out.println(date.parse("2022-03-16 15:06:00"));//解析字符串为DATE
Calendar
Calendar calendar = Calendar.getInstance();
// 或者
calendar = new GregorianCalendar();
calendar.setTime(new Date()); // 根据Date设置calendar
System.out.println(calendar.getTime()); // 获取Date
System.out.println(calendar.get(Calendar.DAY_OF_WEEK));//周几
// 注意,周日显示是1,周一是2,...,周六是7
System.out.println(calendar.get(Calendar.MONTH));//几月
// 注意,从0开始,一月显示是0
calendar.add(Calendar.MINUTE, 1); // 日期运算
Calendar不太好用:Calendar会有一个偏移量,容易弄乱,也无法保证线程安全
JDK8之后
LocalDate、LocalTime、LocalDateTime
初始化
LocalDate date = LocalDate.now(); // 2021-05-11
LocalTime time = LocalTime.now(); // 01:03:01.135762600
LocalDateTime dateTime = LocalDateTime.now(); // 2021-05-11T01:03:01.135762600
LocalDateTime dateTime = LocalDateTime.of(2020, 05, 20, 13, 14); // 2020-05-20T13:14
获取时间
LocalDateTime dateTime = LocalDateTime.of(2020, 05, 20, 13, 14);
System.out.println(dateTime.getDayOfWeek()); // WEDNESDAY
System.out.println(dateTime.getDayOfWeek().getValue()); // 3
System.out.println(dateTime.getDayOfMonth()); // 20
System.out.println(dateTime.getDayOfYear()); // 141
System.out.println(dateTime.getMonth()); // May
System.out.println(dateTime.getMonthValue()); // 5
设置时间
LocalDateTime dateTime = LocalDateTime.of(2020, 05, 20, 13, 14);
System.out.println(dateTime); // 2020-05-20T13:14
System.out.println(dateTime.withDayOfMonth(21)); // 2020-05-21T13:14
// 与Calendar不同,这里是直接返回一个新对象,体现了不可变性
时间运算
LocalDateTime dateTime = LocalDateTime.of(2020, 05, 20, 13, 14);
System.out.println(dateTime); // 2020-05-20T13:14
System.out.println(dateTime.plusDays(1)); // 2020-05-21T13:14
Instant:瞬时(时间戳)
初始化:
Instant instant = Instant.now(); // UTC时间
System.out.println(instant); // 2021-05-10T17:25:13.423739400Z
// 注意,我们是东八区,所以这里的值是我们的北京时间减8小时,是伦敦的本初子午线时间
可以按实际情况添加偏移量
Instant instant = Instant.now();
System.out.println(instant.atOffset(ZoneOffset.ofHours(8)));
// 2021-05-11T01:32:21.631253700+08:00
起始于1970年1月1日0时0分0秒的毫秒数及转换
Instant instant = Instant.now();
long millis = instant.toEpochMilli();
Instant instant1 = Instant.ofEpochMilli(millis);
DateTimeFormatter
转换
// 自带的枚举
LocalDateTime localDateTime = LocalDateTime.now();
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
System.out.println(formatter.format(localDateTime));
// 2021-05-11T01:48:11.8582478
//----------------------------------------------------------------------------
// ofLocalizedDateTime
formatter = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
System.out.println(formatter.format(localDateTime));
// 2021/5/11 上午1:48
formatter = DateTimeFormatter
.ofLocalizedDateTime(FormatStyle.LONG)
.withZone(ZoneOffset.ofHours(8));
System.out.println(formatter.format(localDateTime));
// 2021年5月11日 +08:00 上午1:49:47
//----------------------------------------------------------------------------
// 自定义
formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
System.out.println(formatter.format(localDateTime));
// 2021-05-11 01:55:19
// 解析
TemporalAccessor accessor = formatter.parse("2021-05-11 01:59:59");
System.out.println(accessor);
/* {HourOfAmPm=1, MinuteOfHour=59, SecondOfMinute=59, NanoOfSecond=0, MilliOfSecond=0, MicroOfSecond=0},ISO resolved to 2021-05-11
*/