1.【String】StringBuffer和StringBuilder区别?
String对象是final修饰的不可变的。对String对象的任何操作只会生成新对象,不会对原有对象进行操作。
StringBuilder和StringBuffer是可变的。
其中StringBuilder线程不安全,但开销小。
StringBuffer线程安全,其类成员方法由synchronized修饰,在多线程下保证安全性,但其开销大。
使用:
循环外字符串拼接用String+
有循环体的话,使用StringBuilder的append进行操作
如果采用了多线程,使用StringBuffer的append进行操作
2.【String】== 和 equals 的区别是什么?
== 解读
对于基本类型和引用类型 == 的作用效果是不同的,如下所示:
- 基本类型:比较的是值是否相同;
- 引用类型:比较的是引用是否相同;
String x = "string";
String y = "string";
String z = new String("string");
System.out.println(x==y); // true
System.out.println(x==z); // false
System.out.println(x.equals(y)); // true
System.out.println(x.equals(z)); // true
代码解读:因为 x 和 y 指向的是同一个引用,所以 == 也是 true,而 new String()方法则重写开辟了内存空间,所以 == 结果为 false,而 equals 比较的一直是值,所以结果都为 true。
首先来看默认情况下 equals 比较一个有相同值的对象,代码如下:
class Cat {
public Cat(String name) {
this.name = name;
}
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Cat c1 = new Cat("王磊");
Cat c2 = new Cat("王磊");
System.out.println(c1.equals(c2)); // false
//源码
public boolean equals(Object obj) {
return (this == obj);
}
//String 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;
}
equals 本质上就是 ==。String 重写了 Object 的 equals 方法,把引用比较改成了值比较。
总结 :== 对于基本类型来说是值比较,对于引用类型来说是比较的是引用;而 equals 默认情况下是引用比较,只是很多类重新了 equals 方法,比如 String、Integer 等把它变成了值比较,所以一般情况下 equals 比较的是值是否相等。
3.【String】两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗?
两个对象的 hashCode() 相同,equals() 不一定 true。代码解读:很显然“通话”和“重地”的 hashCode() 相同,然而 equals() 则为 false,因为在散列表中,hashCode() 相等即两个键值对的哈希值相等,然而哈希值相等,并不一定能得出键值对相等。
String str1 = "通话";
String str2 = "重地";
System. out. println(String. format("str1:%d | str2:%d", str1. hashCode(),str2. hashCode()));
System. out. println(str1. equals(str2));
str1:1179395 | str2:1179395
false
4.【重载】重载: 名字相同,与参数列表/返回值不同
函数方法名必须相同,看参数列表即可,无关返回值
5.【final】final 可以修饰类/方法/变量
修饰类不能被继承——>不能修饰抽象类
修饰的方法——可以重载,不能被重写
重载(参数名+返回类型+方法名是不一样的函数)
重载的实现是编译器根据函数的不同的参数表,对同名函数的名称做修饰,那么对于编译器而言,这些同名函数就成了不同的函数。但重写则是子类方法对父类的方法的延申,即子类不仅继承了父类的方法,还向父类的方法中添加了属于自己的内容,改变了父类方法原本的内容,而final代表了一种不可变,这明显与重写形成了冲突。因此被final修饰的类可以被重载但不能被重写
修饰变量不能被重新赋值——当final用来修饰变量时,代表该变量不可被改变,一旦获得了初始值,该final变量就不能被重新赋值。
6.【类型转化】类型自动转换:(自动往大了转)
两个数值进行二元操作时,会有如下的转换操作:
如果两个操作数其中有一个是double类型,另一个操作就会转换为double类型。
否则,如果其中一个操作数是float类型,另一个将会转换为float类型。
否则,如果其中一个操作数是long类型,另一个会转换为long类型。
否则,两个操作数都转换为int类型。 故,x==f1[0]中,x将会转换为float类型。
7.【接口关键字】可以修饰接口的关键字?
接口中字段的修饰符:public static final(默认不写)
接口中方法的修饰符:public abstract(默认不写)
8.【局部变量范围】变量及其范围:在方法中定义的局部变量在该方法被执行时创建,是错误的
不是局部变量在该方法被执行/调用时创建,而是应该为在该变量被声明并赋值时创建,可以理解为“当代码执行到该变量被赋值的代码时才被创建”
栈会为每个方法在运行的时候分配一块独立的栈帧内存区域,栈帧又包含“局部变量表”、“操作数栈”、“动态链接”以及“方法出口”四个部分。
9.【访问修饰符】private\protected\public?
Java中,可以使用访问控制符来保护对类、变量、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
· default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
· private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
· public : 对所有类可见。使用对象:类、接口、变量、方法
· protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)。
我们可以通过以下表来说明访问权限:
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
public | Y | Y | Y | Y | Y |
protected | Y | Y | Y | Y/N | N |
default | Y | Y | Y | N | N |
private | Y | N | N | N | N |
10. 【设计模式】说一下你熟悉的设计模式?
- 单例模式:保证被创建一次,节省系统开销。
- 工厂模式(简单工厂、抽象工厂):解耦代码。
- 观察者模式:定义了对象之间的一对多的依赖,这样一来,当一个对象改变时,它的所有的依赖者都会收到通知并自动更新。
- 外观模式:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。
- 模版方法模式:定义了一个算法的骨架,而将一些步骤延迟到子类中,模版方法使得子类可以在不改变算法结构的情况下,重新定义算法的步骤。
- 状态模式:允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。