19

Below I am Having Two classes.Parent and Child. The Child class inherits from Parent class .In Parent class constructor I am calling print() method of Parent class.

When I create Object for Child class in main() method the Parent class constructor runs and the Child class print() method is called instead of Parent class print() method.

Q1. Why this Happens.

Q2. Why the value of i is 0

public class Sample
{
    public static void main(String[] args) 
    {
        Child objChild = new Child();
        objChild.print();
    }
}

class Parent
{   
    void print()
    {
        System.out.println("i Value");
    }

    Parent()
    {
        print();
    }
}    

class Child extends Parent
{
    int i = 45;

    void print()
    {
        System.out.println("i Value = "+i);
    }
}

OP

i Value = 0
i Value = 45
4

6 回答 6

19

调用子方法的原因是因为虚拟方法分派是 Java 中的规范。当您调用该方法时,它会根据对象的实际类型决定在运行时实际调用哪个方法。

至于为什么打印0,那是因为i还没有设置为45。0在整数的情况下,每个字段都使用该类型的默认值进行初始化。当你编写int i = 45时,编译器会在构造函数中生成代码来设置i = 45。但是它将这段代码放在调用父构造函数之后。因此,您在使用预期值初始化变量之前打印变量。

于 2013-04-24T05:16:37.767 回答
10

Java 实际上对此有一些非常明确的规则。本质上,子类中的“int i = 45”代码是子类构造函数的隐含部分,超类构造函数总是首先运行。

事件顺序为:

  • 创建对象并将所有实例变量清零。
  • 调用超类初始化器。
  • 调用超类构造函数。
  • 调用子类初始化器(int i = 45;在本例中)
  • 调用子类构造函数。

当你有一个 final 字段时,这会变得非常讨厌。您可以在示例中声明“i”final 并获得相同的结果!

通常,在构造函数中调用非私有(或至少非最终)方法是自找麻烦,并且通常是令人讨厌的错误的根源。调用抽象方法是一个非常糟糕的主意(大多数时候)。

于 2013-04-24T05:24:23.230 回答
4

Java初学者:我遇到了你的问题.. 1.当你创建子类的对象时, print() 方法只在子类而不是在父类中调用,即使父类构造函数首先调用 bcoz 对象是子类请请参考以下示例。

public class Test
    {
        public static void main(String[] args) 
        {
            //create the object of child class
            Child child = new Child();
        }
    }

    class Parent
    {   
        void print()
        {
            System.out.println("parent>> i ValueOne=");
        }

        Parent()
        {
            System.out.println("parent>> i ValueTwo=");
            print();
        }
    }    

    class Child extends Parent
    {
        int i = 45;


        void print()
        {
            System.out.println("Child>>i Value = "+i);
        }
    }

输出

parent>> i ValueTwo=
Child>>i Value = 0

2.如果此时创建了父类对象,则调用父类中的print()方法。请参考以下示例。

public class Test
    {
        public static void main(String[] args) 
        {
            //create the object of Parent class
            Parent parent = new Parent();
        }
    }

    class Parent
    {   
        void print()
        {
            System.out.println("parent>> i ValueOne=");
        }

        Parent()
        {
            System.out.println("parent>> i ValueTwo=");
            print();
        }
    }    

    class Child extends Parent
    {
        int i = 45;


        void print()
        {
            System.out.println("Child>>i Value = "+i);
        }
    }

输出

parent>> i ValueTwo=
parent>> i ValueOne=

3.我想你已经清楚了为什么 i 的值是 0 或 45。

于 2013-04-24T06:01:13.007 回答
2

首先,我没有在您的Child类中看到构造函数定义。

当你没有为一个Child类定义构造函数时,它的默认构造函数是:

public Child() {
    super();
}

在哪里super();调用Parent类构造函数(超类构造函数)。

但是,您print()在类中定义了您的方法Child,并且由于它与类中的方法具有相同的签名(名称+参数)Parent,因此它会使用相同的签名覆盖其超类方法。

这就是为什么你的Child类调用Parent类构造函数,而它调用自己的print()方法。

-添加:

第一个 i 值是 0,因为您没有iParent类中初始化 int 变量,而未初始化的 int 变量的值默认为 0。调用之后Parent,调用 nowChildprint()方法,并iChild类中初始化,所以 nowi就是你初始化的值

于 2013-04-24T05:22:30.327 回答
2

因为在第一次调用 print 方法i的时候没有初始化为 45,所以它的打印为 0。
调用是这样的

  • 子构造函数(因为构造函数从子构造链接到父构造)
  • 父构造函数
  • print 方法(现在这里i没有初始化,因为子构造函数还没有完成,所以它的打印默认值为i0 )
  • 现在在父构造函数完成后,子构造函数i得到它的值,即 45 -
  • 所以现在它在下一次调用 print 方法时打印 45
于 2013-04-24T05:17:41.423 回答
1

您的孩子首先调用您父母的构造函数。此时, i 未使用 45 值进行初始化。这就是它打印 0 (默认 int 值)的原因。

于 2013-04-24T05:16:00.533 回答