Java程序在运行过程中不断地创建对象,那么对象创建的过程是怎样的,它又是如何在内存中占据一定的布局呢?下面我们就来详细探究一下Java对象创建的过程及内存布局。
Java对象创建的过程
1.类加载
在Java程序开始运行之前,会先将所有需要用到的类加载到内存中,并建立类与类之间的联系,形成类的层次结构。这个过程中有一个重要的概念——类加载器(class loader),它负责将类文件加载到内存中,使程序可以对其进行解释执行。
2.类的实例化
当程序中需要用到某个类的对象时,就需要对该类进行实例化。Java中的类实例化通过“new”关键字实现。例如:
Student stu = new Student();
这段代码就是将Student类进行实例化,并在内存中创建一个名为“stu”的Student类的对象。
3.分配内存
在虚拟机中,对象的实例化会在堆内存中分配一块足够大的空间。大小由对象的类型以及结构决定。例如Student类中可能包含了一些基本类型的成员变量和对象类型的成员变量,根据内存对齐的原则,内存管理器会为其分配一块连续的区域。并且这部分内存不是连续的,而是分配到堆的任意部分。
4.初始化
对象的初始化涉及到构造函数,在创建一个新对象时,会调用这个对象的构造函数来初始化它的成员变量和对象特有的变量(通常是指类的静态变量)。在调用构造函数之前,系统会先将对象分配到内存中,并对内存进行初始化。
5.对象成员变量的初始化
在创建对象并调用了构造函数之后,系统会将对象内的所有成员变量的值都初始化为默认值,例如int类型的变量会被初始化为0,String类型的变量会被初始化为空字符串"",而自定义类型的变量(对象类型)则会被初始化为null。
Java对象内存布局
Java对象在内存中的布局由三部分组成:对象头、实例数据和填充数据。
1.对象头
Java对象的头信息包括两部分:Mark Word和Class Pointer。
Mark Word是JVM为了实现各种功能所设计的一个内存结构,它记录了对象的锁状态、GC年龄、标识信息等具体内容。而Class Pointer则指向对象所属类的Class对象,这部分内容在对象的生命周期中不发生改变,因此JVM可以通过对象头部的信息定位到它的Class。
2.实例数据
实例数据区是对象的成员变量存放的地方,包括对象的成员变量以及从父类继承下来的成员变量。这些数据根据其类型分别被存储在对象内存区的不同部位。
3.填充数据
填充数据区是为了Java对象在内存中对齐而设置的,因为Java虚拟机规定,每个对象的大小必须是8字节的整数倍。如果实例数据域的大小没有到达8的整数倍,那么就需要填充一些不需要的数据来凑齐8的整数倍。
示例1
下面是一个简单的示例,实现一个Student类,并通过“new”关键字来创建Student类的对象:
public class Student {
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, my name is " + name + ", and I'm " + age + " years old.");
}
public static void main(String[] args) {
Student stu = new Student("Tom", 20);
stu.sayHello();
}
}
该程序中,我们定义了一个Student类,并在其中定义了两个成员变量name和age。然后我们通过构造函数将它们初始化,并在对象创建之后调用了sayHello()方法输出对象的信息。
输出结果为:
Hello, my name is Tom, and I'm 20 years old.
示例2
下面是一个比较复杂的示例,让我们看到在类的继承关系中,Java对象在内存中的布局是如何实现的。
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void sayHello() {
System.out.println("Hello, my name is " + name + ", and I'm " + age + " years old.");
}
}
class Student extends Person {
private String schoolName;
private String className;
public Student(String name, int age, String schoolName, String className) {
super(name, age);
this.schoolName = schoolName;
this.className = className;
}
public void sayHello() {
super.sayHello();
System.out.println("I'm a Student, and my school name is " + schoolName + ", and my class name is " + className + ".");
}
}
public class Main {
public static void main(String[] args) {
Student stu = new Student("Tom", 20, "Harvard University", "Math 101");
stu.sayHello();
}
}
该程序中,我们使用继承关系来实现Student类,其中Student类继承了Person类,它们各自具有不同的成员变量和方法。通过构造函数,我们实现了这些成员变量在对象创建时的初始化,并在对象创建之后调用了sayHello()方法输出对象的信息。
输出结果为:
Hello, my name is Tom, and I'm 20 years old.
I'm a Student, and my school name is Harvard University, and my class name is Math 101.
可以看到,Student类通过继承Person类的方式添加了两个成员变量,并覆写了父类的sayHello()方法,在输出信息时包含了新定义的成员变量的信息,这说明Java对象在内存中的布局是支持类的继承关系的。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:详解Java对象创建的过程及内存布局 - Python技术站