什么是字节码?采用字节码的好处?
在 Java 中,JVM 可以理解的代码就叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不针对一种特定的机器,因此,Java 程序无须重新编译便可在多种不同操作系统的计算机上运行。
包装类
- 包装类是为了解决基本数据类型无法面向对象编程所提供的
- 包装类与基本数据类型的转换:自动装箱、拆箱
- 包装类拆箱就是基本数据类型,基本数据类型装箱就是包装类型
- 包装类的应用场景
- 创建集合类声明的泛型只能用包装类。
- 基本数据类型会有默认值,包装类默认值可以是null
- 包装类作为参数,允许参数为null
String
- java8中,String内部使用char数组存储数据
- value数组使用final,意味着value数组初始化之后就不能再引用其他数组了
- final修饰的变量只能进行一次赋值操作,且赋值后不可修改
不可变性
- 可以缓存hash值,String可以用作hashMap的key
- 如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用。只有 String 是不可变的,才可能使用 String Pool。
- String 经常作为参数,String 不可变性可以保证参数不可变。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 的那一方以为现在连接的是其它主机,而实际情况却不一定是。
- String 不可变性天生具备线程安全,可以在多个线程中安全地使用。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
字符串常量池
- 字符串常量池的设计意图?
字符串作为最基础的数据类型,大量频繁创建字符串分配内存空间会极大的影响程序的性能,JVM为了提高性能和减少内存消耗。
(1)每次创建字符串常量会首先在字符串常量池中判断是否存在该字符串
(2)存在该字符串就返回其引用实例,不存在,实例化该字符串并放入池中,由于字符串是不可变的所以不用担心数据因为共享而发生冲突。
(3)字符串常量池中存储着一个表用于维护每个字符串对象的引用。 - 字符串常量池在哪里?
字符串常量池则存在于方法区 - 如何操作字符串常量池?
java.lang.String.intern()使new创建的字符串对象指向字符串常量池中,如果不存在就创建一个,返回的是一个字符串常量池中的引用。
String, StringBuffer and StringBuilder
String:不可变字符串;
底层是 private final char value[];
StringBuffer:可变字符串、效率低、线程安全;
char[] value; (无final修饰可以改变)
StringBuffer 的操作函数append,append 方法是由 synchronized 修饰的,是线程安全的。
StringBuilder:可变字符序列、效率高、线程不安全;
char[] value; (无final修饰可以改变)
对于 StringBuilder 和 StringBuffer 的区别可以从下面的这张图片上看出,对于append()方法,缺少了synchronized 修饰,这使得 StringBuilder 不是一个线程安全。
总结
不可变性上,首先分析三个的底层结构,String的底层结构final修饰的字符数组,其余两个都是无final修饰的字符数组,String是不可变。
线程安全上,首先由于String的不可变所以它是线程安全的,StringBufffer的append追加方法是synchronized 修饰的同步方法,而StirngBuiler无synchronized 修饰,所以buffer是线程安全的。
String Pool 字符串常量池
字符串常量池(String Pool)保存着所有字符串字面量(literal strings),这些字面量在编译时期就确定。不仅如此,还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。
当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。
值传递与引用传递
https://juejin.im/post/6844903943462453256
值传递与引用传递主要用在方法参数的传递上
- 如果方法参数传递的是基本类型,则是值传递,传递的是基本类型字面量值的拷贝
- 如果方法参数传递的是引用类型,则传递的是该变量所引用对象的堆内存地址的拷贝。
java中方法参数传递方式是按值传递。 如果参数是基本类型,传递的是基本类型的字面量值的拷贝。 如果参数是引用类型,传递的是该参量所引用的对象在堆中地址值的拷贝。
基本数据类型作为参数传递
- 基本类型作为参数传递–传递的是值的拷贝,无论如何改变这个拷贝,原来的值是不会改变的。
public static void main(String[] args) {
//基本类型作为参数传递
int num = 2;
System.out.println("before change , num = " + num);
changeData(num);
System.out.println("after change , num = " + num);
}
public static void changeData(int num) {
num = 10;
}
before change , num = 2
after change , num = 2
对象作为参数传递
public static void main(String[] args) {
//对象作为参数传递
A a = new A("hello");
System.out.println("before change , a.str = " + a.str);
changeData(a);
System.out.println("after change , a.str = " + a.str);
}
public static void changeData(A a) {