web-dev-qa-db-ja.com

Javaのプライベートメソッドをオーバーライドできますか?

リフレクションを使用してプライベートメソッドを呼び出したり、プライベート変数の値を取得または設定したりできることはわかっていますが、メソッドをオーバーライドしたいと思います。

_public class SuperClass {

    public void printInt() {
        System.out.println("I am " + getClass() + ". The int is " + getInt());
    }

    private int getInt() {
        return 1;
    }
}

public class SubClass extends SuperClass {

    public static void main(String[] args) {
        (new SubClass()).printInt();
    }

    public int getInt() {
        return 2;
    }
}
_

mainSubClassメソッドで_2_を出力したいのですが、_1_が出力されます。これは振り返りでできると聞きましたが、どうすればいいのかわかりません。リフレクションでない場合、誰かがそれを行う別の方法を知っていますか? (SuperClass.getInt()を保護するか、printInt()メソッドをコピーしてSubClassに貼り付ける以外に。)プライベートメソッドを実際にオーバーライドできない場合は、次の方法があります。プライベートメソッドの実行前または実行後にサブクラスのメソッドを呼び出す何らかのトリガーを配置しますか?

13
numbers longer

プライベートメソッドは継承されず、オーバーライドすることはできません。振り返ってそれができるとあなたに言った人は誰でも嘘をついているか、何か他のことについて話していました。

ただし、次のようにgetIntを呼び出しているサブクラスのプライベートメソッドprintIntにアクセスできます。

public void printInt() throws Exception {
    Class<? extends SuperClass> clazz = getClass();
    System.out.println("I am " + clazz + ". The int is " +
                       clazz.getMethod("getInt").invoke(this) );
}

これは、サブクラスのgetIntメソッドがスーパークラスのprintIntから呼び出される効果があります。もちろん、サブクラスがしないgetIntを宣言すると、これは失敗するので、試行しない「通常の」サブクラスを処理できるようにチェックを追加する必要があります。プライベートメソッドを「オーバーライド」するには:

public void printInt() throws Exception {
    Class<? extends SuperClass> clazz = getClass();

    // Use superclass method by default
    Method theGetInt = SuperClass.class.getDeclaredMethod("getInt");

    // Look for a subclass method
    Class<?> classWithGetInt = clazz;
    OUTER: while( classWithGetInt != SuperClass.class ){

        for( Method method : classWithGetInt.getDeclaredMethods() )
            if( method.getName().equals("getInt") && method.getParameterTypes().length == 0 ){
                theGetInt = method;
                break OUTER;
            }

        // Check superclass if not found
        classWithGetInt = classWithGetInt.getSuperclass();
    }

    System.out.println("I am " + classWithGetInt + ". The int is " + theGetInt.invoke(this) );
}

これを機能させるには、スーパークラスコードを変更する必要があります。スーパークラスコードを変更する必要があるため、リフレクションハックアラウンドを行う代わりに、getIntのアクセス修飾子をprotectedに変更する必要があります。

14
trutheality

派生クラスを含む他のクラスはそれが存在することを認識できないため、プライベートメソッドをオーバーライドすることはできません。それはプライベート。

プライベートメソッドは暗黙的にfinalです。

関連する注記として、サブクラスの観点からはこれらのメンバーが存在しないため、サブクラスはスーパークラスのprivateフィールドまたはメソッドと同じ名前のフィールドまたはメソッドを宣言できます。これらのメンバー間に特別な関係はありません。

20
erickson

いいえ、できません。外部クラス内のコードがネストされたクラスのプライベートメンバーにアクセスできるという事実を使用して、これを実行できるようにlookプログラムを構築できます。ただし、プライベートメソッドを実際にオーバーライドすることはできません。例:

public class Test {

    public static class Superclass {
        private void foo() {
            System.out.println("Superclass.foo");
        }
    }

    public static class Subclass extends Superclass {
        private void foo() {
            System.out.println("Subclass.foo");
            // Looks like it shouldn't work, but does...
            super.foo();
        }
    }

    public static void main(String[] args) throws Exception {
        Superclass x = new Subclass();
        // Only calls Superclass.foo...
        x.foo();
    }
}

これがのみプライベートメソッドをオーバーライドすることが可能であった状況であることを考えると、それがサポートされていないことは大きな損失ではありません。

スーパークラスのプライベートメンバーの動作を変更したい場合、基本的にデザインは壊れています。

14
Jon Skeet

リフレクションではこれを行うことはできませんでしたが、インストルメンテーションを介してこれを行う方法を見つけました。 Dhruba Bandopadhyayのブログ で提案されているように、私はASMを使用しました。興味がある場合は、 my code を参照してください(ここに投稿するには多すぎます)。

5
numbers longer

リフレクションを使用してこれを本当に実行したい場合は、次のことができます。

public class SuperClass {

    private final Method getInt;

    public SuperClass() {
        /** Find the appropriate method to call and cache it. **/
        Method getInt = null;
        try {
            getInt = getClass().getDeclaredMethod("getInt");
        }
        catch (NoSuchMethodException e) {
            try {
                getInt = SuperClass.class.getDeclaredMethod("getInt");
            } catch (NoSuchMethodException e1) {
                throw new RuntimeException(e1);
            }
        }
        getInt.setAccessible(true);
        this.getInt = getInt;
    }

