一、直接上图
1.举个例子
构造一个Person类
public class Person{
public String name;
public int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
}
实例化person类
Person 张三 = new Person("张三",18);
- 引用变量 张三 (指向堆中张三实例的地址)储存在栈中
- 张三实例(Person(“张三”,18))储存在堆中,
- 张三的实例的class,本类(Person),加载后储存在,方法区,
二、方法区的好处:提高性能。
1. 常量池
(1)避免重复的创建对象:销毁对象而影响系统性能,实现对象的共享
(2)节省内存空间: 常量池的所有的相同的字符串的常量被合并,只占用一个空间。
(3)节省运行时间:比较字符串时候, ( == ) 比 equals() 快,对于2个引用的变量,只用 ( == )
三、常用的面试题
1. String a = “str” 和 String b = new String(“str”) , a == b ?为什么?
回答:
a==b 是false的
- String a = “str” ; 会先在方法区的常量区找是否有字符串 “str”,有的话,直接把 方法区的常量区的"str"地址赋值给 a ,
没有的话就在方法区的常量区开辟一块空间,储存 "str"并赋值"str"的地址给a,
所以无论如何a的地址是指向方法区的常量区的 - String b = new String(“str”)的 b的地址是指向堆空间的
2. String a2 = “hello” ,String b2 = “he”+“llo”; a == b ?为什么?
回答
a2 == b2 为 true
b2 虽然为动态拼接 但是所有的拼接成分都是已知的储存在方法区的常量,这种拼接编译器会自动帮你优化好。
但是如果
String a2 = “hello”
String c2 = new String(“llo”)
String b2 = “he”+c2;
a2 == b2 为false;
因为c2指向储存在堆中的数据所以并不在方法区的常量区,b2会创建一个新的地址,鬼知道b2的地址在哪里,只有运行的时候才知道。