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() 封装,所以可以证明整数是继承的 .
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
Child -
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
70
不,他们没有继承它 .
其他一些类可能间接使用它的事实没有说继承,而是关于封装 .
例如:
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 的值 . 这并不意味着,你继承它 .
UPDATE
即使值存在,它也不会被子类继承 .
例如,子类定义为:
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 被隐藏, not 完全由子类继承 . 尽管如此,正如DigitalRoss所指出的那样, Value 在那里,但不是通过继承手段 .
//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
那么,我对面试官问题的回答是 - Private members are not inherited in sub-classes but they are accessible to subclass or subclass's object only via public getter or setter methods or any such appropriate methods of original class. 通常的做法是保持成员私密并使用公开的getter和setter方法访问它们 . 那么,当他们处理的私有成员对对象不可用时,只继承getter和setter方法的重点是什么?这里'inherited'只是意味着它可以直接在子类中通过子类中新引入的方法来玩 .
将以下文件保存为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
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) {
}
}
}
17 回答
私有类成员或构造函数只能在顶级类(§7.6)的主体内访问,该类包含成员或构造函数的声明 . 它不是由子类继承的 . https://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6
子类不继承其父类的私有成员 . 但是,如果超类具有访问其私有字段的公共或受保护方法,则子类也可以使用这些方法 .
私有成员(州和行为)是继承的 . 它们(可以)影响由类实例化的对象的行为和大小 . 更不用说它们通过所有可用的封装破坏机制对子类非常清晰可见,或者可以由它们的实现者承担 .
虽然继承具有“事实”定义,但它绝对没有“可见性”方面的链接,这些方面由“否”答案假设 .
所以,没有必要外交 . JLS在这一点上是错的 .
任何他们不是“继承”的假设都是不安全和危险的 .
因此,在两个事实上(部分)冲突的定义中(我将不再重复),唯一应该遵循的是更安全(或安全)的定义 .
问题/答案中的大部分混淆都围绕着继承的定义 .
显然,正如@DigitalRoss所解释的那样,一个子类的 OBJECT 必须包含它的超类's private fields. As he states, having no access to a private member doesn' t意味着它不在那里 .
然而 . 这与类的继承概念不同 . 正如java世界中存在语义问题的情况一样,仲裁器是Java Language Specification(目前是第3版) .
正如JLS所述(https://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2):
这解决了采访者提出的确切问题:“做sub CLASSES 继承私人领域” . (重点补充一下)
答案是否定的 . 他们没有 . 子类的OBJECTS包含其超类的私有字段 . 子类本身没有其超类的私有字段的NO OFTION .
这是一种迂腐的语义吗?是 . 这是一个有用的面试问题吗?可能不是 . 但是JLS Build 了Java世界的定义,并且它(在这种情况下)明确地这样做了 .
EDITED(删除了Bjarne Stroustrup的并行引用,因为java和c之间的差异可能只会增加混乱 . 我会让我的答案依赖于JLS :)
是的
重要的是要意识到虽然有两个类,但只有一个对象 .
所以,是的,当然它继承了私有领域 . 它们可能是正确的对象功能必不可少的,虽然父类的对象不是派生类的对象,但派生类的实例绝大多数是父类的实例 . 如果没有所有的领域,那就不可能 .
不,你不能直接访问它们 . 是的,它们是遗传的 . 他们必须是 .
这是一个很好的问题!
Update:
错误,“不”
好吧,我想我们都学到了一些东西 . 由于JLS起源于确切的"not inherited"措辞,因此回答"no"是正确的 . 由于子类无法访问或修改私有字段,因此,换句话说,它们不会被继承 . 但实际上只有一个对象,它确实包含私有字段,因此如果有人以错误的方式使用JLS和教程措辞,那么理解OOP,Java对象以及真正发生的事情将非常困难 .
Update to update:
这里的争议涉及一个基本的模糊性:究竟在讨论什么?物体?或者我们在某种意义上谈论 class 本身?在描述类而不是对象时,允许很多纬度 . 所以子类不继承私有字段,而是一个对象,它是子类的实例 certainly does contain the private fields.
不会 . 私有字段不会被继承......这就是为什么发明了Protected的原因 . 这是设计的 . 我想这证明了保护修饰符的存在 .
现在来到这里 . 你继承的意思是什么 - 如果在派生类创建的对象中存在它?是的 .
如果你的意思是它对派生类有用 . 好吧,不 .
现在,当您进行函数式编程时,超类的私有字段不会以有意义的方式为子类继承 . 对于子类,超类的私有字段与任何其他类的私有字段相同 .
从功能上讲,它不是遗传的 . 但 ideally ,确实如此 .
好的,只是查看Java教程,他们引用了这个:
参考:http://download.oracle.com/javase/tutorial/java/IandI/subclasses.html
我同意,那个领域就在那里 . 但是,子类在该私有字段上没有任何特权 . 对于子类,私有字段与任何其他类的任何私有字段相同 .
我相信's purely matter of point-of-view. You may mould the argument either side. It'两种方式都更合理 .
这取决于你对“继承”的定义 . 子类是否仍有内存中的字段?当然 . 可以直接访问它们吗?不,这只是定义的微妙之处;关键是要了解真正发生的事情 .
我必须回答Java中的私有字段是继承的 . 请允许我证明:
如果您在程序
Bar bar = new Bar();
中运行,那么您将始终在输出框中看到数字"2" . 因为整数"x"用方法update()
和getX()
封装,所以可以证明整数是继承的 .令人困惑的是,因为你不能直接访问整数“x”,所以人们认为它不是继承的 . 但是,类中的每个非静态事物(无论是字段还是方法)都是继承的 .
我将用代码演示这个概念 . 子类ACTUALLY继承超类的私有变量 . 唯一的问题是除非为超类中的私有变量提供公共getter和setter,否则子对象无法访问它们 .
考虑转发包中的两个类 . 孩子延伸父母 .
如果我没记错的话,内存中的子对象由两个区域组成 . 一个是父部分,另一个是子部分 . 子级只能通过父级中的公共方法访问其父级代码中的私有区域 .
这样想吧 . 波拉特的父亲博尔托克有一个10万美元的保险箱 . 他不想分享他的“私人”变量安全 . 所以,他没有为保险箱提供钥匙 . 波拉特继承了保险箱 . 但是,如果他甚至不能打开它会有什么好处呢?如果只有他的父亲提供了钥匙 .
Parent -
Child -
不,他们没有继承它 .
其他一些类可能间接使用它的事实没有说继承,而是关于封装 .
例如:
您还可以通过反射在
UseIt
中获取count
的值 . 这并不意味着,你继承它 .UPDATE
即使值存在,它也不会被子类继承 .
例如,子类定义为:
这与第一个示例的情况完全相同 . 属性
count
被隐藏, not 完全由子类继承 . 尽管如此,正如DigitalRoss所指出的那样, Value 在那里,但不是通过继承手段 .这样说吧 . 如果你的父亲很有钱并且给你一张信用卡,你仍然可以用他的钱买东西,但这并不意味着你有这么多钱,是吗?
Other update
虽然很有意思,to know why the attribute is there.
坦率地说,我没有确切的术语来描述它,但它是JVM及其工作方式,也加载了“未继承”的父定义 .
我们实际上可以更改父级,子类仍然可以工作 .
For instance:
我猜这个确切的术语可以在这里找到:The JavaTM Virtual Machine Specification
那么,我对面试官问题的回答是 - Private members are not inherited in sub-classes but they are accessible to subclass or subclass's object only via public getter or setter methods or any such appropriate methods of original class. 通常的做法是保持成员私密并使用公开的getter和setter方法访问它们 . 那么,当他们处理的私有成员对对象不可用时,只继承getter和setter方法的重点是什么?这里'inherited'只是意味着它可以直接在子类中通过子类中新引入的方法来玩 .
将以下文件保存为ParentClass.java并自己尝试 - >
如果我们尝试在SubClass的方法中使用ParentClass的私有变量x,那么它不能直接访问任何修改(意味着没有继承) . 但是可以通过setXofParent()方法中的原始类的setX()方法在SubClass中修改x,或者可以使用setX()方法或最终调用setX()的setXofParent()方法使用ChildClass对象修改x . 所以这里setX()和getX()是ParentClass的私有成员x的一种门 .
另一个简单的例子是Clock超类将小时和分钟作为私有成员,并将适当的getter和setter方法作为public . 然后DigitalClock作为Clock的子类 . 如果DigitalClock的对象不包含小时和分钟成员,那么事情就搞砸了 .
好吧,这是一个非常有趣的问题,我研究了很多,并得出结论,超类的私有成员确实可用(但不可访问)子类的对象 . 为了证明这一点,这里有一个带有父类和子类的示例代码,我正在将子类对象写入txt文件并在文件中读取名为'bhavesh'的私有成员,因此证明它确实可用于子文件class,但由于访问修饰符而无法访问 .
打开MyData1.txt并搜索名为'bhavesh'的私有成员 . 请让我知道你们的想法 .
似乎子类确实继承了私有字段,因为这些字段在子类的内部工作中被用(哲学上讲) . 子类在其构造函数中调用超类构造函数 . 如果超类构造函数在其构造函数中初始化了这些字段,那么超类私有字段显然是由调用超类构造函数的子类继承的 . 这只是一个例子 . 但是当然没有访问器方法,子类无法访问超类私有字段(就像无法弹出iPhone的后面板以取出电池来重置手机......但电池仍在那里) .
PS我遇到的许多继承定义之一:“继承 - 一种编程技术,它允许派生类扩展基类的功能,继承其所有的STATE(强调是我的)和行为 . ”
私有字段,即使子类不可访问,也是超类的继承状态 .
填充位/对齐以及在VTABLE中包含对象类是不考虑 . 因此,子类的对象确实为Super类的私有成员提供了一个位置 . 但是,无法从子类的对象访问它...
No ,私有字段不是继承的 . 唯一的原因是子类无法访问它们 directly .
我相信,答案完全取决于被问到的问题 . 我的意思是,如果问题是
然后回答是 No ,如果我们通过access specifier details,就会提到,私有成员只能在类本身内访问 .
但是,如果问题是
这意味着,无关紧要,您将如何访问私有成员 . 在这种情况下,我们可以在超类中创建公共方法,您可以访问私有成员 . 因此,在这种情况下,您将创建一个接口/桥接来访问私有成员 .
其他OOP语言如C,具有 friend function 概念,通过它我们可以访问其他类的私有成员 .
我们可以简单地声明,当继承超类时,超类的私有成员实际上成为子类的私有成员,并且不能进一步继承或无法使用子类的对象 .