如果一个类A代码如下:特别注意age是私有的。
package test;public class A {
private int age;
public A() {
System.out.println("调用A的构造方法");
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}
有一个子类B继承了A类:
package test;public class B extends A{
public B() {
System.out.println("调用B的构造方法");
}
public static void main(String[] ss){
B b=new B();
//b.age=34;//没有继承,不能直接赋值
b.setAge(34);
System.out.println("b.age= "+b.getAge());
}
}输出结果是:
调用A的构造方法
调用B的构造方法
b.age= 34显然B不能继承父类的私有变量age,但是可以继承A类的getter/setter方法,当调用b的set方法给age赋值时,这个值“34”到底是赋给谁了?是A类的age么?如果是的话,似乎是当创建子类对象b时,也同时创建了A类的对象,(输出结果显示,在调用B类的构造方法时,也事先调用了A类的构造方法。)那么如果是在创建子类对象时父类对象也同时被创建了,那么、一个大的系统中要有多少个Object对象啊!
从另一个角度来看这个问题:如果A类是个抽象类,理论上抽象类是不能被实例化的,代码如下:
package test;public abstract class A {
private int age;
public A() {
System.out.println("调用A的构造方法");
}
public abstract void test();
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}B类代码:
package test;public class B extends A{ public B() {
System.out.println("调用B的构造方法");
}
public void test(){
System.out.println("实现的抽象方法test()");
}
public static void main(String[] ss){
B b=new B();
//A a=new A(); 不能被实例化
b.setAge(34);
System.out.println("b.age= "+b.getAge());
}
}
运行结果依然如故,谁能解释一下,这中间到底age从哪来,其中应该是怎样的过程。
package test;public class A {
private int age;
public A() {
System.out.println("调用A的构造方法");
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}
有一个子类B继承了A类:
package test;public class B extends A{
public B() {
System.out.println("调用B的构造方法");
}
public static void main(String[] ss){
B b=new B();
//b.age=34;//没有继承,不能直接赋值
b.setAge(34);
System.out.println("b.age= "+b.getAge());
}
}输出结果是:
调用A的构造方法
调用B的构造方法
b.age= 34显然B不能继承父类的私有变量age,但是可以继承A类的getter/setter方法,当调用b的set方法给age赋值时,这个值“34”到底是赋给谁了?是A类的age么?如果是的话,似乎是当创建子类对象b时,也同时创建了A类的对象,(输出结果显示,在调用B类的构造方法时,也事先调用了A类的构造方法。)那么如果是在创建子类对象时父类对象也同时被创建了,那么、一个大的系统中要有多少个Object对象啊!
从另一个角度来看这个问题:如果A类是个抽象类,理论上抽象类是不能被实例化的,代码如下:
package test;public abstract class A {
private int age;
public A() {
System.out.println("调用A的构造方法");
}
public abstract void test();
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}B类代码:
package test;public class B extends A{ public B() {
System.out.println("调用B的构造方法");
}
public void test(){
System.out.println("实现的抽象方法test()");
}
public static void main(String[] ss){
B b=new B();
//A a=new A(); 不能被实例化
b.setAge(34);
System.out.println("b.age= "+b.getAge());
}
}
运行结果依然如故,谁能解释一下,这中间到底age从哪来,其中应该是怎样的过程。
你自己调试下就明白了!
父类A中有age这个属性,B继承A后,当然也就有age这个属性了!
如果在B类中没重新设置这个age属性
在 b.setAge(34); 的时候,
会进到A中的 public void setAge(int age){
this.age=age;
}
setter方法设置age的值!
当你在B中重新设置了age属性,则就会调用自己类中的setter方法!
既然继承了A,当然就可以不用重复写雷同的代码,不然不就冗余了!public class A{
private int age;
public A() {
System.out.println("调用A的构造方法");
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
}public class B extends A{
public B() {
System.out.println("调用B的构造方法");
}
public static void main(String[] ss){
B b=new B();
//b.age=34;//没有继承,不能直接赋值
b.setAge(34);
System.out.println("b.age= "+b.getAge());
}
private int age;
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
} }你自己去调试下,就会明白上面我说的,赋值的时候,会从哪进去。你自己去调试就明白了!
package test;public class B extends A{
private int age;
public B() {
System.out.println("调用B的构造方法");
}
public void test(){
System.out.println("实现的抽象方法test()"+super.getAge()+" : "+this.age);
}
public static void main(String[] ss){
B b=new B();
//A a=new A();
b.setAge(34);
b.test();
System.out.println("b.age= "+b.getAge());
}
}输出结果是:调用A的构造方法
调用B的构造方法
实现的抽象方法test()34 : 0
b.age= 34显然B类自己的age没有被赋值,除非覆盖了A类的setAge方法,B类的age才会被赋值。这样的话,子类继承的方法,还不能算是真正是自己的,还是父类的。
如果不涉及继承跟static,用new创建对象时,会调用那个类的构造函数,而在调用构造函数之前必需先初始化域(因为在构造函数里,可能会用到这些成员变量)
等域初始化完后再调用构造函数。强调一点:只要是成员变量,那么不管它放在类的哪个部位(但在方法或块内部不算,因为那算是局部变量),它都在构造函数调用之前调用,这是编译器确保的。 2.
如果涉及继承,当用new创建子类对象时,调用顺序是这样的:
1.先初始化父类的域(成员变量或块)
2.调用父类的构造函数(没有明确定义的话,调用默认那个,即编译器为你创建的)
3.再到子类,初始化子类的域
4.这时才轮到调用子类的构造函数
原则是:要确保域在被调用之前要被初始化.
上面是涉及两层,如果是涉及多层继承的,那么一致递推上去,即先初始化父类的域,然后调用父类构造函数,再初始化子类的域然后再调用子类的构造函数,再初始化子子类的域(用这个名字好像有点怪,哈哈,就是孙子类的意思)然后再调用子子类的构造函数,一致类推下去
3.涉及static的话,static域是在编译的时候加载的,原则是:
1.static域是在非static(上面说的都是非static)之前调用的
2.static域只初始化一次(即只调用一次),打个比方A a = new A(); A 里有static域,只有当你第一次使用new创建对象的时候它会在非static之前调用,而如果你还想再用new创建对象时,static域这段代码是不会被调用的(因为static的东西是属于类,所以对象共享的,一次就够了) 4.如果涉及继承跟static结合的话(而这个是初始化里最难的,很多初学者会卡在这里),只要按照3.2结合就行了。