String ,StringBuffer ,StringBuilder的区别?


字符串拼接用+还是StringBuilder

查看.class文件的字节码

示例截图: 用的就是 + 拼接字符串示例

字符串对象通过+的字符串拼接⽅式,实际上是通过StringBuilder调⽤append()⽅法实现的,拼接完成之后调⽤toString()得到⼀个 String对象 。

注意事项 :
在循环内使⽤+进⾏字符串的拼接的话,存在比较明显的缺陷:编译器不会创建单个 StringBuilder 以复⽤,会导致创建过多的 StringBuilder对象。


String#equals() 和 Object#equals() 有何区别

String : 比较的是值是否相等;
Object : 比较的是对象的内存地址是否相等;


字符串常量池的作⽤

字符串常量池JVM 为了提升性能和减少内存消耗针对字符串(String 类)专⻔开辟的⼀块区域,主要⽬的是为了避免字符串的重复创建


创建了⼏个字符串对象? String s1 = new String("abc");

String s1 = new String(“abc”) 这段代码创建了几个字符串对象?


String类型的变量和常量做+运算时发生了什么?

+++ 点击展开/隐藏

字符串不加final关键字拼接的情况

String str1 = "str"; //编译器确定常量字符串,jvm将其加入`字符串常量池`
String str2 = "ing"; //编译器确定常量字符串,jvm将其加入`字符串常量池`
String str3 = "str" + "ing"; //常量折叠: String str3 = "string"
String str4 = str1 + str2; //引用的值在编译器无法确定,jvm无法将其优化
String str5 = "string";
System.out.println(str3 == str4);//false
System.out.println(str3 == str5);//true
System.out.println(str4 == str5);//false

编译器的优化:

  1. 编译期可以确定的值的字符串,也就是常量字符串,jvm会将其存入字符串常量池.
  2. 字符串常量拼接可以得到的字符串常量编译阶段已经被存放字符串常量池.

编译器优化: 常量折叠

常量折叠会把常量表达式的值求出来作为常量嵌在最终⽣成的代码中,这是 Javac 编译器会对源代码做的极少量优化措施之⼀(代码优化⼏乎都在即时编译器中进⾏)。

例如: 对于 String str3 = “str” + “ing”; 编译器会给你优化成 String str3 = “string”;

常量折叠的条件:

  • final修饰 / 无final修饰的基本数据类型(byte,short,int,long,double,float,chat,boolean)及字符串常量
  • 运算关系
    • 字符串通过+拼接得到的字符串
    • 基本数据类型之间的算数运算(加减乘除),位运算(<<,>>,>>>)

引⽤的值在程序编译期是⽆法确定的,编译器⽆法对其进⾏优化

对象引⽤和“+”的字符串拼接⽅式,实际上是通过 StringBuilder 调⽤ append() ⽅法实现的,拼接完成之后调⽤ toString() 得到⼀个 String 对象

String str4 = new StringBuilder().append(str1).append(str2).toString();

声明final关键字之后,可以让编译器当作常量处理

final String str1 = "str";
final String str2 = "ing";
// 下⾯两个表达式其实是等价的
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 常量池中的对象
System.out.println(c == d);// true

被 final 关键字修改之后的 String 会被编译器当做常量来处理,编译器在程序编译期就可以确定它的值,其效果就相当于访问常量。

截图参考

没有final关键字修饰的字符串,字节码中通过StringBuilder拼接(属于新的对象,==用来比较引用类型是比较的内存地址是否相等)

编译器在运⾏时才能知道其确切值的话,就⽆法对其优化

final String str1 = "str";
final String str2 = getStr();
String c = "str" + "ing";// 常量池中的对象
String d = str1 + str2; // 在堆上创建的新的对象
System.out.println(c == d);// false
public static String getStr() {
return "ing";
}

+++


Exception 和 Error 有什么区别?


try-catch-finally 的使⽤

注意事项:

不要在finally语句块中使用return!

当 try 语句和 finally 语句中都有 return 语句时,try 语句
块中的 return 语句会被忽略。这是因为 try 语句中的 return 返回值会先被暂存在⼀个本地变量中,当执⾏到 finally 语句中的 return 之后,这个本地变量的值就变为了 finally 语句中的 return 返回值。

代码示例:

public static void main(String[] args) {
System.out.println(f(2));
}

public static int f(int value) {
try {
return value * value;
} finally {
if (value == 2) {
return 0;
}
}
}

输出:

0

finally 中的代码是否⼀定会执⾏

==不⼀定的!==

不会执行finally中的代码情况如下:

  • finally 之前虚拟机被终⽌运⾏的话
  • 程序所在线程死亡
  • 关闭CPU

try-catch-finally关闭资源?

try-catch-finally关闭资源?


什么是SPI

SPI 即 Service Provider Interface ,字⾯意思就是: 服务提供者的接⼝

API 和 API 的区别

SPI : 由接口调用方确定规则,不同的接口实现方去根据这个接口进行实现,从而提供方服务.

SPI 的优缺点

  • 需要遍历加载所有的实现类,不能做到按需加载,这样效率还是相对᫾低的
  • 当多个 ServiceLoader 同时 load 时,会有并发问题

什么是序列化?什么是反序列化?

序列化: 将数据结构或对象转换成⼆进制字节流的过程
反序列化: 将在序列化过程中所⽣成的⼆进制字节流转换成数据结构或者对象的过程

序列化目的: 序列化的主要⽬的是通过⽹络传输对象或者说是将对象存储到⽂件系统、数据库、内存中

部分字段不想进⾏序列化处理

transient 关键字的作⽤是:阻⽌实例中那些⽤此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。

注意事项:

  • 修饰变量,不能修饰类和⽅法
  • 在反序列化后变量值将会被置成类型的默认值。例如,如果是修饰 int类型,那么反序列后结果就是 0 。
  • static 变量因为不属于任何对象(Object),所以⽆论有没有 transient 关键字修饰,均不会被序列化。

Java IO 流

  • InputStream\OutputStream 字节输入流\字节输出流
  • Reader\Writer 字符输入流\字符输出流

Java中设计模式

JavaGuide|Java IO 设计模式总结


BIO、NIO 和 AIO 的区别?