关于java:子类是否继承私有字段?

Do subclasses inherit private fields?

这是一个面试问题。

Does subclasses inherit private
fields?

我回答"不",因为我们不能用"正常OOP方式"访问它们。但面试官认为他们是被继承的,因为我们可以间接地或通过反射来访问这些领域,他们仍然存在于对象中。

回来后,我在javadoc中找到了以下引用:

Private Members in a Superclass

A
subclass does not inherit the private
members of its parent class.

你知道面试官有什么意见吗?


这里的问题/答案中的大部分混淆围绕着继承的定义。

显然,正如@digitalross所解释的,子类的对象必须包含其子类的私有字段。正如他所说,没有私人成员的访问权并不意味着它不在那里。

然而。这与类的继承概念不同。正如Java世界中存在语义问题一样,仲裁器是Java语言规范(目前是第三版)。

正如JLS所说(https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html jls-8.2):

Members of a class that are declared
private are not inherited by
subclasses of that class. Only members
of a class that are declared protected
or public are inherited by subclasses
declared in a package other than the
one in which the class is declared.

这解决了采访者提出的确切问题:"子类继承私有字段吗?"(我强调)

答案是不,他们没有。子类的对象包含其超类的私有字段。子类本身没有关于其超类的私有字段的概念。

它是一种学究式的语义吗?对。这是一个有用的面试问题吗?大概不会。但是JLS为Java世界建立了定义,而且它确实是这样的(在这种情况下)。

由于Java和C++之间的差异,删除了Bjarne Stroustrup的并行引用可能只会增加混乱。我将在jls上给出答案:)


是的

重要的是要认识到虽然有两个类,但只有一个对象。

所以,是的,它当然继承了私有领域。它们大概是适当的对象功能所必需的,虽然父类的对象不是派生类的对象,但派生类的实例绝大多数肯定是父类的实例。如果没有所有的田地就不可能是那样。

不,您不能直接访问它们。是的,它们是遗传的。他们必须是。

这是个好问题!

更新:

"不"

嗯,我想我们都学到了一些东西。由于JLS的措辞是"不继承"的,所以回答"不"是正确的。由于子类不能访问或修改私有字段,因此,换句话说,它们不会被继承。但实际上只有一个对象,它确实包含私有字段,因此如果有人错误地使用JLS和教程用语,很难理解OOP、Java对象和真正发生的事情。

更新到更新:

这里的争论涉及到一个根本性的歧义:到底在讨论什么?对象?或者我们是在某种意义上谈论班级本身?在描述类时,相对于对象,允许有很大的纬度。因此,子类不继承私有字段,但作为子类实例的对象确实包含私有字段。


不,私有字段不是继承的…这就是为什么保护被发明的原因。这是按设计的。我想这证明了受保护修饰语的存在是合理的。

现在来讨论一下上下文。您所说的继承是什么意思——如果它存在于从派生类创建的对象中?是的,是的。

如果您的意思是它对派生类有用吗?嗯,不。

现在,当您谈到函数式编程时,超级类的私有字段不会以有意义的方式继承给子类。对于子类,超级类的私有字段与任何其他类的私有字段相同。

从功能上讲,它不是继承的。但理想情况下是这样的。

好了,看看Java教程,他们引用了如下:

Private Members in a Superclass

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

请参阅:http://download.oracle.com/javase/tutorial/java/iandi/subclasses.html

我同意,领域就在那里。但是,子类在该私有字段上没有任何特权。对于子类,私有字段与任何其他类的私有字段相同。

我认为这纯粹是观点问题。你可以把论点的任何一面塑造出来。两种方法最好都合理。

nbsp;


这取决于你对"继承"的定义。子类在内存中还有字段吗?一定地。它能直接访问它们吗?不,这只是定义的微妙之处,重点是要理解到底发生了什么。


我将用代码演示这个概念。子类实际上继承了超级类的私有变量。唯一的问题是他们无法访问子对象,除非为私有变量提供公共getter和setter在超级班。

考虑在包转储中使用两个类。子级扩展父级。

如果我记得正确,内存中的子对象由两个区域组成。一个是仅父部分,另一个是仅子部分。孩子可以访问私人其父级的代码中的节,只能通过父级中的公共方法。

这样想。波拉特的父亲波托克有一个保险箱,里面有10万美元。他不想分享他的"私人"变量保险箱。所以,他没有提供保险箱的钥匙。宝来继承了保险箱。但是,如果他甚至不能打开它,有什么好处呢?要是他的话就好了爸爸提供了钥匙。

亲本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package Dump;

public class Parent {

    private String reallyHidden;
    private String notReallyHidden;

    public String getNotReallyHidden() {
        return notReallyHidden;
    }

    public void setNotReallyHidden(String notReallyHidden) {
        this.notReallyHidden = notReallyHidden;
    }

}//Parent

