-2

リフレクション (パッケージ java.lang.reflect) を使用して、さらに別のパッケージ内の別の内部クラスを拡張する別のパッケージ内の内部クラスのプライベート フィールドにアクセスするにはどうすればよいですか?

package MainPackage;
import java.lang.reflect.Field;

class PrimaryClass
{
    public static void main(String[] args)
    {
        AuxiliaryPackage.TerciaryClass.BugattiVeyron bugattiVeyron = 
            (new AuxiliaryPackage.TerciaryClass()).new BugattiVeyron(
                new MainPackage.SecondaryClass());        

        System.out.println("Name: "+ bugattiVeyron.name);
        System.out.println("Tires type: " + bugattiVeyron.tiresType);
        try
        {
            Class bugattiVeyronClass = bugattiVeyron.getClass();
            Field invisibleField1 = bugattiVeyronClass.getDeclaredField("topSpeed");
            invisibleField1.setAccessible(true);
            System.out.println(invisibleField1.get(bugattiVeyron));
            Field invisibleField2 = bugattiVeyronClass.getDeclaredField("tamperedOdometer");
            invisibleField2.setAccessible(true);
            System.out.println(invisibleField2.get(bugattiVeyron));
        }
        catch (Exception e)
        {
            /* I ALWAYS GET AN EXCEPTION !! */
            /* I need a change to be done IN the TRY block. */
            /* WHEN THE BugattiVeyron class DOES NOT EXTEND another inner class, NO EXCEPTION. */
            /* See at the end for a detail of the just mentioned case. */
            System.out.println("An exception has occurred.");
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
    }
}



package MainPackage;
public class SecondaryClass
{
    public class SportsCar
    {
        /* Public fields. Accesible from any package. */
        public String name = new String();

        /* Protected fields. Accesible from the same package and subclasses in any package */
        protected String tiresType = new String();

        /* Package fields. No explicit modifier. Accessible from the same package only. */
        int topSpeed; //km per hour

        /* Private fields. Accessible from the same class only. */
        private boolean tamperedOdometer;

        /* Default constructor */
        public SportsCar()
        {
            name = "Sports car";
            tiresType = "Race";
            topSpeed = 250;
            tamperedOdometer = false;
        }

        public SportsCar(String name, String tiresType, int topSpeed, boolean tamperedOdometer)
        {
            this.name = name;
            this.tiresType = tiresType;
            this.topSpeed = topSpeed;
            this.tamperedOdometer = tamperedOdometer;
        }     
    }
}



package AuxiliaryPackage;
public class TerciaryClass
{
    public class BugattiVeyron extends MainPackage.SecondaryClass.SportsCar
    {
        /* Default constructor */
        public BugattiVeyron(MainPackage.SecondaryClass secondaryClass)
        {
            secondaryClass.super("Buggati Veyron", "Michelin Pilot Sport PS2 PAX", 431, false);
        }
    }
}

BugattiVeyron クラスが何も拡張しない場合 (コードにいくつか変更を加えた後)、次のようにインスタンス化します。

AuxiliaryPackage.TerciaryClass.BugattiVeyron bugattiVeyron = (new
        AuxiliaryPackage.TerciaryClass()).new BugattiVeyron();

...そして例外は発生しません...では、try ブロックで何を変更すれば、うまく処理できるのでしょうか?

前もって感謝します!!

EDIT 1. 怒鳴るつもりはありませんでした。投稿が長いので、イントロが失われるかもしれないと思いました。stackTrace を含めました。謝罪します。これは私の 2 番目の質問です。

最初の例外は次のとおりです (他の例外も同様です)。

java.lang.NoSuchFieldException: topSpeed
        at java.lang.Class.getDeclaredField(Unknown Source)
        at MainPackage.PrimaryClass.main(PrimaryClass.java:17)

17 行目は次のとおりです。 Field invisibleField1 = bugattiVeyronClass.getDeclaredField("topSpeed");

EDIT 2.「良いプログラミングパターン」のように見えないことはわかっています。これは、java.lang.reflect の制限に関する調査に関するものです。

編集3:答え。親切で忍耐強く、答えを出そうとしてくれたすべての人に感謝します。最後に、vsbから解決策を得ました。そのため、質問を投稿してから回答を得るまでに約 1 時間かかりました。記録!私の最初の質問は、3 月 1 日以来まったく注目されていません。

4

2 に答える 2

0

このコードは機能します。

        Class bugattiVeyronClass = bugattiVeyron.getClass();
        Class sportsCarClass = bugattiVeyronClass.getSuperclass();
        Field invisibleField1 = sportsCarClass.getDeclaredField("topSpeed");
        Field invisibleField2 = sportsCarClass.getDeclaredField("tamperedOdometer");

BugattiVeyronクラスにはこれらのフィールドがありません。これらはスーパークラスからのものであり、それに応じてアクセスする必要があります。

次のメソッドを使用して、クラス階層内のフィールドを検索できます。

private static Field getDeclaredFieldInHierarchy(Class<?> clazz, String fieldName) {
    if (clazz == null) {
        return null;
    }
    try {
        return clazz.getDeclaredField(fieldName);
    } catch (NoSuchFieldException e) {
        return getDeclaredFieldInHierarchy(clazz.getSuperclass(), fieldName);
    }
}

ただし、問題を解決する別の方法を検討してください。それは非常に悪いスタイルであり、絶対に必要な場合にのみ使用する必要があります。

于 2012-06-11T08:18:38.567 に答える
0

getDeclaredFielddocs に記載されているように、Classオブジェクトが参照する正確なクラスのフィールドを提供します。フィールドがサブクラスで宣言されていない場合、そのようにはなりません。

代わりにgetFieldを使用することをお勧めします。

反映されるフィールドは、次のアルゴリズムによって決定されます。このオブジェクトが表すクラスを C とします。

  1. C が指定された名前でパブリック フィールドを宣言する場合、それが反映されるフィールドです。
  2. 上記のステップ 1 でフィールドが見つからなかった場合、このアルゴリズムが C の各直接スーパーインターフェースに再帰的に適用されます。直接スーパーインターフェースは、宣言された順序で検索されます。
  3. 上記の手順 1 と 2 でフィールドが見つからず、C にスーパークラス S がある場合、このアルゴリズムは S に対して再帰的に呼び出されます。C にスーパークラスがない場合は、NoSuchFieldException がスローされます。
于 2012-06-11T08:04:03.130 に答える