值类型和引用类型并不是不好区分. 我们常见的解释是这样的 -- 值类型保存的是具体的值, 引用类型保存的是值的地址.
之前看到一位大佬的解释, 觉得非常直白易懂. 值类型就是现金, 要直接引用; 引用类型是存折, 要用还得先去银行取现.
声明一个值类型变量, 编译器会在栈上分配一个空间, 这个空间对应着该值类型变量, 空间里存储的就是该变量的值.
引用类型的实例分配在堆上, 新建一个引用类型实例, 得到的变量值对应的是该实例的内存分配地址, 就像银行账号一样.
堆栈(stack)是一种先进后出的数据结构, 在内存中, 变量会被分配在堆栈上来进行操作. 堆(heap)是用于为类型实例分配空间的内存区域, 在堆上创建一个对象, 会将对象的地址传给堆栈上的变量(反过来叫变量指向此对象, 或者变量引用此对象)
例如:
public static void main(String[] args) {
int a = 1;
int b = a;
b++;
System.out.println(a);
System.out.println(b);
}
此时得到的结果是 a仍然是1, b是2
再看引用类型, 例如有个类型是Person
Person p1 = new Person(){Name ="mary"};
Person p2 = p1;
p2.Name ="jack";
此时可以看到结果都是jack, 因为p2 = p1的时候, p1和p2将指向同一个内存中的地址, 改变p2就等于改变了p1.
下面看一道京东的笔试题: (多选题) 有关值类型和引用类型描述正确的是( )
A. 值类型的变量赋值只是进行数据复制, 创建一个同值的新对象, 而引用类型变量赋值, 仅仅是把对象引用的指针赋值给变量, 使他们共用一个内存地址
B. 值类型数据是在栈上分配内存空间, 它的变量直接包含变量的实例, 使用效率相对较高. 而引用类型数据是分配在堆上, 引用类型的变量通常包含一个指向实例的指针, 变量通过指针来引用实例
C. 引用类型一般都具有继承性, 但是值类型一般都是封装的, 因此值类型不能作为其他任何类型的基类
D. 值类型变量的作用域主要是在栈上分配内存空间内, 而引用类型变量作用域主要在分配的堆上