14

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

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

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

4

10 に答える 10

20

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

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

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

于 2012-05-16T17:53:48.247 に答える
15

プライベート メソッドは継承されず、いかなる方法でもオーバーライドできません。リフレクションでそれを行うことができると言った人は、嘘をついているか、何か他のことを話している.

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) );
}

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

于 2012-05-16T18:09:58.647 に答える
14

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

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();
    }
}

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

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

于 2012-05-16T18:20:50.427 に答える
5

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

于 2012-05-27T17:49:52.293 に答える
2

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

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 つの理由から、このアプローチを採用することはほぼ間違いなく悪い考えです。別の方法で目標を達成できる可能性があります。パッケージ保護は本当にオプションではないのですか?

于 2012-05-16T18:30:39.923 に答える
0

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

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

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

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

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

  • スーパークラスに一致するシグネチャを持つメソッドがありません

また

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

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

インスタンス メソッド

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

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

于 2016-06-10T23:49:32.580 に答える
0

java を使用して var -> classes を参照渡しできますか?

可能であれば、上記の問題は次のように書き直すことができます。

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

VB:

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

私が推測するように...

于 2014-03-05T09:34:19.377 に答える
-1

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

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();
}

}

于 2015-05-24T17:42:56.407 に答える
-1

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

class Super
{
   private void fun()
   {
   }
}

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

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

于 2016-01-28T21:53:04.150 に答える
-5

これをよく読んで、

PRIVATE メソッドは継承されません...継承されないため、上書きできません

于 2012-05-16T18:01:57.603 に答える