String
Q:String、StringBuilder、StringBuffer 的区别?
String:
- 底层用被 final 修饰的 char 数组保存数据,所以它是不可变的,也是线程安全的;
- Java 9 后改用 byte 数组和一个标识编码的属性 coder,因为发现实际存储拉丁字符居多,改用 byte 可以节省内存,提高操作速度;
- 由于 String 的不可变,所以每次对它的改变,都要产生新的 String 对象,这会影响系统的性能,所以只适合操作少量数据。
String 不是基础类型(byte、short、int、long、float、double、char、boolean)
char 16 位 2 字节,byte 8 位 1 字节
coder:用于辅助计算字符串长度,对于 LATIN1 它是 0、UTF16 它是 1,字符串长度 = 数组长度右移 coder 位。
操作大量数据要用 StringBuffer、StringBuilder:
- 它们继承于 AbstractStringBuilder,底层用没有 final 修饰 char 数组保存数据,所以是可变的,Java 9 后也改为 byte;不同在于:
- StringBuffer 通过 synchronized 保证了线程安全,适合并发下使用,但有额外的性能开销;
- StringBuilder 不是线程安全的,性能更高,适合单线程下使用。
比如,日常编程用的 + ,底层就是用 StringBuilder;但不要在循环和多表达式中直接用 + ,因为频繁创建 StringBuilder 对象,影响系统性能;最好是新建一个 StringBuilder,调用它的 append 方法来拼接。
StringBuilder b = new StringBuilder();
for (int i = 1; i < 5000000; i++) {
b.append(i);
}
(补充)字符串赋值问题:
String s = "abc";
s == str2.intern(); // true
final String s1 = "a";
final String s2 = "bc";
String s3 = s1 + s2; // 由于 final,编译阶段直接赋值,等同于 s3 = "abc"
s3 == str2.intern(); // true
String s4 = new String("a") + new String("bc"); // 利用StringBuilder的append方法
s4 == str2.intern(); // false
(补充)Q:这行代码,创建几个对象,内存是如何分配的?
String s = new String("abc");
1 或 2 个
new String() 会在堆中创建一个对象,
“abc” 是否创建要看字符串常量池中是否有,有就不建,没有就建。
内存分配:
- "abc"在字符串常量池中
- new的对象实例在堆中
- 引用s在栈中
Object
Q:Object 类的常用方法是什么?
-
getClass():返回对象的 Class;
new ArrayList<>().getClass(); // class java.util.ArrayList
-
toString():返回对象的字符串表示形式;
-
equals():用于比较两个对象是否相等,不能比较基本数据类型;
-
默认实现是,用 == 比较对象的内存地址;
public boolean equals(Object obj) { return (this == obj); }
-
一般会重写,转换成值的比较。
-
-
hashCode():返回对象的哈希值,一个 int 整数,作用是确定对象在哈希表中的索引位置;
// native 修饰的方法调用的是本地方法 public native int hashCode();
-
notify():唤醒一个在该对象监视器上等待的线程;
-
notifyAll():唤醒所有在该对象监视器上等待的线程;
-
wait():让当前对象等待;
-
finalize():用于垃圾收集前,回收特定的资源;因为它可能导致死锁,Java 9 后弃用。