web-dev-qa-db-ja.com

サブクラスはプライベートフィールドを継承しますか?

これはインタビューの質問です。

サブクラスはプライベートフィールドを継承しますか?

"normal OOP way"を使ってアクセスすることはできないので、 "いいえ"と答えました。しかし、インタビュアーはそれらが継承されていると考えています、なぜなら私たちはそのようなフィールドに間接的にあるいはリフレクションを使ってアクセスすることができ、それらはまだオブジェクトの中に存在するからです。

私が戻ってきた後、私は javadoc の中に次の引用を見つけました:

スーパークラスのプライベートメンバー

サブクラスは、その親クラスのプライベートメンバーを継承しません。

あなたはインタビュアーの意見に対する何らかの議論を知っていますか?

225
Stan Kurilin

ここでの質問/回答の混乱の大部分は、継承の定義を取り囲んでいます。

明らかに、@ DigitalRossが説明するように、サブクラスのOBJECTはスーパークラスのプライベートフィールドを含まなければなりません。彼が述べているように、個人会員にアクセスできないということは、会員がそこにいないという意味ではありません。

しかしながら。これはクラスの継承の概念とは異なります。意味論の問題があるJavaの世界の場合と同様に、アービターは Java言語仕様 (現在第3版)です。

JLSが述べているように( https://docs.Oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.2 ):

Privateと宣言されているクラスのメンバーは、そのクラスのサブクラスによって継承されません。クラスが宣言されているもの以外の、パッケージ内で宣言されているサブクラスによって、protectedまたはpublicとして宣言されているクラスのメンバだけが継承されます。

これはインタビュアーによって提起された正確な質問に対処します: "do subCLASSESはプライベートフィールドを継承する"。 (私が強調しました)

答えはいいえです。そうではありません。サブクラスのOBJECTSはそれらのスーパークラスのプライベートフィールドを含みます。サブクラス自体には、そのスーパークラスのプライベートフィールドはありません。

それは小説的な性質の意味論ですか?はい。面接の質問になりますか?おそらくそうではありません。しかし、JLSはJavaの世界のための定義を確立しており、それは明確にそうなっています(この場合)。

EDITED(Bjarne Stroustrupからの並列引用を削除しました。Javaとc ++の違いによるもので、混乱を招くだけのものです。私の答えはJLSに任せましょう:)

222
robert_x44

はい

areクラスが2つありますが、オブジェクトは1つしかないことに注意してください。

そのため、もちろん、プライベートフィールドを継承しました。おそらく、適切なオブジェクト機能に不可欠であり、親クラスのオブジェクトは派生クラスのオブジェクトではありませんが、派生クラスのインスタンスはほとんどの場合、親クラスのインスタンスです。すべてのフィールドがなければ、うまくいきません。

いいえ、直接アクセスすることはできません。はい、それらは継承されます。彼らはhaveになります。

いい質問です!


Update:

エラー、「いいえ」

まあ、私たちは皆何かを学んだと思います。 JLS が「継承されていない」正確な表現に由来するため、"no"と答えることは正しいことです。サブクラスはプライベートフィールドにアクセスまたは変更できないため、言い換えると、これらは継承されません。しかし、実際にはisちょうどoneオブジェクト、それは本当にdoes containsプライベートフィールド。だから誰かがJLSとチュートリアルの言葉遣いを間違った方法で取った場合、OOP、Javaオブジェクト、および実際に何が起こっているのかを理解するのは非常に困難です。

更新して更新:

ここでの論争は根本的な曖昧さを含んでいます:何が正確に議論されていますか?object?クラス自体についてのある意味?オブジェクトとは対照的にクラスを記述するとき、多くの緯度が許されます。したがって、サブクラスはプライベートフィールドを継承しませんが、サブクラスのインスタンスであるオブジェクト確かにcontainプライベートフィールドを継承します。

73
DigitalRoss

プライベートフィールドは継承されません...そしてそれがProtectedが発明された理由です。仕様によるものです。私はこれが保護された修飾語の存在を正当化したと思います。


今文脈に来ています。継承とはどういうことですか - 派生クラスから作成されたオブジェクト内にある場合はどうなりますか?はい、そうです。

あなたが意味するならそれは派生クラスに役立つことができます。うーん、ダメ。

さて、あなたが関数型プログラミングに来るとき、スーパークラスのプライベートフィールドはサブクラスのために意味のある方法で継承されていません。サブクラスの場合、スーパークラスのプライベートフィールドは他のクラスのプライベートフィールドと同じです。

機能的には継承されていません。でも理想的には、そうです


さて、ちょうど彼らがこれを引用するJavaチュートリアルを調べました:

スーパークラスの非公開メンバー

サブクラスは、その親クラスのプライベートメンバーを継承しません。ただし、スーパークラスにそのプライベートフィールドにアクセスするためのパブリックメソッドまたは保護されたメソッドがある場合は、これらもサブクラスで使用できます。

参照してください: http://download.Oracle.com/javase/tutorial/Java/IandI/subclasses.html

私はその分野があることに同意します。しかし、サブクラスはそのプライベートフィールドに対する特権を得ません。サブクラスにとって、プライベートフィールドは他のクラスのプライベートフィールドと同じです。

純粋に視点の問題だと思います。あなたはどちらの側でも議論を形作ることができる。両方の方法を正当化することをお勧めします

18
Nishant

それはあなたの "継承"の定義次第です。サブクラスはまだメモリー内にフィールドを持っていますか?絶対に。直接アクセスできますか?いいえ、それは定義の微妙なことです。重要なのは、実際に起こっていることを理解することです。

11
Mehrdad

この概念をコードで説明します。サブクラスACTUALLYはスーパークラスのプライベート変数を継承します。唯一の問題は、スーパークラスのプライベート変数にパブリックゲッターとセッターを提供しない限り、それらは子オブジェクトにアクセスできないということです

パッケージDumpの2つのクラスを考えます。子供は親を伸ばします。

正しく覚えていれば、メモリ内の子オブジェクトは2つの領域で構成されています。一方は親部分のみで、もう一方は子部分のみです。子は、親のパブリックメソッドを介してのみその親のコード内のプライベートセクションにアクセスできます。

このように考えてください。ボラットの父親であるボルトクは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
10
Borat Sagdiyev

いいえ。彼らはそれを継承していません。

他のクラスが間接的にそれを使用するかもしれないという事実は、継承についてではなく、カプセル化については何も言いません。

例えば:

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?
     }
}

