1

次のコードがあります。次の 2 つの質問があります。

class Parent {  

        private void test()  
        {  
            System.out.print("test executed!");  
        }
        static void print(){
            System.out.println("my class is parent");
        }
}

class Child extends Parent  
    {  
    static void print(){
        System.out.println("my class is Child");
    }

    }  


   public class Inheritence {

        public static void main(String[] args)  
        {  
            Child p1 = new Child();
            Parent p = new Child();  
            System.out.println("The class name of p is "+p.getClass());
            System.out.println("The class name of p1 is "+p1.getClass());
            System.out.println("p instance of child "+ (p instanceof Child));
            System.out.println("p1 instance of child "+ (p1 instanceof Child));
            //p.test(); 
            p.print();
        }     
    }  

出力は次のとおりです。

The class name of p is class Child
The class name of p1 is class Child
p instance of child true
p1 instance of child true
my class is parent

タイプが であるため、クラス名は にpなると思いました。ただし、 として印刷されます。どうすれば の を取得できますか。ParentParentChildtypep

ここでの 2 番目の質問は、プライベート メソッドが継承されているかどうかです。thisを含む多くの記事では、プライベート メソッドは継承されないというコメントがありますが、以下の例では継承されていることがわかります。以下の型キャストの問題である可能性があります。

class Child1 extends Parent1  
    {  

    }  


    public class Parent1 {  

        private void test()  
        {  
            System.out.print("test executed!");  
        }  

        public static void main(String[] args)  
        {  
                Parent1 p = new Child1();  
                p.test();
                Child1 c = new Child1();
                //c.test(); The method test from parent1 is not visible
            }     
        }  

Output is : test executed!

ここでは、タイプのオブジェクトでtestメソッドを呼び出しています。継承されないため、メソッドはありません。しかし、プライベート メソッドが継承されていることを示す出力が得られます。保護されたメソッドであり、子クラスでオーバーライドした場合、それが呼び出されるオブジェクトのタイプが親であっても、実行されるのはオーバーライドされたメソッドですChild1Parent1Child1testtest(parent p1 = new child1());

編集:いくつかのコメントの後、クラス Parent1 とクラス Child1 を別々に作成し、親と子のオブジェクトを構築する App という新しいクラスを作成しました。今、私はp.test以下のコードを呼び出すことができません。

class Child1 extends Parent1  
    {  


    }  


     class Parent1 {  

        private void test()  
        {  
            System.out.print("test executed!");  
        } }

    public class App1{

        public static void main(String[] args)  
        {  
            Parent1 p = new Child1();  
            p.test();//The method test from parent is not visible
            Child1 c = new Child1();
            //c.test(); //The method test from parent1 is not visible

        }     
    }  
4

2 に答える 2

1

2 番目の質問に対処するには、「継承」と「可視性」の概念を区別しておくと役立つ場合があります。privateメソッドは、メソッドが宣言されているクラス内mでのみ表示されます。したがって、外部からCはまったく使用できません。さらに、 の内部でも、オブジェクトが型であると宣言されていないと使用できません。ただし、サブクラスのオブジェクトには引き続きメソッドがあり、そのメソッドを呼び出すことはできますが、内部でのみ可能です。この例はコンパイルされます (2 つのクラスが別々のファイルにある場合でも)。mCCx.m()xCmC

public class Class1 {
    private void test () { System.out.println ("test"); }
    public void doThis (Class2 c) {
        // c.test();  -- does not compile [1]
        ((Class1)c).test();
    }
}

public class Class2 extends Class1 {
    public void doSomething () {
        doThis (this);
        // ((Class1)this).test();  -- does not compile [2]
    }
}

の内部では、タイプがであってものメソッドをdoThis呼び出すことができることに注意してください。ただし、これを行うことができるのは、コードがメソッドを宣言するクラス内にあるためです (これが [2] がコンパイルされない理由です)。タイプのオブジェクトにキャストすることによってのみそれを行うことができます(これが[1]がコンパイルしない理由です)。ただし、コンパイラが type の式として認識するようにキャストした後でも、実際のオブジェクトにはまだ type があります。また、このようにオーバーライドされたメソッドを呼び出す場合:オブジェクトは実際にはまだオブジェクトであるため、ではなくで定義されたメソッドを呼び出します。testccClass2Class1test()cClass1Class1Class2polymorphic((Class1)c).polymorphic()Class2Class1Class2

