使用 Java 中的两个 类 关于继承的基本查询

A Fundamental Query about Inheritance using two classes in Java

请考虑Java中的以下代码:

class a
{
    int i = 10;
    int j = 20;
}

class b extends a
{
    int i = 100;
    int j = 200;
}

public class Test
{
    public static void main(String args[])
    {
        a a1 = new a();
        b b1 = new b();
        a1 = b1;
        System.out.println("a1.i is " + a1.i);
        System.out.println("a1.j is " + a1.j);
        System.out.println("b1.i is " + b1.i);
        System.out.println("b1.j is " + b1.j);

    }
}

我得到的输出是

a1.i is 10
a1.j is 20
b1.i is 100
b1.j is 200

我的问题是:为什么语句a1=b1没有把a1.i变成100,a1.j变成200?语句 a1 = b1 没有任何改变吗?

您正在将 class B 的实例向上转换为 class A.

的实例

执行后

a1 = b1

那么从技术上讲,您无法通过变量 a1 访问 b1 的字段。那是因为 a1,无论它是否来自 b1 的赋值 "comes",实际上都是 之后的 class A 的一个实例向上转换它。

考虑一下:您在 class A 和 class [=13] 中定义了字段 ij 的一个实例这一事实=] 并不意味着它们完全相关。

我认为您打算执行以下操作(概念上):

class A {
    int i;
    int j;
    public A() {
        i = 10;
        j = 20;
    }
}

class B extends A {
    public B() {
        i = 100;
        j = 200;
    }
}

那就试试这个

A a1 = new A();
B b1 = new B();
a1 = b1;
System.out.println("a1.i is " + a1.i); // 100
System.out.println("a1.j is " + a1.j); // 200
System.out.println("b1.i is " + b1.i); // 100
System.out.println("b1.j is " + b1.j); // 200

如果您这样做,那么 class B 正在设置从 class A 继承的字段。届时,您将获得预期的行为。这是因为即使你将 B 的实例向下转换为 A 的实例,你总是在改变从 A 继承的字段,而不是 B你现在的例子。

a 的实例具有字段 i (10) 和 j (20)。

b 的实例具有 a 具有的那些字段,以及另外两个字段,也容易混淆地称为 ij,其值为 100 和 200。

所以 b1{ a::i=10, a::j=20, b::i=100, b::j=200 }.

如果您访问 b1.i,您会从对象 b1 中获得 b::i 字段(如您所料)。

您的 a1 变量是 a 类型(即使它包含 b 的实例),因此您只能使用它访问 a 的字段。因此,如果您访问 a1.i,您会从对象(即 10)中获取 a::i 字段,而不是 b::i 字段(即 100)。

准备好,因为你问的问题需要一个复杂的答案。

Java 在 Jave Virtual Machine.In 中是 运行 你问题的上下文,关于 java 和 JVM,你需要记住两件事。

  1. Java 方法是 运行 时间绑定
    • Java 类型转换(和装箱、拆箱)是 运行时间绑定
  2. Java class 参数是编译时绑定
    • Java 转换会给你错误 当且仅当 .铸造在逻辑上是不正确的。

现在让我们分析您的代码。

    a a1 = new a();
    b b1 = new b();
    //This type cast happens a Runtime and not compile time although the check is done at compile time and your code passes the check!
    a1 = b1;
    //These variables are binded at compile.And hence possess the value
 that they possesed during compie time.This means that they have 
the original values which they were defined with
    System.out.println("a1.i is " + a1.i);
    System.out.println("a1.j is " + a1.j);
    System.out.println("b1.i is " + b1.i);
    System.out.println("b1.j is " + b1.j);

现在说明这个的影响和修改,将这个添加到你的代码中并测试它。

class Test{
     public static void main(String args[])
        {
            a a1 = new a();
            b b1 = new b();
            a1 = b1;
            System.out.println("a1.i is " + a1.i);
            System.out.println("a1.j is " + a1.j);
            System.out.println("b1.i is " + b1.i);
            System.out.println("b1.j is " + b1.j);

            a1.print();
            //shall print b
            b1.print();
            //shall print b
        }

}   
}

class a
{
    int i = 10;
    int j = 20;

    public void print(){
        System.out.println("a");
    }
}

class b extends a
{
    int i = 100;
    int j = 200;
    public void print(){
        System.out.println("b");
    }
}

编辑:努力寻找一个写得很好的 SO 答案来解决差异,但没有遇到 any.So this tutorial 很好地解释了这个概念。