2015-01-16 130 views
0

给定两个.java文件: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,但我无法形成正确的句子来描述为什么这会起作用。您如何描述这样一个概念:让一个阶级领域“复活”,像一个新手一样?

+0

也许我应该澄清我的问题。好的,所以我明白没有Car对象会被实例化。我进一步理解了类字段和实例字段之间的区别。我不清楚的是,因为没有任何对象被实例化,所以Car“成立”是如何返回'0'的值?也许我只是想太多了。 – Sanuglia

+0

'counter'是一个*类变量*。你不需要一个对象来访问一个*类变量*。 – pbaldauf

回答

1

我假设你有两个文件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$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类加载器是JRE的一部分动态将Java类加载到JVM中。当一个类被初始化时,所有静态变量实例被放置在堆上。由于您的Cars.class程序引用了Car.class程序的静态变量,因此它也将其加载到JVM中。

请注意,加载与实例化有很大不同。 “实例化类”一词意味着创建一个类的“实例”。实例化一个类,我们使用new运算符为:

Car myCar = new Car(); 

新员通过一个新的对象分配内存,并返回到内存的引用实例化一个类。这里的实例变量的内存也将被动态分配(根据需要)。请注意,每个实例将被分配一个新的内存空间。但是,它们仍将共享相同的静态分配变量。

所以,在你的程序中,你是不是实例 Car类,但你仍然装载入JVM。

+0

宾果!这个解释巩固了我的理解。谢谢!! – Sanuglia

3

不,它不会。 Car.counter用于获取对Car中的counter的引用。

关键字static意味着该字段counter是属于整个类,而不是分开对象的实例。因此,counter字段对于所有Car的实例具有相同的值。

+1

值得一提静态修饰符:) –

+1

@JorgeCampos,感谢您的提示,我详细阐述了一下;) –

+0

这是一个非常好的答案,尽管我的问题偏离了中心。感谢Niels! – Sanuglia

0

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

1

Oracle Docs

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

所以,要回答你的问题。否 - 当访问一个静态字段时,你做而不是实例化一个类。实际实例化对象的方式是调用它的constructor。通过使用关键字new调用构造函数,构造函数名称与类名称相同。

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

为了描述你的情况:

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

0

简单地说:

你可以考虑类作为对象的描述。类的实例是对象,遵循类文件中给出的描述规则。

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

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

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

简单地说;-)

0

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