我们在 对象的创建与使用 的教程中了解到,对象的创建是通过对类进行 new。那么创建好的对象它在 jvm 内存 里面是怎么存在的的呢?
在学习 数组的内存空间 的时候,我们了解了数组它是怎么样存放的,对象的存储与数组一样,也分为堆区和栈区。
在创建每个对象的时候,(java 里面对创建对象也叫做类的实例化)我们会给每个对象定义一个名字,然后 new 加类的名字来具体的对象来赋值。
我们以对象的创建与使用里面的例子,动物来描述,具体的存储如下图:
从上图中我们可以看到,对象的名称在栈内存中存储(方便理解,其实是栈内存中存储的是对应的堆内存的地址),而对象的具体内容在对应的堆内存中,必须要使用 new 关键字来开辟堆内存空间,在堆内存中保持着对象的属性信息。
对象在使用之前是必须要被实例化的,如果一个对象被定义,但是没有被实例化,那么在运行过程中会抛出异常,java 程序将不会继续运行下去。
前面我们已经介绍过创建一个对象,创建多个对象和创建一个对象一样,但是名字不能相同,我们还是以动物创建为例子,Animal.java 类
package com.haicoder.net.clas;
/**
*
*/
public class Animal {
String clolr;//颜色
int age; //年龄
String animalName;
public void eat(String foodName){
System.out.println("动物名字 : " + animalName +" 在吃 " + foodName); //打印出动物的名字,方法里面的具体操作
}
public String getClolr() {
return clolr;
}
public void setClolr(String clolr) {
this.clolr = clolr;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getAnimalName() {
return animalName;
}
public void setAnimalName(String animalName) {
this.animalName = animalName;
}
}
package com.haicoder.net.clas;
/**
* java 测试类
*/
public class AnimalTest {
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
Animal cat = new Animal(); //定义一个对象
cat.animalName = "猫";
cat.eat("鱼");
Animal dog = new Animal();
dog.animalName = "狗";
dog.eat("骨头");
System.out.println("Over");
}
}
我们可以看到,我们为 Animal 类创建了 dog 和 cat 两个对象,他们的运行结果如下,他们是用 Animal 类 new 类两次,创建了两个不同的对象。
我们可以看到创建的两个动物,一个是猫一个是狗,他们都在做自己对应的事情。内存结构图如下:
package com.haicoder.net.clas;
/**
* java 测试类
*/
public class AnimalTest {
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
Animal cat = new Animal(); //定义一个对象
cat.animalName = "猫";
cat.eat("鱼");
Animal dog = cat;
dog.animalName = "狗";
dog.eat("骨头");
System.out.println("猫对象的动物名字: " + cat.animalName);
System.out.println("Over");
}
}
我们在创建 dog 对象的时候,直接将 cat 的名字给了 dog,意思就是创建动物对象的时候, dog 和 cat 指向同一个堆内存地址。运行结果如下:
我们看到,运行后的猫对象的名字也变成了狗了,因为猫和狗对象指向的堆内存空间是一样的,任何一个对象堆数据进行修改,另一个指向同一个堆的对象数据也会改变。内存结构如下:
我们看到 cat 和 dog 指向的堆地址空间是一样的,所以如果两个对象名称指向同一个对象,那么任意一个对象改变了里面的数据信息,另位指向相同堆地址的对象就能够看到变化的数据。
我们知道,对象的创建的时候,会先定义一个对象名称,然后在 new 一个对象给该对象名称。对象的存储空间是先将名称存在栈上面,在将栈上面记录的地址指向堆。匿名对象表示只在堆上面开辟空间,不会占用栈的任何空间。
package com.haicoder.net.clas;
/**
* java 测试类
*/
public class AnimalTest {
public static void main(String[] args) {
System.out.println("嗨客网(www.haicoder.net)");
new Animal().eat("好吃的食物!");
}
}
运行结果如下:
我们可以看到,匿名对象的创建与一般对象创建一样,只不过匿名对象没有对一个对象名称赋值,而是直接 new 然后调用对象里面的方法,打印结果,名字为 null
,是因为我们没有对对象里面的属性 animalName
赋值,String
类型的数据,默认值是 null
。
Java 语言创建多个对象和创建一个对象一样,可以用 new 关键字加类名称来创建对象,创建多个对象的时候,我们如果用 new 来创建不同的对象的时候,他们指向的堆地址空间是不一样的,数据的变化不会影响其他的对象,如果对象创建赋值的时候通过其他已经创建好的对象赋值,那么指向相同的堆内存空间。
堆内存空间相同,那么一个数据变化,剩下的相同的指向该堆区域的对象数据也会变化。
匿名对象和普通对象的创建一样,都是通过 new 方法来创建,只不过,匿名对象只会在堆空间上面生成对象,在栈里面不会占用内存空间。