test だから、ある意味では、プライベートでも受け継がれていると思います。に表示されないだけですClass2

詳細: コンパイル時の型と実行時の型 (またはインスタンス型) には違いがあることを理解することも役立つと思います。変数を宣言すると、Parent x;コンパイルx時の型はParent. f戻り値の型がの関数がある場合Parent、次のような式の型は にobj.f(arg,arg2)なりますParent。ただし、実行時に、変数または式にコンパイル時の type がある場合、Parent実行時の実際の型はParent またはそのサブクラスのいずれかになります。実行時の型は、オブジェクトがどのように構築されたかに基づきます。したがって、変数はコンパイル時の型Parentと実行時の型を持つことができますChild。次に、どのタイプがいつ使用されるかを知る必要があります。メソッドが表示されているかどうかを確認するため (どこにあるかprivateが登場する)、コンパイル時の型が使用されます。子サブクラスがメソッドをオーバーライドするときに呼び出すメソッドを決定するために、ランタイム型が使用されます (これがポリモーフィズムです)。の場合.getClass()、ランタイム タイプが使用されます。とにかく、あまり混乱しないように、そう考えています。

例: あるとしましょう:

class Parent { }
class Child extends Parent { }
class Grandchild extens Child { }

他のクラスでは、

Parent x1 = new Parent();
Parent x2 = new Child();
Parent x3 = new Grandchild();

変数x1x2、およびx3すべてのコンパイル時の型は Parentです。これは、3 つの変数すべてが のインスタンス、Parentのインスタンス、ChildまたはGrandchildの他のサブクラスを参照できることを意味しますParentx2は のインスタンスを参照しChildx3のインスタンスを参照し ますGrandchild

同様に:

private Parent getAParent(int n) {
    if (n == 0) return new Parent();
    if (n == 1) return new Child();
    if (n == 2) return new Grandchild();
    throw new IllegalArgumentException();
}

Parent x4 = getAParent (0);
Parent x5 = getAParent (1);
Parent x6 = getAParent (2);

x5は のインスタンスを参照し、 のインスタンスをChild参照x6しますGrandchild

しかし、すべての変数と呼び出しのコンパイル時の型getAParent はまだParent. コンパイラは、プログラムの実行時に、変数または関数呼び出しが実際にどのクラスを参照しているかを知りません。したがって、play()内でメソッドを宣言しGrandchildても、これらは依然として不正です。

x3.play ();             // ERROR
x6.play ();             // ERROR
getAParent(2).play ();  // ERROR

コンパイラは 2 つの変数 andを、 ではなくgetAParent(2) 型を持つと見なすためです。Andは に対して定義されていません。これらの変数がメソッドを持つランタイム型を持っているかどうかを確認するには、コンパイラが実行時にチェックするコードを生成する必要がありますが、コンパイラはそれを行いません。ParentGrandchildplayParentplay

p.test()それが、2番目の例で機能する理由です。p のインスタンスを参照しているにもかかわらずChild1pのコンパイル時の型は Parent1、 type を持つと宣言したためですParent1。そして、コンパイラはParent1メソッドがあるtestことを認識します。コードは内部Parent1にあるため、testメソッドは非公開ですが表示されます。それが機能する理由です。pコンパイラは、実行時の型が実際に参照するものをチェックするコードを生成しません。これが物事の説明に役立つことを願っています。

于 2013-09-13T00:33:41.153 に答える
0

p のクラス名は Parent 型なので、Parent になると思いました。ただし、子として印刷されます。

クラス名は、変数の型ではなく、インスタンスの型を反映します。

ここでは、Parent1 型の Child1 オブジェクトでテスト メソッドを呼び出しています。Child1 は継承されていないため、テスト メソッドはありません。

ただし、 2 つのクラスが同じファイルにあり、プライベート メソッドがそれぞれに表示されるため、テスト メソッド継承される可能性があります。そのため、Child1 は継承され、その親の非プライベート メソッドをすべて使用できるようになります。それが継承のすべてです。つまり、親の動作 (メソッド) と状態 (フィールド) を再利用します。Child1 がしないことは、親メソッドをオーバーライドしないことです。


編集

テストメソッドは親クラスでプライベートであるため、正しく継承されません

コードが同じ単一のファイルにあるように見えるため、利用できます。クラスを独自のファイルに入れてみて、何が起こるかを確認してください (コードがコンパイルされるかどうかを確認してください)。

于 2013-09-12T23:59:58.440 に答える