今天回学校听米老师讲算法,结果一不小,我跟建敏引到了Java实例化,new这个问题上来,我们俩就偷偷的在下边开了个小会,自己组织了个简单的头脑风暴,真的是收获颇多啊。讨论的很激烈,但是有着很好效果,感谢建敏小朋友。
下边我就总结一下晚上讨论的问题,给我们这个问题一个完美的句号。
起因
这个就是我们讨论的问题:a b 两个实例化的是dog类,那么a b一样的吗? 由此我们得到了一系列的扩展,我们看a b两个实例,就要知道他们在内存当中的在哪,这就引出了堆和栈的概念。
什么是堆和栈?
Java 把内存划分成两种:一种是栈内存,另一种是堆内存。
栈内存:在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配,当在一段代码块定义一个变量时,Java 就在栈中为这个变量分配内存空间,当超过变量的作用域后(比如,在函数A中调用函数B,在函数B中定义变量a,变量a的作用域只是函数B,在函数B运行完以后,变量a会自动被销毁。分配给它的内存会被回收),Java 会自动释放掉为该变量分配的内存空间,该内存空间可以立即被另作它用。
堆内存:用来存放由 new 创建的对象和数组,在堆中分配的内存,由 Java 虚拟机的自动垃圾回收器来管理。
实例化过程
在堆中产生了一个数组或者对象之后,还可以在栈中定义一个特殊的变量,让栈中的这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或者对象,引用变量就相当于是为数组或者对象起的一个名称。引用变量是普通的变量,定义时在栈中分配,引用变量在程序运行到其作用域之外后被释放。而数组和对象本身在堆中分配,即使程序运行到使用 new 产生数组或者对象的语句所在的代码块之外,数组和对象本身占据的内存不会被释放,数组和对象在没有引用变量指向它的时候,才变为垃圾,不能在被使用,但仍然占据内存空间不放,在随后的一个不确定的时间被垃圾回收器收走(释放掉)。这也是 Java 比较占内存的原因,实际上,栈中的变量指向堆内存中的变量,这就是 Java 中的指针!
public class dog {
String name;
int age;
}
如图:
我们可以从上图中发现,对象名称a被保存在了栈内存中(更加准确的说法是,在栈内存中保存的是堆内存空间的访问地址),而对象的具体内容,比如属性name和age,被保存在了堆内存中。因为a对象只是被实例化,还没有具体被赋值,所以都是默认值。字符串的默认值为null,int类型的默认值为0。前面也已经提到,堆内存空间必须使用new关键字才能开辟。
创建多个对象
public static void main(String[] args){
dog a = new dog();
a.name = "小黑";
a.age=1;
dog b = new dog();
b.name = "小白";
b.age=1;
}
现在我们进行一下比较
这里又涉及到了 == 和 equals 的概念。
== :对于Java的8种基本数据类型的变量,变量直接存储的是“值”,因此在用关系操作符==来进行比较时,比较的就是 “值” 本身。而对于非基本数据类型的变量,在一些书籍中称作为 引用类型的变量。此时==比较的是其关联的对象在内存中的地址。由此可知 a == b 为false。
equals:equals方法不能作用于基本数据类型的变量,如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址,诸如String、Date等类对equals方法进行了重写的话,比较的是所指向的对象的内容。所以a.equals(b) 也是false。
暂时先整理到这里吧,再扯就回不来了。剩下的继续总结咯。