to 12楼:你所引用并同意的那种说法是错的。to 所有人:请仔细看看我在7楼和9楼的回复,如果不同意的话,请好好研究并实际运行一下下面的代码: abstract class AbstractBase { private int i; public int j; { // 看仔细哦,这不是构造方法,是实例初始化块,如果我没有实例化,这段怎么执行了呢? i = 20; j = 30; } public int getI() { return i; }}class Inherited extends AbstractBase { private int i; public int j;
TO F14 偶的观点是 比如这样2个类public class a{ private int i; public a(int i){ this.i = i; } public void f(){ } } public class b extends a{ private int j; public b(int j){ super(j); this.j = j; } public void g(){ } }那么 ,编译器把它弄成类似这样一个类,当然,实际上还是分开装到不同的class上面去 public class b extends a{ private int i; private int j; private a(int i){ this.i = i; } public b(int j){ a(j); this.j = j; } public void f(){ } public void g(){ } }然后new的时候,就按照这个东西来做一个Instance,所有数据都放进这个Instance里面包括类型信息,这样就算向上转型,所有信息也不会丢失所以只存在这一个Instance而已当然这只是我的推测而已,我没有任何证据可以证明
后来用JAVAP看了一下 发现new跟调用构造函数的方法是一样的:invokespecial #1; //Method a."<init>":(I)V 便以为调用构造函数便要分配内存了,但是又想了一下,用this调用会怎么样呢? 结果都是一样的:invokespecial #1; //Method a."<init>":(I)V 所以,我认为调用了构造函数不一定便要创建实例,所以我认为...(见F16) 如有错误,请指正...C:\java>javap -c b Compiled from "test.java" class b extends a{ public b(int); Code: 0: aload_0 1: iload_1 2: invokespecial #1; //Method a."<init>":(I)V 5: aload_0 6: iload_1 7: putfield #2; //Field j:I 10: returnpublic b(); Code: 0: aload_0 1: bipush 99 3: invokespecial #3; //Method "<init>":(I)V 6: returnpublic b(java.lang.String); Code: 0: aload_0 1: invokespecial #4; //Method "<init>":()V 4: returnpublic void g(); Code: 0: new #5; //class a 3: dup 4: bipush 9 6: invokespecial #1; //Method a."<init>":(I)V 9: pop 10: return}class a{ private int i; public a(int i){ this.i = i; } public void f(){ } } class b extends a{ private int j; public b(int j){ super(j); this.j = j; } public b(){ this(99); } public b(String s){ this(); } public void g(){ new a(9); } }
to zapdos:你的那种理解从实用主义角度来看也是无可厚非的,但和事实的真相还是有出入,呵呵。你的那个例子不具备一般性,请看我在14楼的例子,派生类和基类中同时存在变量i和j,如果按你的理解,派生类的实例中只有一个i和一个j,但实际上,是各有两个。构造函数的调用是建立实例的最后一步工作,当调用到构造函数的时候,实例已经基本上建好了。 很多人认为构造函数的调用是实例创建的开始,其实是结束。 所以这时没有多余的工作要做,按构造函数中的代码逐步执行就完了。
父类只是被作为基础的模板使用的,new出来的只是这个子类而已
调用构造函数只是为了正确地使用这个父类而已
new AbstractType();
但是它的部分实现是需要被实例化的
这就是子类在构造的时候把抽象父类能实例化的部分都实例化了 可继承的部分成为
自身不可分割的一部分 也符合面向对象的特性
换句话说,抽象类远没有大家想象的那么特殊,它和一般“具象类”的实质区别非常小。
父类只是被作为基础的模板使用的,new出来的只是这个子类而已
调用的是子类的构造方法,并没调用父类的
调用构造函数只是为了正确地使用这个父类而已
abstract class AbstractBase { private int i;
public int j; { // 看仔细哦,这不是构造方法,是实例初始化块,如果我没有实例化,这段怎么执行了呢? i = 20;
j = 30;
} public int getI() { return i; }}class Inherited extends AbstractBase { private int i;
public int j;
{ // 看仔细哦,这不是构造方法,是实例初始化块
i = 200;
j = 300;
} public void f() {
System.out.println("i = " + i); // 我自己有一个i,值是200
// System.out.println("i = " + super.i); // 我的超类实例中也有一个i,值是20,但是我不能访问
System.out.println("super.i = " + super.getI()); //这样就可以访问了 System.out.println("j = " + j); // 我自己有一个j,值是300
System.out.println("super.j = " + super.j); // 我的超类实例中也有一个j,值是30,可以访问
}
}public class AbstractStudy { public static void main(String[] args) {
new Inherited().f();
}}
偶的观点是
比如这样2个类public class a{
private int i;
public a(int i){
this.i = i;
}
public void f(){
}
}
public class b extends a{
private int j;
public b(int j){
super(j);
this.j = j;
}
public void g(){
}
}那么 ,编译器把它弄成类似这样一个类,当然,实际上还是分开装到不同的class上面去
public class b extends a{
private int i;
private int j;
private a(int i){
this.i = i;
}
public b(int j){
a(j);
this.j = j;
}
public void f(){
}
public void g(){
}
}然后new的时候,就按照这个东西来做一个Instance,所有数据都放进这个Instance里面包括类型信息,这样就算向上转型,所有信息也不会丢失所以只存在这一个Instance而已当然这只是我的推测而已,我没有任何证据可以证明
发现new跟调用构造函数的方法是一样的:invokespecial #1; //Method a."<init>":(I)V
便以为调用构造函数便要分配内存了,但是又想了一下,用this调用会怎么样呢?
结果都是一样的:invokespecial #1; //Method a."<init>":(I)V
所以,我认为调用了构造函数不一定便要创建实例,所以我认为...(见F16)
如有错误,请指正...C:\java>javap -c b
Compiled from "test.java"
class b extends a{
public b(int);
Code:
0: aload_0
1: iload_1
2: invokespecial #1; //Method a."<init>":(I)V
5: aload_0
6: iload_1
7: putfield #2; //Field j:I
10: returnpublic b();
Code:
0: aload_0
1: bipush 99
3: invokespecial #3; //Method "<init>":(I)V
6: returnpublic b(java.lang.String);
Code:
0: aload_0
1: invokespecial #4; //Method "<init>":()V
4: returnpublic void g();
Code:
0: new #5; //class a
3: dup
4: bipush 9
6: invokespecial #1; //Method a."<init>":(I)V
9: pop
10: return}class a{
private int i;
public a(int i){
this.i = i;
}
public void f(){
}
}
class b extends a{
private int j;
public b(int j){
super(j);
this.j = j;
}
public b(){
this(99);
}
public b(String s){
this();
}
public void g(){
new a(9);
}
}
现在我完全同意Dan1980 的观点
调用构造函数时,JVM都做了些什么呢?
谢谢
很多人认为构造函数的调用是实例创建的开始,其实是结束。
所以这时没有多余的工作要做,按构造函数中的代码逐步执行就完了。
{ // 看仔细哦,这不是构造方法,是实例初始化块,如果我没有实例化,这段怎么执行了呢? i = 20;
j = 30;
}
和直接写在所在类(如这里的AbstractBase类)的构造方法中作用是完全相同的,每一次构造方法被调用时都会被执行。
当使用"new Inherited()"创建子类Inherited对象时,会在Inherited构造方法执行过程中隐含通过"super();"调用其父类AbstractBase的缺省无参构造方法,super方式调用构造方法不会创建AbstractBase类的实例,同时隐含执行了前述的游离初始化块,这里初始化的仍是子类的实例。
从OOA开始学习整个OO才是正道!!
只有C++才是这样的一种伪动态的静态来实现动态绑定...