儿童-

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package Dump;

public class Child extends Parent {

    private String childOnly;

    public String getChildOnly() {
        return childOnly;
    }

    public void setChildOnly(String childOnly) {
        this.childOnly = childOnly;
    }

    public static void main(String [] args){

        System.out.println("Testing...");
        Child c1 = new Child();
        c1.setChildOnly("childOnly");
        c1.setNotReallyHidden("notReallyHidden");

        //Attempting to access parent's reallyHidden
            c1.reallyHidden;//Does not even compile

    }//main

}//Child

不,他们不继承它。

事实上,其他一些类可能会间接地使用它,这与继承无关,而与封装无关。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Some {
   private int count;
   public void increment() {
      count++;
   }
   public String toString() {
       return Integer.toString( count );
   }
}

class UseIt {
    void useIt() {
        Some s = new Some();
        s.increment();
        s.increment();
        s.increment();
        int v = Integer.parseInt( s.toString() );
        // hey, can you say you inherit it?
     }
}

您还可以通过反射得到UseItcount的值。这并不意味着,你继承了它。

更新

即使值存在,它也不会被子类继承。

例如,一个子类定义为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class SomeOther extends Some {
    private int count = 1000;
    @Override
    public void increment() {
        super.increment();
        count *= 10000;
    }
}

class UseIt {
    public static void main( String ... args ) {
        s = new SomeOther();
        s.increment();
        s.increment();
        s.increment();
        v = Integer.parseInt( s.toString() );
        // what is the value of v?          
     }
}

这与第一个例子完全相同。属性count是隐藏的,根本不由子类继承。然而,正如DigitalRoss指出的,价值是存在的,但不是通过继承来实现的。

这样说吧。如果你父亲很富有,给了你一张信用卡,你仍然可以用他的钱买东西,但这并不意味着你继承了所有的钱,是吗?

其他更新

不过,知道属性为什么存在是非常有趣的。

坦率地说,我没有确切的术语来描述它,但是它是JVM,它的工作方式也加载了"未继承"的父定义。

实际上,我们可以更改父类,子类仍然可以工作。

例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
//A.java
class A {
   private int i;
   public String toString() { return""+ i; }
}
// B.java
class B extends A {}
// Main.java
class Main {
   public static void main( String [] args ) {
      System.out.println( new B().toString() );
    }
}
// Compile all the files
javac A.java B.java Main.java
// Run Main
java Main
// Outout is 0 as expected as B is using the A 'toString' definition
0

// Change A.java
class A {
   public String toString() {
      return"Nothing here";
   }
}
// Recompile ONLY A.java
javac A.java
java Main
// B wasn't modified and yet it shows a different behaviour, this is not due to
// inheritance but the way Java loads the class
Output: Nothing here

我想确切的术语可以在这里找到:JavaTM虚拟机规范


好吧,我对采访者的问题的回答是-私有成员不是在子类中继承的,但是它们只能通过公共getter或setter方法或原始类的任何此类适当方法被子类或子类的对象访问。通常的做法是保持成员私有,并使用公共的getter和setter方法访问它们。那么,当处理的私有成员对对象不可用时,只继承getter和setter方法有什么意义呢?这里的"继承"仅仅意味着它可以直接在子类中通过子类中新引入的方法来玩耍。

将以下文件另存为parentclass.java,然后自己尝试->

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class ParentClass {
  private int x;

  public int getX() {
    return x;
  }

  public void setX(int x) {
    this.x = x;
  }
}

class SubClass extends ParentClass {
  private int y;

  public int getY() {
    return y;
  }

  public void setY(int y) {
    this.y = y;
  }

  public void setXofParent(int x) {
    setX(x);
  }
}

class Main {
  public static void main(String[] args) {
    SubClass s = new SubClass();
    s.setX(10);
    s.setY(12);
    System.out.println("X is :"+s.getX());
    System.out.println("Y is :"+s.getY());
    s.setXofParent(13);
    System.out.println("Now X is :"+s.getX());
  }
}

Output:
X is :10
Y is :12
Now X is :13

如果我们试图在子类的方法中使用parentclass的私有变量x,那么对于任何修改都不能直接访问它(意味着不能继承)。但是x可以通过原始类的setx()方法在子类中进行修改,就像在setxofparent()方法中那样,或者可以使用使用setx()方法或setxofparent()方法(最终调用setx())使用childClass对象修改。所以这里setx()和getx()是parentclass私有成员x的一种门。

另一个简单的例子是clock superclass将hours和mins作为私有成员,将适当的getter和setter方法作为公共方法。然后,DigitalClock作为时钟的一个子类出现。这里,如果数字钟的对象不包含小时和分钟的成员,那么事情就搞砸了。