リフレクションを介してcount内のUseItの値を取得することもできます。それはあなたがそれを継承するという意味ではありません。

更新

値がそこにあっても、それはサブクラスによって継承されません。

例えば、次のように定義されたサブクラス

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とそれが機能する方法です。

私たちは実際に親を変更することができ、サブクラスはまだ動作します。

たとえば

//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仮想マシン仕様

9
OscarRyz

インタビュアーの質問に対する私の答えは - です。非公開メンバーはサブクラスに継承されませんが、サブクラスまたはサブクラスのオブジェクトにアクセスできるのは、パブリックgetterメソッドまたはsetterメソッドまたはそのような適切なオリジナルメソッドのみです。 class - 通常の慣例では、メンバーを非公開にして、公開されている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を使用しようとすると、変更のために直接アクセスすることはできません(継承されないことを意味します)。しかし、setXofParent()メソッドORのように、元のクラスのsetX()メソッドを使用してxをSubClassで変更することができます。 ()。だからここでsetX()とgetX()はParentClassのプライベートメンバxへの一種のゲートです。

もう1つの単純な例は、Clockスーパークラスがprivateメンバとしてhoursとminを持ち、publicとして適切なgetterメソッドとsetterメソッドを持つことです。それからDigitalClockがClockのサブクラスとして登場する。 DigitalClockのオブジェクトに時間と分のメンバーが含まれていない場合は、状況がおかしくなります。

6
dganesh2002

わかりました、これは私がよく調べた非常に興味深い問題で、スーパークラスのプライベートメンバーはサブクラスのオブジェクトで実際に利用可能です(しかしアクセス不可能)という結論に至りました。これを証明するために、これは親クラスと子クラスを持つサンプルコードで、私は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」という名前のプライベートメンバーを検索します。皆さんの考えを教えてください。

4
Bhavesh Agarwal

サブクラスはプライベートフィールドを継承しているように見えます。これらのフィールドはサブクラスの内部的な働きで利用されているからです(哲学的に言えば)。サブクラスは、そのコンストラクター内でスーパークラスコンストラクターを呼び出します。スーパークラスのプライベートフィールドは、スーパークラスのコンストラクタがコンストラクタ内でこれらのフィールドを初期化している場合、スーパークラスのコンストラクタを呼び出すサブクラスによって継承されることは明らかです。それはほんの一例です。しかし、もちろん、アクセサメソッドがないと、サブクラスはスーパークラスのプライベートフィールドにアクセスできません(iPhoneのバックパネルをポップして、電話機をリセットするためにバッテリを取り外すことはできませんが、バッテリはまだあります)。

PS私が遭遇した継承の多くの定義の1つです。「継承 - 派生クラスが基本クラスの機能を拡張し、そのすべてのSTATE(強調は私のものです)と振る舞いを継承することを可能にするプログラミング技法」。

プライベートフィールドは、サブクラスからアクセスできない場合でも、スーパークラスの継承状態です。

3
Flanker

Memory Layout in Java vis-a-vis inheritance

enter image description here

VTABLEにパディングビット/アライメントおよびオブジェクトクラスを含めることは考慮されていません。そのため、サブクラスのオブジェクトには、スーパークラスのプライベートメンバーのための場所があります。しかし、それはサブクラスのオブジェクトからアクセスすることはできません...

いいえ、プライベートフィールドは継承されません。唯一の理由は、サブクラスがそれらにアクセスできない直接ということです。

1
joooohnli

私は、Javaのプライベートフィールドareが継承されていると答える必要があります。説明させてください:

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"にアクセスすることができないので、人々はそれが継承されないと主張するということです。ただし、クラス内の静的でないものはすべて、フィールドでもメソッドでも継承されます。

0
Lawful Lazy

非公開クラスのメンバまたはコンストラクタは、メンバまたはコンストラクタの宣言を囲む最上位クラスの本体( §7.6 )内でのみアクセス可能です。サブクラスによって継承されません。 https://docs.Oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.6

0
mimibar

私は信じています、答えは完全に尋ねられてきた質問に依存しています。質問があれば

直接にサブクラスからスーパークラスのプライベートフィールドにアクセスできますか?

答えはNoです。 アクセス指定子の詳細 を通過すると、非公開メンバーはクラス内でのみアクセス可能です。

しかし、質問があれば

サブクラスからスーパークラスのプライベートフィールドにアクセスできますか?

つまり、重要ではなく、あなたがプライベートメンバーにアクセスするために何をするかということです。その場合は、スーパークラスでパブリックメソッドを作成してプライベートメンバーにアクセスすることができます。したがって、この場合は、プライベートメンバーにアクセスするためのインターフェイス/ブリッジを1つ作成しています。

C++のような他のOOP言語にはfriend functionという概念があり、それによって他のクラスのprivateメンバーにアクセスできます。

0
Ravi

スーパークラスが継承されると、スーパークラスのプライベートメンバは実際にはサブクラスのプライベートメンバになり、それ以上継承できないか、サブクラスのオブジェクトにアクセスできないと簡単に言えます。

0
Aamir wani