如果有一个带有某些方法的类,每当我们创建一个新对象时,该对象都会在堆上创建字段和方法。如果我们有一个具有静态和普通方法的类,并且我们创建了此类的对象,则实例变量和普通方法仍然存在,但是静态方法是如何创建的?
所有方法(静态和非静态)都是类的一部分,类存储在非堆内存中。
驻留在堆中的所有内容都是包含以下内容的结构:
- 指向此对象为其实例的类的指针
- 每个非静态字段的当前值(对象字段的引用、基元字段的值)
所以例如:
public class Person {
private String name;
private int age;
public String getName() {
return name;
}
// ... etc.
}
非堆内存中的一个结构包含:
- 关于类的元数据,例如它的名字
Person
,指向其超类的指针等。 getName()
和任何其他方法的字节码- 字节码的 JIT 优化版本
对于Person
的每个实例,我们得到堆:
- 对类条目的引用
age
的整数值- 对
String
对象的引用name
因此,至少在概念上,您可以看到运行时处理对aPerson.getName()
的调用:
- 在堆中查看对象的记录
- 遵循对其类的引用
- 在类中,找到方法
getName()
- 运行该方法,使用堆中的字段对象记录
这意味着如果你有 1000 个Person
实例,你仍然只有来自类的代码的一个副本,这是完美的,因为它不会从一个实例更改为下一个实例。
如果Doctor
、Nurse
、Patient
都是Person
的子类,如果它们都没有覆盖getName()
,那么getName()
的代码仍然只在内存中存在一次。(概念上)当你调用aNurse.getName()
运行时将在Nurse
中查找getName()
,如果找到,则运行该,否则在超类Person
中查找,找到它并运行该。
我已经"概念上"说过几次了。实际上,我所描述的一些动态发生的事情可能在编译时静态发生。就理解对内存和性能的影响而言,这并不重要。