好吧,这是一个非常有趣的问题,我研究了很多,得出了一个结论,即超类的私有成员确实在子类的对象中可用(但不可访问)。为了证明这一点,这里有一个带有父类和子类的示例代码,我正在将子类对象写入一个txt文件,并在文件中读取一个名为"bhavesh"的私有成员,因此证明它确实在子类中可用,但由于访问修饰符而无法访问。

1
2
3
4
5
6
7
8
9
10
import java.io.Serializable;
public class ParentClass implements Serializable {
public ParentClass() {

}

public int a=32131,b,c;

private int bhavesh=5555,rr,weq,refw;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import java.io.*;
import java.io.Serializable;
public class ChildClass extends ParentClass{
public ChildClass() {
super();
}

public static void main(String[] args) {
ChildClass childObj = new ChildClass();
ObjectOutputStream oos;
try {
        oos = new ObjectOutputStream(new FileOutputStream("C:\\MyData1.txt"));
        oos.writeObject(childObj); //Writing child class object and not parent class object
        System.out.println("Writing complete !");
    } catch (IOException e) {
    }


}
}

打开mydata1.txt并搜索名为"bhavesh"的私有成员。请告诉我你们的想法。


子类似乎继承了私有字段,因为这些字段被用于子类的内部工作(从哲学上讲)。子类在其构造函数中调用超类构造函数。如果超类构造函数已在其构造函数中初始化了这些字段,则调用超类构造函数的子类显然继承了超类私有字段。这只是一个例子。当然,如果没有访问器方法,子类就不能访问超类私有字段(就像不能弹出iPhone的后面板,取出电池来重置手机一样……但是电池还在那里)。

聚苯乙烯继承的众多定义中的一个:继承——一种编程技术,允许派生类扩展基类的功能,继承其所有状态(重点是我的)和行为。

私有字段(即使子类不能访问)是超类的继承状态。


不,不继承私有字段。唯一的原因是子类不能直接访问它们。


Memory Layout in Java vis-a-vis inheritance

enter image description here

不考虑填充位/对齐以及在vtable中包含对象类。所以子类的对象确实为超级类的私有成员提供了一个位置。但是,它不能从子类的对象中访问…


我们可以简单地说,当一个超类被继承时,超类的私有成员实际上成为子类的私有成员,不能被进一步继承,也不能被子类的对象所继承。


我必须回答,Java中的私有字段是继承的。请允许我演示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public class Foo {

    private int x; // This is the private field.

    public Foo() {
        x = 0; // Sets int x to 0.
    }

    //The following methods are declared"final" so that they can't be overridden.
    public final void update() { x++; } // Increments x by 1.
    public final int getX() { return x; } // Returns the x value.

}


public class Bar extends Foo {

    public Bar() {

        super(); // Because this extends a class with a constructor, it is required to run before anything else.

        update(); //Runs the inherited update() method twice
        update();
        System.out.println(getX()); // Prints the inherited"x" int.

    }

}

如果在程序Bar bar = new Bar();中运行,那么在输出框中始终会看到数字"2"。因为整数"x"是用update()getX()方法封装的,所以可以证明整数是继承的。

令人困惑的是,因为您不能直接访问整数"x",所以人们认为它不是继承的。然而,类中的每一个非静态的东西,无论是字段还是方法,都是继承的。


私有类成员或构造函数只能在包含成员或构造函数声明的顶级类(§7.6)的主体中访问。它不是由子类继承的。https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html jls-6.6


我相信,答案完全取决于所问的问题。我是说,如果问题是

Can we directly access the private field of the super-class from
their sub-class ?

那么答案是"否",如果我们浏览访问说明符的详细信息,就会提到,私有成员只能在类本身内访问。

但是,如果问题是

Can we access the private field of the super-class from
their sub-class ?

这意味着,访问私有成员的方式并不重要。在这种情况下,我们可以在超级类中使用public方法,并且您可以访问私有成员。因此,在本例中,您将创建一个接口/网桥来访问私有成员。

其他的OOP语言,如C++,有EDOCX1的0个概念,通过这个概念,我们可以访问其他类的私有成员。


子类不继承其父类的私有成员。但是,如果超类具有用于访问其私有字段的公共或受保护方法,那么子类也可以使用这些方法。


私有成员(状态和行为)是继承的。它们(可以)影响由类实例化的对象的行为和大小。更不用说,子类通过所有可用的或者可以由其实现者假定的封装破坏机制都能很好地看到它们。

虽然继承有一个"诽谤"的定义,但它肯定与"可见性"方面没有联系,而"不"的答案会假定"可见性"方面。

所以,没有必要采取外交手段。JLS在这一点上是错误的。

任何认为它们不是"继承"的假设都是不安全和危险的。

因此,在两个(部分)相互冲突的定义中(我不会重复),唯一应该遵循的是更安全(或安全)的定义。