Java class 实例化说明
Java class instantiation clarification
给定两个 .java 文件:
// Car.java
class Car {
static int counter = 0; // Class field
Car () { counter++;}
}
和
// Cars.java
public class Cars{
public static void main(String[] args){
System.out.println(Car.counter); // Does this instantiate a Car?
}
}
我正在学习 Java,我只是想在这里做到准确(迂腐?)。
编译,然后执行 java Cars
产生 0
的正确值。由于 Car 尚未实例化(或已实例化?),您认为这段代码中会发生什么?我的意思是,我可以看到 Cars.class 使用了 Car.class,但我无法形成正确的句子来描述其工作原理。您如何向新手描述制作 class 字段 "come to life" 的概念?
不,不会。 Car.counter
用于获取对Car
中counter
的引用。
关键字static
表示字段counter
是属于整个class的东西,而不是分隔对象的实例。因此,counter
字段对于 Car
.
的所有实例具有相同的值
您正在递增 Car consyructor 中的计数器。
这意味着只有当您使用 "new Car" 创建 Car 的新实例时,计数器才会增加。该代码没有实例化任何 Car 是 way counter 是 0.
来自Oracle Docs:
Sometimes, you want to have variables that are common to all objects. This is accomplished with the static
modifier. Fields that have the static
modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.
所以,回答你的问题。否 - 在访问静态字段时,您 不会 实例化一个 class。实际实例化一个对象的方式是调用它的 constructor。使用关键字 new
调用构造函数,构造函数名称与 class 名称相同。
Car c = new Car(); // instantiation via constructor
为了描述您的案例:
The Cars
class uses a class variable from the Car
class. Class variables are associated with the class and shared between every instance of the class.
简单地说:
您可以将 classes 视为对象的描述。 class 的实例是对象,它们遵循 class 文件中给出的描述规则。
但是描述本身也可以看作是遵循描述规则的对象。此对象是 class Class
的实例 - 描述描述 ;-) :
System.out.println(Car.class instanceof Class); // true
System.out.println(Class.class instanceof Class); // true
因此您可以看到 classes 具有表示(例如 Car.class),并且表示可以具有字段和方法 - static
。
简单地说;-)
我假设您有两个文件 Car.java 和 Cars.java,对应于您给定的代码。
现在,当你编译 Cars.java 时,它会自动创建 Car.class 和 Cars.class
事实上,这个 Car.class 是 运行 Cars.class 程序所需要的。如果您删除前者然后尝试 运行 宁汽车程序,您将得到以下异常:
Exception in thread "main" java.lang.NoClassDefFoundError: Car
at Cars.main(Cars.java:3)
Caused by: java.lang.ClassNotFoundException: Car
at java.net.URLClassLoader.run(Unknown Source)
at java.net.URLClassLoader.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more
注意这里的异常来源
java.lang.ClassLoader.loadClass
Java 类加载器是 JRE 的一部分,可将 Java classes 动态加载到 JVM 中。当一个class被初始化时,所有的静态变量实例都放在堆上。由于您的 Cars.class 程序引用了 Car.class 程序的静态变量,它也将它加载到 JVM 中。
请注意,加载与实例化有很大不同。短语 "instantiating a class" 表示创建一个 class 的 "instance"。要实例化一个 class,我们使用 new 运算符作为:
Car myCar = new Car();
new 运算符通过为新对象分配内存并返回对该内存的引用来实例化 class。这里实例变量的内存也将动态分配(根据需要)。请注意,每个实例都会分配一个新内存space。但是,它们仍将共享相同的静态分配变量。
所以,在您的程序中,您没有实例化 Car class,但您仍然加载它到JVM。
static 关键字表示整个 class 的单个副本,它不属于此 class 的任何特定实例。 class 中的静态字段在 class 首次加载到 JVM 时由 class 初始化程序初始化。
给定两个 .java 文件:
// Car.java
class Car {
static int counter = 0; // Class field
Car () { counter++;}
}
和
// Cars.java
public class Cars{
public static void main(String[] args){
System.out.println(Car.counter); // Does this instantiate a Car?
}
}
我正在学习 Java,我只是想在这里做到准确(迂腐?)。
编译,然后执行 java Cars
产生 0
的正确值。由于 Car 尚未实例化(或已实例化?),您认为这段代码中会发生什么?我的意思是,我可以看到 Cars.class 使用了 Car.class,但我无法形成正确的句子来描述其工作原理。您如何向新手描述制作 class 字段 "come to life" 的概念?
不,不会。 Car.counter
用于获取对Car
中counter
的引用。
关键字static
表示字段counter
是属于整个class的东西,而不是分隔对象的实例。因此,counter
字段对于 Car
.
您正在递增 Car consyructor 中的计数器。 这意味着只有当您使用 "new Car" 创建 Car 的新实例时,计数器才会增加。该代码没有实例化任何 Car 是 way counter 是 0.
来自Oracle Docs:
Sometimes, you want to have variables that are common to all objects. This is accomplished with the
static
modifier. Fields that have thestatic
modifier in their declaration are called static fields or class variables. They are associated with the class, rather than with any object. Every instance of the class shares a class variable, which is in one fixed location in memory. Any object can change the value of a class variable, but class variables can also be manipulated without creating an instance of the class.
所以,回答你的问题。否 - 在访问静态字段时,您 不会 实例化一个 class。实际实例化一个对象的方式是调用它的 constructor。使用关键字 new
调用构造函数,构造函数名称与 class 名称相同。
Car c = new Car(); // instantiation via constructor
为了描述您的案例:
The
Cars
class uses a class variable from theCar
class. Class variables are associated with the class and shared between every instance of the class.
简单地说:
您可以将 classes 视为对象的描述。 class 的实例是对象,它们遵循 class 文件中给出的描述规则。
但是描述本身也可以看作是遵循描述规则的对象。此对象是 class Class
的实例 - 描述描述 ;-) :
System.out.println(Car.class instanceof Class); // true
System.out.println(Class.class instanceof Class); // true
因此您可以看到 classes 具有表示(例如 Car.class),并且表示可以具有字段和方法 - static
。
简单地说;-)
我假设您有两个文件 Car.java 和 Cars.java,对应于您给定的代码。 现在,当你编译 Cars.java 时,它会自动创建 Car.class 和 Cars.class 事实上,这个 Car.class 是 运行 Cars.class 程序所需要的。如果您删除前者然后尝试 运行 宁汽车程序,您将得到以下异常:
Exception in thread "main" java.lang.NoClassDefFoundError: Car
at Cars.main(Cars.java:3)
Caused by: java.lang.ClassNotFoundException: Car
at java.net.URLClassLoader.run(Unknown Source)
at java.net.URLClassLoader.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
at java.lang.ClassLoader.loadClass(Unknown Source)
... 1 more
注意这里的异常来源
java.lang.ClassLoader.loadClass
Java 类加载器是 JRE 的一部分,可将 Java classes 动态加载到 JVM 中。当一个class被初始化时,所有的静态变量实例都放在堆上。由于您的 Cars.class 程序引用了 Car.class 程序的静态变量,它也将它加载到 JVM 中。
请注意,加载与实例化有很大不同。短语 "instantiating a class" 表示创建一个 class 的 "instance"。要实例化一个 class,我们使用 new 运算符作为:
Car myCar = new Car();
new 运算符通过为新对象分配内存并返回对该内存的引用来实例化 class。这里实例变量的内存也将动态分配(根据需要)。请注意,每个实例都会分配一个新内存space。但是,它们仍将共享相同的静态分配变量。
所以,在您的程序中,您没有实例化 Car class,但您仍然加载它到JVM。
static 关键字表示整个 class 的单个副本,它不属于此 class 的任何特定实例。 class 中的静态字段在 class 首次加载到 JVM 时由 class 初始化程序初始化。