4.2java包装类
Java中的基本数据类型不具备对象特性,为了使其能够参与面向对象操作,Java提供了对应的包装类,如
Integer
、Double
等。包装类属于引用类型,继承自Object
类,具备对象特性,可用于泛型、类型转换等场景。Java 5引入了自动装箱和自动拆箱机制,简化了基本数据类型与包装类之间的转换。自动装箱通过valueOf()
方法实现,自动拆箱通过xxxValue()
方法实现。使用包装类时需注意缓存问题和空指针异常。此外,Java提供了StringBuilder
、StringBuffer
和StringJoiner
等类,用于高效处理字符串拼接操作。StringBuilder
适用于单线程环境,StringBuffer
适用于多线程环境,StringJoiner
则用于将多个字符串用指定分隔符连接。这些工具类在处理批量字符串拼接时,能有效提升性能并减少内存开销。
在 Java 里,基本数据类型不具备对象的特性,像不能调用方法、参与面向对象的操作等。为了让基本数据类型也能有对象的行为,Java 提供了对应的包装类。同时,自动拆箱和自动装箱机制让基本数据类型和包装类之间的转换更加便捷。
包装类概述
Java 为 8 种基本数据类型都提供了对应的包装类,具体如下:
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
包装类属于引用类型,继承自 Object
类,具备对象的特性,能调用方法和参与面向对象的操作。
包装类的用途
- 作为泛型的类型参数:泛型只能使用引用类型,不能使用基本数据类型,这时就需要用到包装类。例如:
import java.util.ArrayList;
import java.util.List;public class WrapperClassGenericExample {public static void main(String[] args) {// 正确,使用包装类作为泛型类型参数List<Integer> intList = new ArrayList<>();intList.add(1);// 错误,不能使用基本数据类型作为泛型类型参数// List<int> wrongList = new ArrayList<>(); }
}
- 包含实用方法:包装类提供了一些实用的方法,像类型转换、进制转换等。例如:
public class WrapperClassMethodExample {public static void main(String[] args) {String str = "123";// 将字符串转换为整数int num = Integer.parseInt(str); System.out.println(num);int decimal = 255;// 将十进制数转换为十六进制字符串String hex = Integer.toHexString(decimal); System.out.println(hex);}
}
自动装箱和自动拆箱
自动装箱
自动装箱指的是把基本数据类型自动转换为对应的包装类对象。在 Java 5 之后引入了自动装箱机制,让代码更简洁。例如:
public class AutoBoxingExample {public static void main(String[] args) {int num = 10;// 自动装箱,将 int 类型的 num 转换为 Integer 类型的 objInteger obj = num; System.out.println(obj);}
}
自动拆箱
自动拆箱是把包装类对象自动转换为对应的基本数据类型。例如:
public class AutoUnboxingExample {public static void main(String[] args) {Integer obj = 20;// 自动拆箱,将 Integer 类型的 obj 转换为 int 类型的 numint num = obj; System.out.println(num);}
}
自动装箱和拆箱的实现原理
自动装箱和拆箱是通过编译器在编译阶段自动插入相应的方法调用实现的。具体来说,自动装箱调用的是包装类的 valueOf()
方法,自动拆箱调用的是包装类的 xxxValue()
方法(xxx
代表基本数据类型)。例如:
public class AutoBoxingUnboxingPrinciple {public static void main(String[] args) {// 自动装箱,实际调用 Integer.valueOf(30)Integer obj = 30; // 自动拆箱,实际调用 obj.intValue()int num = obj; }
}
注意事项
- 缓存问题:部分包装类(如
Integer
、Byte
、Short
、Long
、Character
)会对一定范围内的值进行缓存,以提高性能。例如,Integer
类会缓存 -128 到 127 之间的值,当使用自动装箱创建这个范围内的Integer
对象时,会直接从缓存中获取,而不是创建新对象。示例如下:
public class WrapperClassCacheExample {public static void main(String[] args) {Integer a = 100;Integer b = 100;// 输出 true,因为 100 在缓存范围内,a 和 b 引用同一个对象System.out.println(a == b); Integer c = 200;Integer d = 200;// 输出 false,因为 200 不在缓存范围内,c 和 d 是不同的对象System.out.println(c == d); }
}
- 空指针异常:在进行自动拆箱时,如果包装类对象为
null
,会抛出NullPointerException
异常。例如:
public class NullPointerInAutoUnboxing {public static void main(String[] args) {Integer obj = null;// 会抛出 NullPointerException 异常int num = obj; }
}
通过使用包装类、自动装箱和自动拆箱机制,Java 让基本数据类型和对象之间的交互更加灵活和方便。不过在使用过程中,要注意缓存问题和空指针异常等潜在风险
批量字符串拼接操作
在 Java 里,String
类是不可变的,这意味着一旦创建了一个 String
对象,它的内容就不能被改变。当使用 +
运算符进行字符串拼接时,每次拼接操作都会创建一个新的 String
对象。如果进行批量拼接,会产生大量临时对象,这不仅会占用额外的内存空间,还会增加垃圾回收的负担,从而影响性能。
1. StringBuilder
StringBuilder
是一个可变的字符序列,它提供了高效的字符串拼接操作。在 JDK 1.5 中引入,是非线程安全的,因此在单线程环境下性能较高。
常用方法
append()
:用于在当前字符序列末尾追加各种类型的数据。insert()
:在指定位置插入各种类型的数据。delete()
:删除指定位置的字符。reverse()
:反转当前字符序列。
示例代码
public class StringBuilderExample {public static void main(String[] args) {StringBuilder sb = new StringBuilder();// 追加字符串sb.append("Hello");sb.append(" ");sb.append("World");// 在指定位置插入字符串sb.insert(5, ",");// 删除指定位置的字符sb.delete(5, 6);// 反转字符串sb.reverse();System.out.println(sb.toString()); // 输出 dlroW olleH}
}
适用场景
适用于单线程环境下需要频繁进行字符串拼接、修改等操作的场景,例如在循环中动态构建字符串。
2. StringBuffer
StringBuffer
也是一个可变的字符序列,与 StringBuilder
类似。它是线程安全的,因为它的大部分方法都被 synchronized
关键字修饰,因此在多线程环境下可以保证数据的一致性,但性能相对较低。
常用方法
StringBuffer
的方法与 StringBuilder
基本相同,如 append()
、insert()
、delete()
、reverse()
等。
示例代码
public class StringBufferExample {public static void main(String[] args) {StringBuffer sb = new StringBuffer();sb.append("Hello");sb.append(" ");sb.append("Java");System.out.println(sb.toString()); // 输出 Hello Java}
}
适用场景
适用于多线程环境下需要频繁进行字符串拼接、修改等操作,且需要保证线程安全的场景。
3. StringJoiner
StringJoiner
是 Java 8 引入的一个类,用于方便地将多个字符串用指定的分隔符连接起来,还可以指定前缀和后缀。
常用方法
add()
:添加一个元素到StringJoiner
中。merge()
:合并另一个StringJoiner
的内容。setEmptyValue()
:设置当没有元素时的空值表示。
示例代码
import java.util.StringJoiner;public class StringJoinerExample {public static void main(String[] args) {// 指定分隔符、前缀和后缀StringJoiner sj = new StringJoiner(", ", "[", "]");sj.add("Apple");sj.add("Banana");sj.add("Cherry");System.out.println(sj.toString()); // 输出 [Apple, Banana, Cherry]// 合并另一个 StringJoinerStringJoiner anotherSj = new StringJoiner("; ");anotherSj.add("Dog");anotherSj.add("Cat");sj.merge(anotherSj);System.out.println(sj.toString()); // 输出 [Apple, Banana, Cherry, Dog; Cat]}
}
适用场景
适用于需要将多个字符串用特定分隔符连接起来的场景,例如将数组元素连接成一个字符串。
性能对比
package com.example.pkg4;import java.util.StringJoiner;public class Test3 {public static void main(String[] args) {int n = 10000;// 使用 + 运算符进行字符串拼接long startTime1 = System.currentTimeMillis();String result1 = "";for (int i = 0; i < n; i++) {result1 = result1 + Integer.toString(i);}long endTime1 = System.currentTimeMillis();System.out.println("使用 + 运算符拼接耗时: " + (endTime1 - startTime1) + " 毫秒");// 使用 StringBuilder 进行字符串拼接long startTime2 = System.currentTimeMillis();StringBuilder sb = new StringBuilder();for (int i = 0; i < n; i++) {sb.append(Integer.toString(i));}String result2 = sb.toString();long endTime2 = System.currentTimeMillis();System.out.println("使用 StringBuilder 拼接耗时: " + (endTime2 - startTime2) + " 毫秒");// 使用 StringBuffer 进行字符串拼接long startTime3 = System.currentTimeMillis();StringBuffer strbuf = new StringBuffer();for (int i = 0; i < n; i++) {strbuf.append(Integer.toString(i));}String result3 = strbuf.toString();long endTime3 = System.currentTimeMillis();System.out.println("使用 StringBuffer 拼接耗时: " + (endTime3 - startTime3) + " 毫秒");// 使用 StringJoiner 进行字符串拼接long startTime4 = System.currentTimeMillis();StringJoiner strjoin = new StringJoiner("");for (int i = 0; i < n; i++) {strjoin.add(Integer.toString(i));}String result4 = strjoin.toString();long endTime4 = System.currentTimeMillis();System.out.println("使用 StringJoiner 拼接耗时: " + (endTime4 - startTime4) + " 毫秒");}}
总结
StringBuilder
:单线程环境下,性能高,用于频繁的字符串操作。StringBuffer
:多线程环境下,线程安全,用于频繁的字符串操作。StringJoiner
:用于方便地将多个字符串用指定分隔符连接起来,可指定前缀和后缀。