    public void print() {
        int val = 0;
        try {
            val = (Integer) getInt.invoke(this);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
        System.out.println(val);
    }

    private int getInt() {
        return 1;
    }
}

public class SubClass extends SuperClass {
    public int getInt() {
        return 2;
    }

    public static void main(String[] args) throws Exception {
        new SubClass().print();
    }
}

このアプローチをとるのではなく、別の方法でプログラムを設計したいのではないでしょうか。それはパフォーマンスが良くなく、SuperClassを拡張する人を驚かせるでしょう。

この方法でリフレクションを使用すると、サブクラスのgetInt()メソッドがプライベートになる可能性があることに注意してください。繰り返しますが、少なくともこの2つの理由から、このアプローチを取ることはほぼ間違いなく悪い考えです。別の方法で目標を達成できる可能性があります。パッケージ保護は本当にオプションではありませんか?

2

プライベートメソッドをオーバーライドすることはできませんが、派生クラスでプライベートメソッドを導入/再定義することはできます。

class Super
{
   private void fun()
   {
   }
}

class Child extends Super
{
    private void fun()
    {
    }
}

これでは、Childクラスでこのfun()をオーバーライドしていませんが、同じ名前で新しいメソッドを定義していますが、Childクラスのfun()の上で@overrideを使用しようとすると、コンパイル時エラーが発生します。このfun()をオーバーライドすることを強制している場合は、Childクラスで新しいfun()を再定義するだけです。

0
Moni

Javaを使用してクラスを参照->クラスで渡すことができますか?

なぜなら、それが可能であれば、上記の問題は次のように書き直すことができるからです。

(これは仕様のみを目的としていることに注意してください)

VB:

function(ByRef intX as Integer)//値は明示的に変更できますが、メソッド自体は変更できません:P end function

そんなに私が推測するように...

0
i am ArbZ

いいえ、プライベートメソッドをオーバーライドすることはできませんが、プライベートメソッドもオーバーライドできる場合があります。つまり、内部クラスです。

class PrivateTest { 

private String msg = "OuterAndInner";

private void fun() {
     System.out.println("Outer fun()");
}

class Inner extends PrivateTest {
    private void fun()  {
          System.out.println("Accessing Private Member of Outer: " + msg);
    }
}
public static void main(String args[])  {
     PrivateTest o = new PrivateTest();
     Inner  i   = o.new Inner();
     i.fun();
     // o.fun() calls Outer's fun (No run-time polymorphism).
     o = i; 
     o.fun();
}

}

0
Rahul Maurya

プライベートメソッドをオーバーライドすることはできません。

オーバーライドするメソッドは、オーバーライドされるメソッドのサブクラスにのみ存在できます。オーバーライドするメソッドがprivateとマークされている場合、サブクラスはprivateとマークされたものを継承しないため、オーバーライドすることはできません。したがって、そのプライベートメソッドとサブクラスのメソッドを含む、サブクラス内のすべてのもの。

「オーバーライドする」とは、JVMが、呼び出すインスタンスタイプに基づいて使用するメソッドを決定できるようにすることを意味します。ポリモーフィズムの理論は、これを可能にするものを説明しています。 JVMが「これらのメソッドが接続され、一方が他方をオーバーライドする」と言えるようにするには、JVMがoverriddenメソッドを表示できる必要があります内からoverridingメソッドを含むサブクラス

そうは言っても、指定した場合のクラスは引き続きコンパイルされますが、JVMに基づいて呼び出されるメソッドはどちらも、インスタンスベースの呼び出しを個別に実行しません。これらは単に、JVMによってオーバーライドまたはオーバーライドされていると認識されない、まったく異なるメソッドになります。

さらに、NetBeansなどのIDEを使用している場合、@ Overrideアノテーションを使用すると、スーパークラスで同じシグネチャを使用してメソッドをオーバーライドしていることをコンパイラに指示します。そうでない場合この場合、注釈を付けることを示唆する警告が表示されますが、次の場合にこの注釈を適用すると、コンパイルエラーが発生します。

  • スーパークラスに一致する署名を持つメソッドはありません

OR

  • オーバーライドしようとしているスーパークラスのメソッドがprivateまたはfinalとマークされている

次の抜粋については、オラクルの公式ドキュメントhttps://docs.Oracle.com/javase/tutorial/Java/IandI/override.htmlを参照してください。

インスタンスメソッド

...サブクラスがメソッドをオーバーライドする機能により、クラスは動作が「十分に近い」スーパークラスから継承し、必要に応じて動作を変更できます。..メソッドをオーバーライドする場合は、@を使用することをお勧めします。スーパークラスのメソッドをオーバーライドすることをコンパイラに指示するオーバーライドアノテーション。なんらかの理由で、コンパイラーがメソッドがスーパークラスの1つに存在しないことを検出すると、エラーが生成されます。

オーバーライドは、JVMが一見独立してアクションを実行することを伴うため、非常に混乱する可能性があります。スーパークラスのメソッド[s]にアクセスしないと(つまり、すべてのメソッドがprivateとマークされている場合)、サブクラスはそのメソッドを呼び出すこともオーバーライドすることもできないことに注意してください。そうするためにそれらを継承しないでください。

0