一、前言常见面试题来自牛客网:https://www.nowcoder.com/tutorial/94/4206176d637541fa92c784a4f547e979
这个专栏是Java基础复习,将记录我准备大数据开发面试的过程,在校招面试中占了比较大的部分。希望自己现在夯实基础,笑着面对接下来的校招。那么现在开始行动起来吧!
二、常见题1.String和StringBuffer有什么区别?
不同点:
(一)String类不可变,有"final"修饰符,规定了String类是不能被继承的,而且我们可以看到,char value[]也是final修饰,这说明一旦String对象建立,char数组的长度就等于字符串的长度,且数组长度一旦固定,就没有办法扩容,所以String类不可变。下面是String部分源码
public final class String
implements java.io.Serializable, Comparable, CharSequence {
private final char value[];
private int hash; // Default to 0
private static final long serialVersionUID = -6849794470754667710L;
...
...
}
StringBuffer类可变,下面是StringBuffer部分源码
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence
{
private transient char[] toStringCache;
static final long serialVersionUID = 3388685877147921107L;
...
...
}
(二)安全角度:String和StringBuffer是线程安全的,StringBuilder线程不安全
StringBuffer是线程安全的
@Override
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
@Override
public synchronized StringBuffer delete(int start, int end) {
toStringCache = null;
super.delete(start, end);
return this;
}
StringBuilder线程不安全
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
@Override
public StringBuilder delete(int start, int end) {
super.delete(start, end);
return this;
}
...
...
可以很明显的看出,两者的差异在于有没有加同步锁
(三)效率角度:
StringBuffer是线程安全的,也就是多线程修改同一个StringBuffer对象的时候,过程是同步的,当然这就导致了StringBuffer的效率降低,毕竟如果要提升安全性,就必须要损失一定的效率。
StringBuilder是jdk1.5后新增的,主要就是为了提升单线程下StringBuffer的效率问题,因为StringBuilder没有了同步操作,所以效率提升了。
从执行效率快慢来看
String < StringBuffer < StringBuilder,
但是存在一种特殊情况,就是当String全是字面量相加的时候,这种情况会很快,因为字面量在编译期时,编译器会优化处理,将字面量全部合成一个字面量然后扔进方法区的常量池中,所以运行时当在执行S1指向的时候,这个对象就已经存在与常量池中了,不需要计算了。而StringBuffer 则需要在运行时进行append操作,所以这就造成了这种假象。
//String效率在这种场景下,是远要比StringBuffer快的:
String S1 = "This is a" + " simple" + "test";
StringBuffer Sb = new StringBuffer("This is a").append("simple").append("test");
但是,修改一下,把上面代码换成下面代码,String的执行效率就低了很多,因为运行时需要重新创建一个对象,将S2,S3 ,S4的值相加后再复制给这个新对象,S1再重新指向这个新对象。
//此时String速度是非常慢的:
String S2 = “This is a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
StringBuffer Sb = new StringBuffer("This is a").append("simple").append("test");
2.’=='和equals区别?
简单来说, == 是比较内存地址是否相同,equals针对的是引用数据类型,比较内存地址上面的值是否相同(equals在不同的使用场景下,经常被重写)。基本数据类型无equals方法。
下面用代码通俗易懂的解释这个道理:
public class IntegerTest {
public static void main(String[] args) {
Integer aaa=new Integer(5);
Integer bbb=new Integer(5);
//由于Integer变量实际是对一个Integer对象的引用,所以两个通过new生成的Integer变量永远不==(因为其内存地址不同)
System.out.println(aaa==bbb);//false
//比较的是值,所以相等
System.out.println(aaa.equals(bbb));//true
int a=10;
int b=10;
System.out.println(a==b);//true
String str1=new String("justice");
String str2=new String("justice");
System.out.println(str1==str2);//false
System.out.println(str1.equals(str2));//true
String str3;
str3=str1;
System.out.println(str1==str3);//true
System.out.println(str1.equals(str3));//true
}
}
aaa、bbb是两个new出来的Integer变量,内存地址永远不同,所以==结果不同,但值相同;
a和b都是基本数据类型,变量存储值,所以为==结果为true
str1和str2都是String类型,属于引用类型,变量存储地址,所以==为false,equals为true
由于str3指向str1,所以两者内存地址相同,值也相同
以下是equals的源码:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}



