class ClassA {
void h() { }
}
class ClassB extends ClassA{
public static void main(String[] args){
ClassA a = new ClassA();
ClassB b = new ClassB();
}
}
是的,每个人都认为它很简单,必须且肯定应该只创建两个对象。
但是在我读到“Think in Java,2nd Edition”之后,我认为它可能包含一些更有趣的内容。
在“Think in Java”中,有一句话:“当你创建一个派生类的对象时,它包含一个基类的子对象。这个子对象就像你创建了一个对象一样基类本身。“
第2版第278页。你也可以通过这个链接“http://www.codeguru.com/java/tij/tij0065.shtml”(标题为“初始化基类”的部分)看到它。
答案 0 :(得分:13)
应为2. main
函数是静态的,因此它不需要对象。
ClassA a
是一个对象,ClassB b
是一个对象
编辑:ClassB不包含两个对象,因为extends是is-a
关系,而不是has-a
关系。 (ta mik)
编辑:还有运行时系统创建的String[]
对象,并且可能在该数组中放置任意数量的字符串对象。我有意无视这些,但承认它们可能存在。 (ta diveshpremdeep和Adam Goode)
最终编辑:为了确定创建了多少对象(通过程序,而不是运行时系统),您可以像命令一样在命令行上使用javap
程序(如果测试) .java包含你的例子)
$ javac test.java
$ javap -c ClassB
输出:
Compiled from "test.java"
class ClassB extends ClassA{
ClassB();
Code:
0: aload_0
1: invokespecial #1; //Method ClassA."<init>":()V
4: return
public static void main(java.lang.String[]);
Code:
0: new #2; //class ClassA
3: dup
4: invokespecial #1; //Method ClassA."<init>":()V
7: astore_1
8: new #3; //class ClassB
11: dup
12: invokespecial #4; //Method "<init>":()V
15: astore_2
16: return
}
正如您所看到的,只有两位字节码是new
(它创建了我假设的对象)。一个用于课程ClassA
,另一个用于课程ClassB
。您可以注意到之后调用invokespecial
命令来调用构造函数,以及如何从类ClassA
的构造函数中调用类ClassB
的构造函数,但是没有创建新对象在构造函数内部(它是默认的空构造函数)。
调用javap -c ClassA
显示了一个同样无聊的构造函数,它调用Object的构造函数。
总结:它是new
字节码,它在堆上创建对象,而不是仅仅填充invokespecial
字节码分配的内存细节的new
。
答案 1 :(得分:3)
调用3个构造函数来创建2个对象。
答案 2 :(得分:3)
如果您指的是main
方法块中的对象,那么2.这可以通过Java堆转储和以下代码扩展来验证:
class ClassA {
void h() { }
}
class ClassB extends ClassA{
public static void main(String[] args) throws Exception {
System.in.read();
main1(args);
System.in.read();
}
public static void main1(String[] args){
ClassA a = new ClassA();
ClassB b = new ClassB();
}
}
所以:
jmap -dump:format=b,file=snapshot1.jmap PROCESS_ID
jmap -dump:format=b,file=snapshot2.jmap PROCESS_ID
之后,您将获得两个可以比较的Java堆转储快照。
我得到了以下值(使用Java 1.6.0_15,OSX):
差异是2,也是创建对象的数量。
答案 3 :(得分:2)
创建了两个对象 - ClassA的实例和ClassB的实例。
调用新的ClassB()不会调用main()方法。默认构造函数,格式为
public ClassB() {}
将被使用。 ClassA也是如此。
答案 4 :(得分:1)
仅
虽然B
在创建A
时会延伸A
,B
中的构造函数会被执行,但最后只会创建A
中的一个对象。
1 B
+ 1 ClassA a = new ClassA();
a = new ClassB();
= 2个对象
至于:
“当您创建派生类的对象时,它在其中包含基类的子对象。此子对象与您自己创建基类的对象相同。”
这意味着,以下是可能的:
B
也就是说,您可以将B的实例分配给A类型的引用,因为:
“...此子对象与您自己创建基类的对象相同”
这就是"is-a"关系的全部意义所在。你可以说“每个B都是一个A”,这是真的。
你不能做的是调用A
中定义的{{1}}
我希望有所帮助。
答案 5 :(得分:0)
默认构造函数,自动调用super()(父默认构造函数)构造函数。如果您创建一个Class对象,也会创建一个ClassA对象。
答案 6 :(得分:0)
这似乎是您的教授要求您在抽象层面上思考的问题之一。
话虽如此,我愿意打赌其创建的4个对象:
1) Class A
2) Class B
3) String[]
4) Since there is no such thing as a string array it is a char array.
当然这只是一个纯理论上的想法