这是一道面试题。
子类是否继承私有字段?
我回答“否”,因为我们无法使用“普通 OOP 方式”访问它们。但是面试官认为它们是继承的,因为我们可以间接访问这些字段或使用反射,它们仍然存在于对象中。
回来后,我在javadoc中找到了以下引用:
超类中的私有成员 子类不继承其父类的私有成员。
你知道面试官的观点有什么论据吗?
这里的问题/答案中的大部分混淆都围绕着继承的定义。
显然,正如@DigitalRoss 解释的那样,子类的 OBJECT 必须包含其超类的私有字段。正如他所说,无法访问私人成员并不意味着它不存在。
然而。这与类的继承概念不同。与 Java 世界中的情况一样,存在语义问题的仲裁者是 Java Language Specification(当前为第 3 版)。
正如 JLS 所述 (https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2):
声明为私有的类的成员不会被该类的子类继承。只有声明为protected 或public 的类的成员才能被声明在一个包中的子类继承,而不是声明该类的那个。
这解决了面试官提出的确切问题:“子类继承私有字段”。 (重点由我添加)
答案是否定的。他们没有。子类的对象包含其超类的私有字段。子类本身没有其超类的私有字段的概念。
它是迂腐性质的语义吗?是的。这是一个有用的面试问题吗?可能不是。但是 JLS 为 Java 世界建立了定义,并且它(在这种情况下)明确地这样做了。
已编辑(删除了 Bjarne Stroustrup 的平行引用,由于 java 和 c++ 之间的差异可能只会增加混乱。我会让我的答案停留在 JLS 上:)
是的
重要的是要意识到虽然有两个类,但只有一个对象。
所以,是的,它当然继承了私有字段。它们大概是正确的对象功能所必需的,虽然父类的对象不是派生类的对象,但派生类的实例大多肯定是父类的实例。如果没有所有领域,情况就不会很好。
不,您不能直接访问它们。是的,它们是遗传的。他们必须是。
这是个好问题!
更新:
错了,“不”
好吧,我想我们都学到了一些东西。由于 JLS 起源于确切的“非继承”措辞,因此回答 “否” 是正确的。由于子类不能访问或修改私有字段,因此,换句话说,它们不能被继承。但确实 is 只是 一个 对象,它确实 确实包含 私有字段,因此如果有人以错误的方式使用 JLS 和教程措辞,很难理解 OOP、Java 对象以及实际发生的事情。
更新更新:
这里的争议涉及一个基本的模糊性:到底在讨论什么?物体?还是我们在某种意义上谈论班级本身?在描述类而不是对象时,允许有很大的自由度。所以子类不继承私有字段,但是作为子类实例的对象肯定包含私有字段。
car
,他把它放在孩子没有钥匙的private
储物柜里。你确实继承了 car
但它对你没用。因此,实际上,您并没有从继承中受益。
不,私有字段不会被继承......这就是发明 Protected 的原因。这是设计使然。我想这证明了受保护修饰符的存在。
现在进入上下文。您所说的继承是什么意思——如果它存在于从派生类创建的对象中?是的。
如果您的意思是派生类是否有用。嗯,不。
现在,当您进行函数式编程时,超类的私有字段不会以对子类有意义的方式继承。对于子类,超类的私有字段与任何其他类的私有字段相同。
从功能上讲,它不是继承的。但理想情况下,确实如此。
好的,刚刚查看了他们引用的 Java 教程:
超类中的私有成员 子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。
参考:http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html
我同意,该领域就在那里。但是,子类在该私有字段上没有任何特权。对于子类,私有字段与任何其他类的任何私有字段相同。
我相信这纯粹是观点问题。你可以塑造任何一方的论点。最好双向证明。
I believe it's purely matter of point-of-view.
和 justified the existence of protected modifier.
+1
这取决于您对“继承”的定义。子类是否还有内存中的字段?确实。它可以直接访问它们吗?不,这只是定义的微妙之处;关键是要了解真正发生的事情。
我将用代码演示这个概念。子类实际上继承了超类的私有变量。唯一的问题是子对象无法访问它们,除非您为超类中的私有变量提供公共 getter 和 setter。
考虑包 Dump 中的两个类。子扩展父。
如果我没记错的话,内存中的子对象由两个区域组成。一个只是父部分,另一个是子部分。子只能通过父级中的公共方法访问其父级代码中的私有部分。
这样想吧。波拉特的父亲博尔托克有一个装有 10 万美元的保险箱。他不想共享他的“私有”变量安全。所以,他没有提供保险箱的钥匙。波拉特继承了保险箱。但是,他连打开都打不开又有什么用呢?如果只有他的父亲提供了钥匙。
家长 -
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
孩子 -
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
不,他们不会继承它。
其他一些类可能间接使用它的事实并没有说明继承,而是说明了封装。
例如:
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?
}
}
您还可以通过反射在 UseIt
中获取 count
的值。这并不意味着,你继承它。
更新
即使值在那里,它也不会被子类继承。
例如一个子类定义为:
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 指出的那样,价值是存在的,但不是通过继承来实现的。
这么说吧。如果你父亲很有钱,给你一张信用卡,你仍然可以用他的钱买东西,但这并不意味着你继承了所有的钱,不是吗?
其他更新
不过,这很有趣,to know why the attribute is there.
坦率地说,我没有确切的术语来描述它,但它是 JVM 和它的工作方式,它也加载了“未继承”的父定义。
我们实际上可以更改父类,子类仍然可以工作。
//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
我想确切的术语可以在这里找到:The JavaTM Virtual Machine Specification
encapsulation
与 inherit
的好点,我想这个答案值得更多投票。
好吧,我对面试官问题的回答是 - 私有成员不会在子类中继承,但子类或子类的对象只能通过公共 getter 或 setter 方法或原始类的任何此类适当方法访问它们。通常的做法是让成员保持私有并使用公共的 getter 和 setter 方法访问它们。那么,当他们处理的私有成员对对象不可用时,只继承 getter 和 setter 方法有什么意义呢?这里的“继承”只是意味着它可以直接在子类中使用,以供子类中新引入的方法使用。
将以下文件另存为 ParentClass.java 并自己尝试 ->
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
如果我们尝试在 SubClass 的方法中使用 ParentClass 的私有变量 x,那么任何修改都不能直接访问它(意味着不继承)。但是 x 可以通过原始类的 setX() 方法在子类中修改,就像在 setXofParent() 方法中所做的那样,或者可以使用 ChildClass 对象使用 setX() 方法或最终调用 setX() 的 setXofParent() 方法进行修改。所以这里的 setX() 和 getX() 是一种通往 ParentClass 的私有成员 x 的门。
另一个简单的例子是 Clock 超类将小时和分钟作为私有成员,并将适当的 getter 和 setter 方法作为公共成员。然后是作为时钟子类的 DigitalClock。在这里,如果 DigitalClock 的对象不包含小时和分钟成员,那么事情就搞砸了。
好的,这是一个非常有趣的问题,我研究了很多并得出结论,超类的私有成员在子类的对象中确实可用(但不可访问)。为了证明这一点,这是一个包含父类和子类的示例代码,我正在将子类对象写入 txt 文件并读取文件中名为“bhavesh”的私有成员,因此证明它确实在子类中可用类,但由于访问修饰符而无法访问。
import java.io.Serializable;
public class ParentClass implements Serializable {
public ParentClass() {
}
public int a=32131,b,c;
private int bhavesh=5555,rr,weq,refw;
}
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 的后面板以取出电池来重置手机......但电池仍然存在)。
PS 我遇到的许多继承定义之一:“继承——一种编程技术,它允许派生类扩展基类的功能,继承它的所有状态(重点是我的)和行为。”
私有字段,即使子类无法访问,也是超类的继承状态。
例如,
class Person {
private String name;
public String getName () {
return this.name;
}
Person(String name) {
this.name = name;
}
}
public class Student extends Person {
Student(String name) {
super(name);
}
public String getStudentName() {
return this.getName(); // works
// "return this.name;" doesn't work, and the error is "The field Person.name is not visible"
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student("Bill");
String name = s.getName(); // works
// "String name = s.name;" doesn't work, and the error is "The field Person.name is not visible"
System.out.println(name);
}
}
https://i.stack.imgur.com/NuSQn.jpg
https://i.stack.imgur.com/jY9Y5.jpg
不考虑填充位/对齐和在 VTABLE 中包含对象类。所以子类的对象确实为超类的私有成员占有一席之地。但是,不能从子类的对象访问它...
我不得不回答 Java 中的私有字段是继承的。请允许我演示一下:
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”,所以人们认为它不是继承的。但是,类中的每个非静态事物,无论是字段还是方法,都是继承的。
不,私有字段不会被继承。唯一的原因是子类不能直接访问它们。
我相信,答案完全取决于已提出的问题。我的意思是,如果问题是
我们可以直接从子类访问超类的私有字段吗?
那么答案是否,如果我们通过access specifier details,提到,私有成员只能在类本身内访问。
但是,如果问题是
我们可以从子类访问超类的私有字段吗?
这意味着,您将如何访问私有成员并不重要。在这种情况下,我们可以在超类中创建公共方法,您可以访问私有成员。因此,在这种情况下,您正在创建一个接口/桥来访问私有成员。
其他 OOP 语言如 C++,具有 friend function
概念,通过它我们可以访问其他类的私有成员。
我们可以简单地说,当一个超类被继承时,那么超类的私有成员实际上变成了子类的私有成员,不能进一步被继承或不能被子类的对象访问。
私有类成员或构造函数只能在包含成员或构造函数声明的顶级类 (§7.6) 的主体内访问。它不被子类继承。 https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6
子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法
我可以试着帮助你。当子类(例如名为 B)扩展超类(例如名为 A)时,它会自动从其超类继承字段(例如属性和/或方法)。现在,B 在其内存布局中为 A 类中的每个字段(甚至是私有字段)提供了空间。事实上,Java 不允许子类 B 使用私有字段,因为它们是私有的。
子类不继承其父类的私有成员。但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法。
私有成员(状态和行为)是继承的。它们(可以)影响由类实例化的对象的行为和大小。更不用说通过所有可用的或可以由其实现者假设的封装破坏机制,它们对子类非常可见。
尽管继承有一个“事实上的”定义,但它肯定与“可见性”方面没有联系,这些方面由“否”答案假设。
因此,没有必要外交。 JLS 在这一点上是错误的。
任何假设它们不是“继承”的都是不安全和危险的。
因此,在两个事实上(部分)冲突的定义(我不会重复)中,唯一应该遵循的是更安全(或安全)的定义。
不定期副业成功案例分享