Java类实例化澄清

时间:2015-01-16 19:16:42

标签: java class field instantiation

给出两个.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值。既然汽车没有被实例化(或有汽车?),你会说这个代码会发生什么?我的意思是,我可以看到Cars.class使用了Car.class,但是我无法形成正确的句子来描述为什么这有效。您如何描述这样一个概念,即创建一个类字段"来生活",就像它对新手一样?

6 个答案:

答案 0 :(得分:3)

不,不会。 Car.counter用于获取counterCar的引用。

关键字static表示字段counter属于整个类,而不是分隔对象的实例。因此,counter字段对Car的所有实例都具有相同的值。

答案 1 :(得分:1)

来自Oracle Docs

  

有时,您希望拥有所有对象共有的变量。这是使用static修饰符完成的。在声明中具有static修饰符的字段称为静态字段类变量。它们与类相关联,而不是与任何对象相关联。该类的每个实例共享一个类变量,该变量位于内存中的一个固定位置。任何对象都可以更改类变量的值,但也可以在不创建类实例的情况下操作类变量。

所以,回答你的问题。否 - 访问静态字段时,您实例化一个类。实际实例化对象的方法是调用其constructor。使用关键字new调用构造函数,构造函数名称与类名相同。

Car c = new Car(); // instantiation via constructor

为了描述你的情况:

  

Cars类使用Car类中的类变量。类变量与类关联并在类的每个实例之间共享。

答案 2 :(得分:1)

我假设你有两个文件Car.java& Cars.java,对应于您给定的代码。 现在,当您编译Cars.java时,它将自动创建Car.class以及Cars.class 实际上,运行Cars.class程序需要这个Car.class。如果您删除前者然后尝试运行Cars程序,您将获得以下异常:

Exception in thread "main" java.lang.NoClassDefFoundError: Car
        at Cars.main(Cars.java:3)
Caused by: java.lang.ClassNotFoundException: Car
        at java.net.URLClassLoader$1.run(Unknown Source)
        at java.net.URLClassLoader$1.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 Classloader是JRE的一部分,它将Java类动态加载到JVM中。初始化类时,所有静态变量实例都放在堆上。由于您的Cars.class程序引用了Car.class程序的静态变量,因此它也将它加载到JVM中。

请注意,加载与实例化完全不同。短语“实例化一个类”意味着创建一个类的“实例”。要实例化一个类,我们使用new运算符:

Car myCar = new Car();

new运算符通过为新对象分配内存并返回对该内存的引用来实例化一个类。此处的内存实例变量也将动态分配(根据需要)。请注意,每个实例都将分配一个新的内存空间。但是,它们仍将共享相同的静态分配变量。

因此,在您的程序中,您不是实例化 Car类,但您仍然加载到JVM中。

答案 3 :(得分:0)

您正在增加Car consyructor中的计数器。 这意味着只有在使用" new Car"创建Car的新实例时,计数器才会递增。代码不会实例化任何计数器为0的汽车。

答案 4 :(得分:0)

简单地说:

您可以将类视为对象的描述。类的实例是对象,遵循类文件中给出的描述规则。

但是描述本身也可以被视为遵循描述规则的对象。这个对象是类Class的实例 - 描述描述的描述;-):

System.out.println(Car.class instanceof Class); // true
System.out.println(Class.class instanceof Class); // true

所以你可以看到类有表示(例如Car.class),表示可以有字段和方法 - static

简单地说; - )

答案 5 :(得分:0)

static keyword表示整个类的单个副本,它不属于此类的任何特定实例。当您的类第一次加载到JVM中时,类初始化器会初始化类中的静态字段。