Java常用类解析
java常用类解析
包装类
包装类值基本数据类型对应的引用类型,包装类封装好的方法能够很方便的让我们操作基本数据类型而不需要自己再去编写不必要的代码。
基本数据类型 | 包装类 |
---|---|
boolean | Boolean |
char | Character |
byte | Byte |
short | Short |
int | Integer |
long | Long |
floast | Float |
double | Double |
包装类和基本数据类型的转换
首先,引出装箱和拆箱两个概念,装箱:基本数据类型->引用类型,拆箱:引用类型->基本数据类型。
jdk5以前需要手动装箱和拆箱,比较麻烦。jdk5以后自动进行装箱和拆箱。
int n = 100;
//自动装箱 int->Integer
Integer integer = n; //底层使用的是 Integer.valueOf(n2)
//自动拆箱 Integer->int
int n2 = integer; //底层仍然使用的是 intValue()方法
包装类型和字符串类型的转换
以Integer类型和String类型为例
//包装类(Integer)->String
Integer i = 100;//自动装箱
//方式 1
String str1 = i + "";
//方式 2
String str2 = i.toString();
//方式 3
String str3 = String.valueOf(i);
//String -> 包装类(Integer)
String str4 = "12345";
Integer i2 = Integer.parseInt(str4);//使用到自动装箱
Integer底层机制
先来看一道面试题
public static void main(String[] args) {
Integer i = new Integer(1);
Integer j = new Integer(1);
System.out.println(i == j);//False
Integer m = 1; //底层 Integer.valueOf(1);
Integer n = 1;//底层 Integer.valueOf(1);
System.out.println(m == n); //True
Integer x = 128;//底层 Integer.valueOf(128);
Integer y = 128;//底层 Integer.valueOf(128);
System.out.println(x == y);//False
}
这里输出False,True,False。
首先第一个好理解,使用new操作符,两个Integer类变量指向不同的对象,当然是不相等的。
第二个和第三个需要理解底层机制,因为这里自动装箱,底层调用的是valueof() 方法,源码如下:
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
分析一下可以知道当 i 在 IntegerCache.low(-128)~IntegerCache.high(127)范围内,Integer对象就直接从数组返回,这个数组是在类加载时就已经初始化好了,如果超出了这个范围,则会重新new一个Integer对象。
String类
String结构剖析
- String实现了两个接口 1.Comparable接口 2.Serializable接口
- String类是final类不能被继承
- String类的属性是 private final char[] value 用于存放字符串内容,因为valued的指向不可变,而String内部没有提供修改value的方法,因此String类是不可变类。
String对象创建的两种方式
String s1 = "yjh";
String s2 = new String("yjh");
以上两种创建方式存在区别
方式一:先在常量池中查找是否有存储"yjh"的空间,如果有则直接返回常量池的地址,如果没有,则在常量池创建"yjh"并返回地址,即s1最终指向的是常量池的地址。
方式二:先在堆中创建对象,里面的value属性指向字符串常量"yjh",如果没有则创建并返回地址给value,s2最终指向的是堆中的空间地址。
下面的例子帮助理解String对象的创建
测试题一:
String a = "abc";
String b = "abc";
System.out.println(a.equals(b))//true
System.out.println(a == b)//true
测试题二:
String a = "yjh";
String b = new String("yjh");
System.out.println(a == b)//false
System.out.println(a == b.intern())//true
System.out.println(b == b.intern())//false
说明:intern()方法返回String对象的字符串在常量池中的地址
字符串的特性
String是不可变类,字符串对象一旦被分配,内容是不可变类。所以在每次给String变量赋值时,都会重新返回一个新的对象给String变量。
分析题1:
//以下语句创建了几个对象
String s = "hellp";
s = "world
解析:创建了两个对象,前后两个s指向的不是同一个对象。
分析题2:
//创建了几个对象
String s = "hello" + "world";
解析:创建了一个对象,编译器做一个优化:s = "hello" + "world" -> s = "helloworld"
分析题3
//a,b,c三个对象内存分布,分析第三句代码底层执行过程
String a = "hello";
String b = "world";
String c = a + b;
- 先创建一个StringBuilder对象,StirngBuilder sb = new StringBuilder();
- 然后用append方法,sb.append(a),sb.append(b);
- 最后用toString方法返回,c = sb.toString()
String增强类
由于String不可变,每次更新或者拼接新的字符串都会新创建一个对象,当有大量的修改操作时,效率很低。因此Java提供了StringBuffer和StringBuilder类,字符串长度和内容可以变化。
StringBuffer
- StringBuffer 的直接父类是 AbstractStringBuilder
- 在父类中 AbstractStringBuilder 有属性 char[] value,不是 final,该 value 数组存放字符串内容。
- StringBuffer 是一个 final 类,不能被继承
- 因为 StringBuffer 字符内容是存在 char[] value, 所以增加/删除除不用每次都更换地址,StringBuffer只有在value数组空间不足时,会扩容,value将指向新的字符串常量而StringBuffer的指向不变。
- StringBuffer是线程安全的。
StringBuffer扩容机制
- 使用无参构造器时,默认初始化字符串长度为16,如果指定了容量,则用指定大小初始化,如果用String对象初始化,字符串长度初始化String对象的长度 + 16
- 当使用append()方法扩充字符串时,如果当前字符串长度加上拼接字符串的长度超过了value数组的容量,容量为扩充为当前容量的两倍+2
StringBuffer和String对象的转换
//String——>StringBuffer
String str = "hello tom";
//方式 1 使用构造器
StringBuffer stringBuffer = new StringBuffer(str);
//方式 2 使用的是 append 方法
stringBuffer = stringBuffer.append(str);
// StringBuffer ->String
//方式一:使用toString方法
String s = stringBuffer.toString();
//方式二:使用构造器
String s1 = new String(stringBuffer3);
StringBuilder
StringBuilder是StringBuffer的一个简易替换,但不是线程安全的,但是StringBuilder的速度更快,因此在单线程时更多考虑使用StringBuilder。
Random类
Java的Random类提供了丰富的随机数生成方法
方法 | 说明 |
---|---|
nextBoolean() | 生成true或者false,两者概率相等 |
nextDouble | 生成[0,1.0)区间的小数 |
nextInt() | 生成int范围的整数 |
nextInt(int n) | 生成[0,n)之间的整数,不包括n |
//生成[a,b)区间的整数
Random r = new Random();
int n = r.nextInt(b-a) + a;
日期类
Java先后有三代日历类库,现在的第三代是**LocalDate(日期/年月日),LocalTime(时间/时分秒),LocalDateTime(时间日期/年月日时分秒)
获取日期信息
LocalDateTime ldt = LocalDateTime.now()
System.out.println("年=" + ldt.getYear());
System.out.println("月 =" + ldt.getMonth());//英文描述
System.out.println("月 =" + ldt.getMonthValue());//数字描述
System.out.println("日=" + ldt.getDayOfMonth());
System.out.println("时=" + ldt.getHour());
System.out.println("分=" + ldt.getMinute());
System.out.println("秒=" + ldt.getSecond());
格式化输出
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");//指定输出格式
String format = dtf.format(ldt);//传入需要格式化的LocalDateTime对象,并返回给String对象
System.out.println("格式化的日期=" + format);
plus和minus方法
//100天后,日期信息
LocalDateTime localDateTime = ldt.plusDays(890);
System.out.println("100 天后=" + dateTimeFormatter.format(localDateTime));
//999分钟后时间信息
LocalDateTime localDateTime2 = ldt.minusMinutes(3456);
System.out.println("3456 分钟前 日期=" + dateTimeFormatter.format(localDateTime2))
大数字处理类
如果我们要处理的数据超过了long支持的范围或者说我们要求更高的精度,我们可以使用BigInteger类和BigDecimal类。
数学运算 | 方法 |
---|---|
加 | add() |
减 | subtract() |
乘 | mutiply() |
除 | divide() |
学习总结来源于韩顺平老师循序渐进学Java