理解继承有点麻烦? (JAVA)

时间:2018-06-03 18:36:39

标签: java inheritance

我一直在尝试使用java教自己继承,但我真的很困惑,看起来像在线youtube视频/看以前的问题根本没有帮助。我尝试了这个网站上的练习题:http://javaconceptoftheday.com/java-inheritance-practice-coding-questions/,但我遇到问题2,3和7的问题。

在问题2中,由于对象a的构造函数是B(),为什么不打印B类的i值而不是类a?相反,它打印出一个类,我不知道为什么。

在问题3中,是程序打印1 2 3的原因是因为没有构造函数而且它只是函数?我知道当你从一个类继承时,你基本上就好像它的所有函数都在子类中一样,所以你基本上只是假装C类说:

的System.out.println(1);

的System.out.println(2);

的System.out.println(3);

在问题7中,由于构造函数是一个C()构造函数,为什么它仍然遍历A类和B类的构造函数中的代码?

感谢您提供任何帮助,继承只是我在编程课程介绍中没有涉及的主题之一,所以我试图在秋季学期开始之前填写所有空白。

问题2的代码:

class A
{
    int i = 10;
}

class B extends A
{
    int i = 20;
}

public class MainClass
{
    public static void main(String[] args)
    {
        A a = new B();

        System.out.println(a.i);
    }
}

问题3的代码:

class A
{
    {
        System.out.println(1);
    }
}

class B extends A
{
    {
        System.out.println(2);
    }
}

class C extends B
{
    {
        System.out.println(3);
    }
}

public class MainClass
{
    public static void main(String[] args)
    {
        C c = new C();
    }
}

问题7的代码:

class A
{
    public A()
    {
        System.out.println("Class A Constructor");
    }
}

class B extends A
{
    public B()
    {
        System.out.println("Class B Constructor");
    }
}

class C extends B
{
    public C()
    {
        System.out.println("Class C Constructor");
    }
}

public class MainClass
{
    public static void main(String[] args)
    {
        C c = new C();
    }
}

2 个答案:

答案 0 :(得分:1)

Q2) Java语言的多态行为适用于方法而不是成员变量:它们设计语言在编译时绑定成员变量,在运行时绑定方法。

Q3)它被称为 instance initialization block 。子类的每个实例都隐式包含其超类的实例。因此,呼叫顺序从class AB开始,然后C开始。

Q7) Q3同样适用于问题的原因

答案 1 :(得分:0)

首先,我认为你应该看看Oracle的Java教程,主要是Classes上的那个和Inheritance上的那个。

让我们从问题2开始:

class A {
    int i = 10;
}

class B extends A {
    int i = 20;
}

public class MainClass {
    public static void main(String[] args) {
        A a = new B();

        System.out.println(a.i);
    }
}

由于AB的成员名称相同,B会隐藏A中的成员。从本质上讲,B的实例有两个成员i:一个来自A,另一个来自B。在方法main中,您编写A a = new B();,即a的静态类型为Aa的运行时类型为B。当您现在访问成员时,静态类型会决定选择哪个成员(AB)。因此,选择了i中的A。这是为什么?如果我们稍微修改一下这个例子,我们就会明白为什么:

class A {
    int i = 100;
}

class B extends A {
    String i = "Hello";
}

class Ideone {
    public static void main (String[] args) throws java.lang.Exception {
        A a = new B();
        int i = a.i;
        System.out.println(i);

        String s = ((B) a).i;
        System.out.println(s);
    }
}

Run it on ideone.com

在此示例中,B再次隐藏了i中的成员A。但这一次,这些领域有不同的类型。然而,无论何时访问i中的成员A,您都需要int,而不是String。这就是静态类型决定选择哪个成员的原因。

问题3:

class A {
    {
        System.out.println(1);
    }
}

class B extends A {
    {
        System.out.println(2);
    }
}

class C extends B {
    {
        System.out.println(3);
    }
}

public class MainClass {
    public static void main(String[] args) {
        C c = new C();
    }
}

为此,我们需要了解三件事:

  • 如果没有为类提供构造函数,则它具有隐式默认构造函数。
  • 如果构造函数中的第一个语句既不是this(...)也不是super(...),那么它是隐式的super();
  • 类的初始值设定项在超类构造函数之后执行,但在自己的构造函数之前执行。

我们可以从这三个陈述中得出什么结论?如果我们初始化任何对象,我们必须首先执行超类构造函数。这会导致您尝试初始化为Object的类型的构造函数级联。因此,我们按顺序看到输出:

1
2
3

问题7:

class A {
    public A() {
        System.out.println("Class A Constructor");
    }
}

class B extends A {
    public B() {
        System.out.println("Class B Constructor");
    }
}

class C extends B {
    public C() {
        System.out.println("Class C Constructor");
    }
}

public class MainClass {
    public static void main(String[] args) {
        C c = new C();
    }
}

这个问题的答案已经通过我对最后一个问题的回答得到了回答:如果构造函数的第一个语句既不是this(...)也不是super(...),那么它隐含super()。因此,从C的构造函数中我们调用B的构造函数,并从B的构造函数中调用A的构造函数。所以我们再次按顺序获取输出:

Class A Constructor
Class B Constructor
Class C Constructor