常用类与基础API
String(JDK8)
String类的结构
- 类的声明
public final class String implements java.io.Serializable,Comparable<String>,CharSequence
- final:String是不可被继承的
- Serializable:可序列化的接口。凡是实现此接口的类的对象就可以通过网络或本地流进行数据的传输
- Comparable:凡是实现此接口的类,其对象都可以比较大小
- 内部声明的属性
private final char value[]
- final:指明此value数组一旦初始化,其地址就不可变。
- 所以,在进行字符串拼接的时候是开辟了新的内存空间
- 字符串常量的存储位置
- 字符串常量池(StringTable)
- 字符串常量池中不会有相同的常量
- jdk7之前在方法区,之后在堆空间
- String的创建
String s1 = "hello";
String s2 = new String("hello");
- 通过双引号直接创建的字符串会存储在字符串常量池中
- 通过new关键字创建的字符串对象则会存储在堆内存中
- 当你使用双引号直接创建字符串时,如果字符串常量池中已经存在相同内容的字符串,Java会直接返回常量池中的引用,而不会创建新的对象。这意味着如果你再次使用相同内容的双引号创建字符串,实际上你得到的是同一个对象的引用。
- 通过new关键字创建的字符串对象每次都会创建一个新的对象,即使内容相同也会在堆内存中创建一个新的对象,
- 变量s1中存放的是在字符串常量池中存放有"hello"地址空间的地址,变量s2中同样的是存放指向"hello"地址空间的地址,但是由于是new出来的创建了新的地址对象,在堆中,故s1存放地址与s2存放地址不同,但是二者存放地址指向的那个存储空间中存放的地址是相同的即为常量"hello"的地址
- 用c语言描述:s1 != s2, *s1 == *s2, s1 == “h” , s2 == “h”(c语言中指针指向的是字符串第一个字符的地址)
- String的拼接
- 常量+常量:结果仍然在常量池中
- 常量+变量:会通过new的方式创建一个新的字符串,返回堆空间中此字符串对象的地址
- 调用字符串intern():返回的是字符串常量池中字面量的地址
String类的常用方法
- length():返回字符串的长度。
- charAt(int index):返回指定索引处的字符。
- toUpperCase():将字符串转换为大写。
- toLowerCase():将字符串转换为小写。
- equals(Object obj):比较字符串是否相等。
- equalsIgnoreCase(String anotherString):忽略大小写比较字符串是否相等。
- indexOf(int ch):返回指定字符第一次出现的索引。
- substring(int beginIndex):返回从指定索引开始到字符串末尾的子字符串。
- substring(int beginIndex, int endIndex):返回从指定起始索引到结束索引的子字符串。
- startsWith(String prefix):检查字符串是否以指定的前缀开始。
- endsWith(String suffix):检查字符串是否以指定的后缀结束。
- trim():去除字符串首尾的空格。
- replace(char oldChar, char newChar):替换字符串中的字符。
- replaceAll(String regex, String replacement):使用给定的替换替换与给定的正则表达式匹配的所有子字符串。
- split(String regex):根据给定正则表达式拆分字符串。
String类的特性
- 不可变性(Immutability):
- String对象一旦被创建就不能被修改。任何修改String的操作实际上都是创建一个新的String对象。这种特性使得String在多线程环境下更安全,也有利于字符串共享。
- 字符串池(String Pool):
- Java中的字符串池是一个存储字符串的特殊内存区域,用来节省内存和提高性能。当创建一个字符串时,如果字符串池中已经存在相同内容的字符串,则会直接返回引用,而不会创建新的对象。
- String常量池(String Constant Pool):
- 这是字符串池的一部分,用于存储编译时期确定的字符串常量。例如,直接使用双引号定义的字符串常量会被放入String常量池。
- StringBuilder和StringBuffer:
- 这两个类用于处理可变的字符串。StringBuilder是非线程安全的,适合单线程环境下使用;而StringBuffer是线程安全的,适合多线程环境下使用。它们提供了修改字符串内容的方法,避免了频繁创建新的String对象。
- 字符串连接性能优化:
- 在Java中,使用加号(+)连接字符串时会创建大量临时对象,影响性能。为了优化性能,可以使用StringBuilder或StringBuffer的append方法进行字符串拼接。
- String与StringBuffer/StringBuilder的区别:
- String是不可变的,每次对String进行修改都会创建一个新的String对象;而StringBuilder和StringBuffer是可变的,可以直接修改原始对象。
- 字符串编码(Encoding):
- 在Java中,字符串是以UTF-16编码存储的,但可以通过指定编码格式将字符串转换为字节数组或其他格式。
- 字符串比较:
- 在Java中,字符串比较通常使用equals方法进行内容比较,使用==进行引用比较。另外,可以使用compareTo方法进行字符串的字典顺序比较。
StringBuffer和StringBuilder
StringBuffer
- 线程安全性:
- StringBuffer 是线程安全的,所有的方法都是同步的(synchronized),这意味着多个线程可以安全地同时访问一个 StringBuffer 对象。
这种线程安全性是通过在每个方法上添加 synchronized 关键字来实现的,确保在多线程环境下不会出现竞态条件。
- StringBuffer 是线程安全的,所有的方法都是同步的(synchronized),这意味着多个线程可以安全地同时访问一个 StringBuffer 对象。
- 性能:
- 由于线程安全性的考虑,StringBuffer 的性能可能会受到影响,特别是在并发环境中。
每个方法调用都要获取和释放锁,这可能导致性能下降。
- 由于线程安全性的考虑,StringBuffer 的性能可能会受到影响,特别是在并发环境中。
- 可变性:
- StringBuffer 是可变的,可以通过调用不同的方法来修改其内容,例如追加、插入、删除等操作。
StringBuilder
- 线程安全性:
- StringBuilder 不是线程安全的,不进行同步处理,因此在单线程环境下,StringBuilder 的性能通常比 StringBuffer 更好。
- 在多线程环境下,如果多个线程同时访问一个 StringBuilder 对象,可能会导致数据不一致或其他问题。
- 性能:
- 由于不需要进行同步处理,StringBuilder 的性能通常比 StringBuffer 更好,特别是在单线程环境下。
- 可变性:
- StringBuilder 也是可变的,可以通过调用不同的方法来修改其内容,与 StringBuffer 类似。
共同点
- 方法:
- StringBuffer 和 StringBuilder 都提供了类似的方法,如 append(), insert(), delete(), reverse() 等,用于操作字符串内容。
- 继承关系:
- StringBuffer 和 StringBuilder 都继承自 AbstractStringBuilder 类。
常用方法
- append(String str):将指定字符串追加到字符串缓冲区的末尾。
- insert(int offset, String str):将指定字符串插入到指定位置。
- delete(int start, int end):删除指定位置的字符序列。
- deleteCharAt(int index):删除指定位置的字符。
- replace(int start, int end, String str):用新字符串替换指定位置的字符序列。
- substring(int start):返回从指定位置开始到末尾的子字符串。
- substring(int start, int end):返回从指定位置开始到指定位置结束的子字符串。
- reverse():反转字符串。
- length():返回当前字符串的长度。
- charAt(int index):返回指定位置的字符。
- indexOf(String str):返回指定字符串第一次出现的位置。
- lastIndexOf(String str):返回指定字符串最后一次出现的位置。
- toString():将字符串缓冲区内容转换为字符串。
String,StringBuffer,StringBuilder对比
- String:
- StringBuffer:
- StringBuilder:
日期时间API
LocalDate:处理日期
- now():获取当前日期
- of(int year, int month, int dayOfMonth):根据年月日创建日期
- plusDays(long daysToAdd):增加指定天数
- minusDays(long daysToSubtract):减少指定天数
- getYear()、getMonthValue()、getDayOfMonth():获取年、月、日等
LocalTime:处理时间
- now():获取当前时间
- of(int hour, int minute):根据小时和分钟创建时间
- plusHours(long hoursToAdd)、minusHours(long hoursToSubtract):增加/减少小时数
- getHour()、getMinute()、getSecond():获取小时、分钟、秒等
LocalDateTime:结合日期和时间
- now():获取当前日期和时间
- of(LocalDate date, LocalTime time):根据日期和时间创建日期时间对象
- plusDays(long daysToAdd)、minusDays(long daysToSubtract):增加/减少天数
- toLocalDate()、toLocalTime():分别获取日期和时间部分
Instant:瞬时
- now():静态方法,用于获取当前的时间戳。
- ofEpochSecond(long epochSecond):静态方法,根据秒数创建一个Instant实例。
- plusSeconds(long secondsToAdd):在当前时间戳的基础上增加指定秒数。
- minusSeconds(long secondsToSubtract):在当前时间戳的基础上减去指定秒数。
- isAfter(Instant otherInstant):判断当前时间戳是否在另一个时间戳之后。
- isBefore(Instant otherInstant):判断当前时间戳是否在另一个时间戳之前。
- plus(Duration amountToAdd):在当前时间戳的基础上增加指定的持续时间。
- minus(Duration amountToSubtract):在当前时间戳的基础上减去指定的持续时间。
DateTimeFormatter:格式化日期
-
ofPattern(String pattern):静态方法,用于创建一个自定义格式的 DateTimeFormatter 对象。例如:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
; -
format(TemporalAccessor temporal):将日期时间对象格式化为字符串。例如:
String formattedDate = formatter.format(LocalDateTime.now())
; -
parse(CharSequence text):将字符串解析为日期时间对象。例如:
LocalDateTime parsedDate = LocalDateTime.parse("2024-04-02 14:30:00", formatter)
; -
withLocale(Locale locale):设置 DateTimeFormatter 的区域设置。例如:
formatter = formatter.withLocale(Locale.US)
; -
withZone(ZoneId zone):设置 DateTimeFormatter 的时区。例如:
formatter = formatter.withZone(ZoneId.of("America/New_York"))
; -
withResolverStyle(ResolverStyle resolverStyle):设置解析风格。例如:
formatter = formatter.withResolverStyle(ResolverStyle.STRICT)
; -
getResolverStyle():获取解析风格。
-
getDecimalStyle():获取十进制样式。
-
withDecimalStyle(DecimalStyle decimalStyle):设置十进制样式。
JAVA比较器
Comparable接口实现自然排序
- Comparable接口是一个泛型接口,它定义了一个对象与另一个对象进行比较的方法。
- 实现Comparable接口的类必须实现compareTo方法
- 如果当前对象小于另一个对象,则返回负整数。
- 如果当前对象等于另一个对象,则返回0。
- 如果当前对象大于另一个对象,则返回正整数。
- 可以看作对类本身增加排序的方法
import java.util.*;
class Person implements Comparable<Person> {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int compareTo(Person otherPerson) {
// 按照年龄升序排列
return this.age - otherPerson.age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 20));
people.add(new Person("Charlie", 30));
Collections.sort(people);
for (Person person : people) {
System.out.println(person);
}
}
}
Comparator接口实现定制排序
- 主要用于没实现Comparable接口,又不方便修改代码
- Comparator接口是用于定义自定义对象比较规则的接口。
- 它包含一个抽象方法compare(T o1, T o2),用于比较两个对象o1和o2的顺序。
- 根据比较结果,compare方法返回负数、零或正数,表示o1小于、等于或大于o2。
- 可以看作新增一个专门的类来对某类进行比较
import java.util.Comparator;
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
class PersonAgeComparator implements Comparator<Person> {
@Override
public int compare(Person p1, Person p2) {
return p1.getAge() - p2.getAge();
}
}
public class Main {
public static void main(String[] args) {
List<Person> people = new ArrayList<>();
people.add(new Person("Alice", 25));
people.add(new Person("Bob", 20));
people.add(new Person("Charlie", 30);
Collections.sort(people, new PersonAgeComparator());
for (Person person : people) {
System.out.println(person.getName() + " - " + person.getAge());
}
}
}