String类
字符串,final修饰类,实现了Serializable(序列化),Comparable(比较大小),CharSequence(可读可写序列)
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
由于是final 修饰的类,所以String类无法被继承。
从String的源码当中我们可以抽取出一句话
The value is used for character storage.(这个值作为字符存储)
String字符串使用char型数组的方式来进行储存,同时此数组也被final修饰,故String的值也不允许被修改。
1. String声明
String可通过new对象的方式创建,也可以直接通过字面量的方式来进行赋值。
代码:
String a = new String("a");
String b = "b";
经典面试题:
请说出下列程序运行结果:
String s1 = new String("a");
String s3 = "a";
System.out.println(s1 == s3); // false
问题:
String s1 = new String("a");
String s1 = "a";
两种方式有何不同?
答:通过new的方式创建的对象在内存当中分配在堆空间当中,栈中变量的地址值为堆空间的值。而堆空间中的储存为字符串常量池中的地址值(如果有的话)
通过字面量直接赋值那么栈中变量的地址值为字符串常量池中的值。
经典面试题:
请说出运行结果
String s1 = "hello";
String s2 = "world";
String s3 = "helloworld";
String s4 = s1 + "world";
String s5 = "hello" + "world";
String s6 = s1 + s2;
String s7 = "hello" + s2;
String s8 = (s1+s2).intern();
System.out.println(s3 == s4); // false
System.out.println(s3 == s5); // true
System.out.println(s3 == s6); // false
System.out.println(s3 == s7); // false
System.out.println(s3 == s8); // true
结果分析:
当String直接用字面量的方式来赋值时,它的地址指向方法区中的字符串常量池。
当String声明当中出现变量时,那么此时他的地址则不再指向与方法区字符串常量池,而是指向堆空间,类似new String对象的操作。
当调用intern()方法之后,返回的字符串储存在字符串常量池中。
请查找指定字符串出现的次数
@Test
public void test02() {
String str = "abcdfgewabdsqweabweqfabqsabfdsab";
String sub = "ab";
System.out.println(getCount(str, sub));
}
/**
*
* @param str 字符串
* @param sub 需要查找的字符串
* @return
*/
public int getCount(String str, String sub) {
int count = 0;
int index = 0;
// index = str.indexOf(sub, index); 寻找某个字符串从指定的位置开始
while ((index = str.indexOf(sub, index)) != -1) {
index +=sub.length();
count++;
}
return count;
}
常用方法
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结束 左闭右开即从beginIndex开始,包含beginIndex,从endIndex结束不包含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); //返回指定子字符串在此字符串中最右边出现处的索引,从指定位置开始
String replace(char oldChar,char newChar); // 返回一个新的字符串,它是通过用newChar替换此字符串中出现的所有oldChar得到的。
String replace(CharSequence target,CharSequence replacement); // 使用指定的字面值替换序列换此字符串所有匹配字面值目标序列的字符串。
String replaceAll(String regex,String replacement); //使用给定的replacement替换此字符串所有匹配给定的正则表达式的子字符串。
String replaceFist(String regex,String replacement);
// 使用给定的replacement替换此字符串匹配给定的正则表达式的第一个字字符串。
boolean matches(String regex); // 告知此字符串是否匹配给定的正则表达式
String[] split(String regex); // 根据给定正则表达式的匹配拆分此字符。
String[] split(String regex,int limit); // 根据给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中
StringBuffer(线程安全方法大部分为synchronized)、StringBuilder
StringBuffer初始化的长度为16如果调用空参构造器的话
如果使用带参构造器
例如:StringBuffer sb = new StringBuffer(“abcd”); // 那么长度为原有字符串长度再加16 ,如下为源码逻辑
length返回的不为value.length而是count
扩容问题:
- 如果添加的数据底层数组撑不下了,那就需要扩容
默认情况下,扩容为原来的容量2倍+2,同时将原有数组中的元素复制到新的数组
扩容代码(部分)
public StringBuffer(String str) {
super(str.length() + 16);
append(str);
}
public AbstractStringBuilder append(String str) {
if (str == null) str = "null"; // 首先判断是否为空,避免出现空指针
int len = str.length();
ensureCapacityInternal(count + len); // 是否需要扩容 参数为 当前长度+需要append的字符
str.getChars(0, len, value, count);
count += len;
return this;
}
/**
* This method has the same contract as ensureCapacity, but is
* never synchronized.
*/
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) // 如果 总长度 - 当前长度>0那么则需要扩容
expandCapacity(minimumCapacity);
}
/**
* This implements the expansion semantics of ensureCapacity with no
* size check or synchronization.
*/
void expandCapacity(int minimumCapacity) {
int newCapacity = value.length * 2 + 2; // 新长度为 (原来长度*2) + 2
if (newCapacity - minimumCapacity < 0) // 如果乘以2+2长度还是不够
newCapacity = minimumCapacity; // 直接等于传入的长度
if (newCapacity < 0) {
if (minimumCapacity < 0) // overflow
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity); // 复制数组给新的数组
}
常用方法:
StringBuffer append(xxx); // 提供了很多的append方法,用于进行字符串拼接
StringBuffer delete(int start,int end); // 删除指定位置的内容
StringBuffer replace(inst start,int end,String str); // 把[start,end]位置替换为str
StringBuffer insert(int offset,xxx); // 在指定位置插入XXX
StringBuffer reverse(); // 反转字符串;
void setCharAt(int n,char ch); // 在指定位置替换
经典面试题String,StringBuffer,StringBuilder有什么异同?
相同:
1. 底层都使用char[]数组储存
不同:
1. String为不可变字符,StringBuffer,StringBuilder为可变字符,可以动态扩容
2. StringBuffer为线程安全,StringBuilder为线程不安全
3. String初始化长度为0,StringBuffer与StringBuilder初始化长度为16。
4. 执行效率上StringBuilder>StringBuffer>String
注意:StringBuffer与StringBuilder中length方法返回的为count,即字符串的长度,而非它们本身的长度。
public synchronized int length() {
return count;
}
而我们平时所使用的length方法返回为value.length,即它们本身的长度
public int length() {
return value.length;
}
java 比较器
背景:
Java当中比较大小的运算符大多数只对于基本数据类型有效,对于引用数据类型无法进行大小区分。
在实际开发当中我们需要根据对象来进行排序,而Java当中比较大小的运算符无法满足我们的需求。
为了解决上述情况,Java当中为我们提供了两个接口进行比较。
- comparable(自然排序)
实现Comparable接口,重写comparaTo()方法
重写规则:- 如果当前对象this大于形参对象obj,则返回正整数
- 如果当前对象this小于形参对象obj,则返回负整数
- 如果当前对象this等于形参对象obj,则返回零
使用参考: String类
public final class String implements java.io.Serializable, Comparable<String>, CharSequence {
public int compareTo(String anotherString) {
int len1 = value.length;
int len2 = anotherString.value.length;
int lim = Math.min(len1, len2);
char v1[] = value;
char v2[] = anotherString.value;
int k = 0;
while (k < lim) {
char c1 = v1[k];
char c2 = v2[k];
if (c1 != c2) {
return c1 - c2;
}
k++;
}
return len1 - len2;
}
}
@Test
public void test03(){
String[] arr = new String[]{"D","E","B","A","Q","P"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
在Java当中还有许多的包装类实现了Comparable接口,此处不一一举例了。
对于自定义类来说,如果需要排序,可以让自定义类实现Comparable接口,重写comparaTo()方法,在comparaTo方法当中自定义排序规则
public class Student implements Comparable {
private Integer id;
private String name;
private Integer className;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getClassName() {
return className;
}
public void setClassName(Integer className) {
this.className = className;
}
public Student(Integer id, String name, Integer className) {
this.id = id;
this.name = name;
this.className = className;
}
public Student() {
}
//指定比较大小的方式(按学号)
@Override
public int compareTo(Object o) {
if (o instanceof Student) {
Student student = (Student) o;
if (this.id > student.getId()) {
return 1;
} else if (this.id < student.getId()) {
return -1;
} else {
return 0;
}
}
throw new RuntimeException("类型不匹配");
}
@Override
public String toString() {
return "Student [id=" + id + ", name=" + name + ", className=" + className + "]";
}
}
@Test
public void test1 () {
Student[] arr = new Student[3];
arr[0] = new Student(1,"张三",110);
arr[1] = new Student(3,"张三",112);
arr[2] = new Student(2,"张三",111);
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
- comparator(定制排序)
使用场景:
当元素的类型没有实现Comparable接口而又不方便修改代码,或者实现了comparable接口的排序规则不适合当前的操作,那么可以考虑使用comparator接口。
实现comparator接口,重写compara(Object o1,Object o2)
规则:- 如果方法返回正整数,则表示o1大于o2
- 如果返回0,表示相等
- 返回负整数,表示o1小o2
String示例:
自定义排序:@Test public void test2() { String[] arr = {"B","A","Q","D"}; Arrays.sort(arr, new Comparator() { // 字符串从大到小 @Override public int compare(Object o1, Object o2) { // TODO Auto-generated method stub if (o1 instanceof String && o2 instanceof String) { String s1 = (String) o1; String s2 = (String) o2; return -s1.compareTo(s2); } throw new RuntimeException("类型不匹配"); } }); System.out.println(Arrays.toString(arr)); }
@Test public void test3 () { Student[] arr = new Student[3]; arr[0] = new Student(1,"张三",110); arr[1] = new Student(3,"张三",112); arr[2] = new Student(2,"张三",111); Arrays.sort(arr,new Comparator() { // 按照班级排序从高到低 @Override public int compare(Object o1, Object o2) { if (o1 instanceof Student && o2 instanceof Student) { Student s1 = (Student) o1; Student s2 = (Student) o2; return -s1.getClassName().compareTo(s2.getClassName()); } throw new RuntimeException("类型不匹配"); } }); System.out.println(Arrays.toString(arr)); }
Comparable接口与Comparator的使用对比
Comparable接口的方式一旦确定,保证Comparable接口实现类的对象在任何位置都可以比较大小。
Comparator接口属性临时性的比较。
System
-
System代表系统,系统级的很多属性和控制方法都放置在该类的内部。
-
由于该类的构造器是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的属性对应的值。系统中常见的属性名以及属性的作用如下表所示:
属性 说明 java.version java运行是环境版本 java.home java安装目录 os.name 操作系统的名称 os.version 操作系统的版本 user.name 用户的帐户名称 user.home 用户的主目录 user.dir 用户的当前工作目录
-
BigInteger与BigDeimal
- BigInteger
-
Integer类作为int的包装类,能存储的最大整型值为231-1,Long类也是有限的,最大为263-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 multlply(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
-
BigDecimal
-
一般的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 multlply(BigDecimal multiplicand) // 乘法 public BigDecimal divide(BigDecimal divisor,int scale,int roundingMode) //除法
使用举例:
@Test public void test2(){ BigInteger bi = new BigInteger("123"); BigDecimal bd = new BigDecimal("3.14"); BigDecimal bd2 = new BigDecimal("11"); System.out.println(bi); System.out.println(bd.divide(bd2,BigDecimal.ROUND_HALF_UP)) System.out.println(bd.divide(bd2,15,BigDecimal.ROUND_HALF_UP)) }
JDK8hi前的和JDK8中日期、时间相关的类分别有哪些?
jdk8之前:
1. java.util.Date
2. java.sql.Date
3. SimpleDateFormaterr
4. CalenDar
jdk8:- Instant
- DateTimeFormatter
- LocalDate、LocalTime、LocalDateTime
-