Java反射メカニズムアクセスクラスプライベートメソッドと変数

8279 ワード

Java反射メカニズムアクセスクラスプライベートメソッドと変数
背景
Javaの反射メカニズムを利用して、実行時のクラス情報(RTTI)を得ることができ、従来のRTTIとは異なり、反射は実行時に.classファイルを得ることができ、.classファイルを開いてチェックすることができ、すべてのJavaの反射は強い柔軟性を持っている.反射は、使用可能なメソッドをチェックし、メソッド名を返すメカニズムを提供します.もちろん、ドメイン変数メンバーなどの他の情報を得ることもできます.反射機構により変数を得るためのプライベートメソッドと変数は理論的に実行可能であり,手順は非常に簡単であり,Javaコードと組み合わせて紹介する.
1.クラス構造
class Food{
    private String foodname;

    Food(String foodname){
        this.foodname = foodname;
    }
    private void f(){
        System.out.println("private Food Method");
    }
}

class Cake extends Food{
    private String privateCakeName;
    public String publicCakeName;

    Cake(String priName, String pubName, String superName){
        super(superName);
        privateCakeName = priName;
        publicCakeName = pubName;
    }

    private void g(){
        System.out.println("private Cake Method");
    }

    public void h(){
        System.out.println("public Cake Method");
    }
}

2.このクラスのプライベート変数とメソッドへのアクセス
まずClass.getMethod(String name,Class...parameterType)はこのクラスおよび親クラスがアクセスできる方法を得ることができ,ここでの方法はpublic void h()であるため,直接反射によって得ることができる.Class.getDeclaredField(String name)を使用すると、プライベートメソッド(親を取得できない)を含むクラスのすべてのメソッドを取得できます.これにより、プライベートメソッドを反射的に呼び出すことができます.invoke(...)を呼び出す前にsetAccessible(boolean flag)を追加する必要があります.そうしないとjava.lang.IllegalAccessExceptionが生成されます.この方法はAccessibleObjectクラスから継承されます.Method.setAccessible(true)を呼び出すと、アクセス制御はこのMethodオブジェクトにのみ機能し、他のMethodオブジェクトには機能しません.
JDK API    
  
    AccessibleObject    Field、Method   Constructor      。                      Java            。      、  (  )    、          ,      Field、Method   Constructor           、    ,                ,       。
             accessible                  (   Java Object Serialization         )                 。
    setAccessible 
    public void setAccessible(boolean flag) 
                       throws SecurityException 
          accessible            。   true                  Java       。   false              Java       。
       setAccessible               ,    true     false     ,     ,                ,        ,     ,         ,               ,   ,       AccessibleObject  setAccessible()         ,        Field,Method Constructor   AccessibleObject,  ,         setAccessible()  ,              。                ,  ,      java.security.manager           setAccessible()   。     ,  API             ,       URLClassLoader             。

同様に、Class.getDeclaredFiled(String name)は、nameに基づいてクラスのプライベートドメインオブジェクトを取得してアクセスすることもできますが、スーパークラスのドメインオブジェクトは取得できません.
Cake applecake = new Cake("smallAppleCake", "bigAppleCake", "cake");
try {
    //        
    Cake.class.getMethod("h").invoke(applecake);
    //Output:public Cake Method

    //        
    Method privateMethod = Cake.class.getDeclaredMethod("g");
    privateMethod.setAccessible(true);
    privateMethod.invoke(applecake);
    //Output:private Cake Method

    //        
    Field privateField = Cake.class.getDeclaredField("privateCakeName");
    privateField.setAccessible(true);
    System.out.println(privateField.get(applecake));
    //Output:smallAppleCake

} catch (Exception e) {
    e.printStackTrace();
}

3.親プライベート変数とメソッドへのアクセス
Class.getSuperclass()を使用すると、クラス、インタフェース、またはvoidを含むエンティティのスーパークラスが得られます.スーパークラスが得られると、以前の方法で反射してスーパークラスのプライベートメソッドとプライベートドメインオブジェクトにアクセスできます.
Cake applecake = new Cake("smallAppleCake", "bigAppleCake", "cake");
try {
    //        
    Method privateMethod = Cake.class.getSuperclass().getDeclaredMethod("f");
    privateMethod.setAccessible(true);
    privateMethod.invoke(applecake);
    //Output:private Food Method

    //        
    Field privateField = Cake.class.getSuperclass().getDeclaredField("foodname");
    privateField.setAccessible(true);
    System.out.println(privateField.get(applecake));
    //Output:cake

} catch (Exception e) {
    e.printStackTrace();
}

4.いくつかの反射機構の応用例
  • は、オブジェクトが属するクラスおよびスーパークラスのすべてのドメイン変数名(プライベートを含む)
  • を得る.
    private List getInheritedPrivateFields(Class> type) {
        List result = new ArrayList();
    
        Class> i = type;
        while (i != null && i != Object.class) {
            Collections.addAll(result, i.getDeclaredFields());
            i = i.getSuperclass();
        }
    
        return result;
    }
  • final Stringが指す文字列の内容を変更する
  • final String s = "abc";
    System.out.println(s);
    //Output:abc
    Field field = s.getClass().getDeclaredField("value");
    field.setAccessible(true);
    char[] chars = (char[])field.get(s);
    chars[0] = '1';
    chars[1] = '2';
    chars[2] = '3';
    System.out.println(s);
    //Output:123

    5.反射メカニズムによるプライベートドメインへのアクセスを防止する方法はありますか?SecurityManagerは、setAccessibleの呼び出しを制限することができ、それ以外に方法はない.