Java中,String也是一个类,我们用String这个类来说明问题;
new 运算符
public class HelloWorld{
public static void main(String[] args)
{
String a = "Jack";
String b = new String("Jack");
String c = "Jack";
String d = new String("Jack");
System.out.println(a==b); //false
System.out.println(a==c); //true
System.out.println(b==d); //false
}
}
【分析】
String a 只是在栈中创建一个String类的对象引用变量,变量名为a;
String a = “Jack”; 在栈中创建一个引用变量,然后查找栈中是否有“Jack”,如果有则直接指向,否则创建一个,再指向。
String c = new String(“Jack”); 在栈中创建一个引用String类的引用变量a,并在堆中创建一个对象,a指向堆中的这个对象。
==运算符在堆中比较的是地址,在栈中比较的是内容。因此a和c是true,因为他们内容相同。而new对象,就算对象内容是一样的,也会开辟新的空间,因此b和d为false,他们的地址不同。
匿名对象
匿名对象没有对象名,直接new一个,然后直接调用方法或者作为参数传递之类的,有点类似于Python中的lambda函数,函数简短,不需要函数名。
这里匿名对象一般只用一次,另外注意,就算是匿名对象也会在堆中开辟存储空间。
例如:
//匿名对象,直接new一个
new student("Jack").print();
//有名对象
student stu = new student("Jack");
那么问题来了,Java中堆和栈有什么区别呢?
Java的堆和栈
Java 把内存划分成两种:一种是栈内存,另一种是堆内存。在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
堆内存用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。
这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!
具体参考:Java中堆和栈的区别
一个对象被当作垃圾回收的情况主要有两种:
(1)超过了对象引用的作用域
Object object = new Object();
//object是一个对象引用,也是一个变量,当超出这个引用的作用域的时候,那么new的对象在堆中就没有引用指向它,被认为是垃圾。可能在某个时间被清除。
(2)对象被赋值为null
Object object = new Object();
object = null; //对象被赋值为null被视为垃圾
GC(Garbage Collection)
空对象
首先明确一点,null是一个特殊的引用类型,Java支持两种数据类型:一种是基本数据类型,另一种是引用数据类型。
当一个对象赋值为null之后,那么不会分配内存,但是对象的引用还存在。前面讲过,对象引用在栈中,对象在堆中。因此只是在栈中分配了一个小内存存放引用变量,而堆中不分配内存,因为这是一个空对象。
public class HelloWorld{
public static void main(String[] args)
{
String a = null;
System.out.println(a); //null
int len = a.length(); //抛出异常NullPointerException
}
}
不能调用空对象的属性和方法。
判断一个对象是否为空对象:
if(obj==null)
{
System.out.println("null");
}
注意:空字符串并不是空对象,空字符会分配内存,它的长度为0。
public class HelloWorld{
public static void main(String[] args)
{
String a = ""; //注意不能加空格,加了空格长度为1 : " "
boolean isNull = (a==null);
if(!isNull)
{
int len = a.length();
System.out.println(len);
}
}
}