(31)反射

Javaのリフレクション機構コンセプト

1.反射とは何ですか?
      反射(反射):鍵は、動的言語とみなされ、反射リフレクションAPIは、内部および内部特性及び任意のオブジェクトのメソッドの実装によって、任意のタイプの情報を取得するプログラムを直接操作することができる可能にします。

2、Javaリフレクション機構は、機能を提供します

①は、実行時のオブジェクトで決定されたいずれかのクラスに属し、

②、実行時に任意のオブジェクトのコンストラクタクラス

③、任意のクラスの決意は、実行時にメンバ変数とメソッドを有します

④、実行時に一般的な情報を取得します

⑤、実行時にオブジェクトのいずれかのメンバ変数やメソッドを呼び出します

⑥、実行時に注釈を処理します

⑦、動的プロキシを生成

3、3つの一般的な方法のクラスインスタンスを取得

Class clazz1 = String.class;
Class clazz2 = person.getClass();
Class clazz3 = Class.forName(String classpath)

図4に示すように、反射を使用して

@Test
//反射的使用
public void test01() throws Exception {
    Class clazz = Person.class;
    //1,通过反射,创建Person类的对象
    Constructor constructor = clazz.getConstructor(String.class, int.class);
    Object object = constructor.newInstance("Tommey,222");
    Person p = (Person)object;
    System.out.println(p.toString());
    
    //2,通过反射,调用对象指定的属性,方法
    Field age = clazz.getDeclaredField("age");
    age.set(p,10);
    System.out.println(p.toString());

    //调用方法
    Method show = clazz.getDeclaredMethod("show");
    show.invoke(p);

    //通过反射,可以调用Person类的私有结构的。比如:私有的构造器,方法,属性
    //调用私有的构造器
    Constructor constructor1 = clazz.getDeclaredConstructor(String.class);
    constructor1.setAccessible(true);
    Person p1 = (Person)constructor1.newInstance("Tom");
    
    //调用私有的属性
    Field name = clazz.getDeclaredField("name");
    name.setAccessible(true);
    name.set(p1, "a");
    
    //调用私有的方法
    Method showNation = clazz.getDeclaredMethod("showNation", String.class);
    showNation.setAccessible(true);
    showNation.invoke(p1,"中国");
}

ClassLoaderクラスローダーと理解

1、java.lang.Classクラスの理解

①、クラスのロード処理

       プログラムコマンドのjavac.exe後にした後、それが一つ以上のバイトコードファイル(エンドの.class)を生成します。その後、我々はファイル解釈バイトコードの実行にはjava.exeコマンドを使用します。メモリにバイトコードファイルを読み込むと同等。このプロセスは、ロード・クラスと呼ばれています。メモリクラスにロードされ、我々はそれがクラスの一例として、ある、このクラスが実行されているランタイムクラスと呼ばれます。

②、言い換えれば、それはクラスのランタイムクラスの一例に相当し、

③、ランタイムクラスのメモリにロードされ、いくつかの時間をキャッシュし、この時間の間、私たちはさまざまな方法でこのランタイムクラスを取得することができます

2、2つの方法で設定ファイルをロード

道の設定ファイルを読み込みます:

Properties pros = new Properties();
FileInputStream fis = new FileInputStream("jdbc.properties");
pros.load(fis);

第二の方法の設定ファイルを読み込み:ClassLoaderを

ClassLoader classLoader = ClassLoaderTest.class.getClassLoader();
InputStream is = classLoader.getResourceAsStream("jdbc.properties");
pros.load(fis);

完全な実行時のクラス構造のため

図1に示すように、一般的なアプリケーションのランタイム・クラス、メソッド、インターフェイス、コンストラクタを取得します

//getFields():获取当前运行时类及其父类中声明为public访问权限的属性
Class clazz = Person.class;
Field[] fields = clazz .getFields();
//getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)
Field[] declaredFields = clazz.getDeclaredFields();
getMethods():获取当前运行时类及其所有父类中声明为public权限的方法
getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)
Field方法中:
  public int getModifiers() 以整数形式返回此Field的修饰符 --> Modifier.toString(modifier)
  public Class<?> getType() 得到Field的属性类型
  public String getName() 返回Field的名称
全部的方法:
   public Method[] getDeclaredMethods()返回此Class对象所表示的类或接口的全部方法
   public Method[] getMethods()返回此Class对象所表示的类或接口的public的方法
Method类中:
   public Class<?> getReturnType()取得全部的返回值
   public Class<?>[] getParameterTypes()取得全部的参数
   public int getModifiers()取得修饰符
   public Class<?>[] getExceptionTypes()取得异常信息
   //获取运行时类的带泛型的父类的泛型
   Type genericSuperclass = Person.class.getGenericSuperclass();
   ParameterizedType paramType = (ParameterizedType) genericSuperclass;
   //获取泛型类型
   Type[] actualTypeArguments = paramType.getActualTypeArguments();

   //获取运行时类实现的接口
   Class[] interfaces = clazz.getInterfaces();
   //获取运行时类的父类实现的接口
   Class[] interfaces1 = clazz.getSuperclass().getInterfaces();

プロパティ、メソッド/フォント>:2、ランタイムがクラスに割り当てられた構造を呼び出し、

属性:

  //创建运行时类的对象
  Person p = (Person)clazz.newInstance();
  //1,getDeclaredField(String fieldName):获取运行时类中指定变量名的属性
  Field name = clazz.getDeclaredField("name");
  //获取指定的属性:要求运行时类中属性声明为public,不理想,要求属性权限太高
  Field id = clazz.getField("id");
  id.set(p,1000);
  //2,保证当前属性是可访问的
  name.setAccessible(true);
  //3,获取,设置指定对象的此属性值
  name.set(p, "Tommey");

方法:

  //1,获取指定的某个方法getDeclaredMethod():参数1:指明获取的方法的名称 参数2:指明获取的方法形参列表
  Method show = clazz.getDeclaredMethod("show", String.class);
  show.setAccessible(true);
  //2,调用方法invoke():参数1:方法的调用者 参数2:给方法形参赋值的实参,invoke()的返回值即为对应类中调用的方法的返回值
  Object returnValue = show.invoke(p, "CHN");
  //调用静态方法
  Method showDesc = clazz.getDeclaredMethod("showDesc");
  showDesc.setAccessible(true);
  Object returnVal = showDesc.invoke(Person.class);

ダイナミックエージェントが反映しました

1、管理プロキシデザインパターンの原則:
      プロキシオブジェクトの使用は、パッケージ、および、プロキシオブジェクトを使用して、元のオブジェクトを置き換えています。元のオブジェクトに対するすべての呼び出しは、プロキシを経由しなければなりません。プロキシオブジェクトは、いつ元のオブジェクトのメソッド呼び出しに行くことにするかどうかを決定します。

図2に示すように、例えば帯電防止剤、。

interface ClothFactory{
    void produceCloth();
}
//代理类
class ProxyClothFactory implements ClothFactory{

    private  ClothFactory factory;//用被代理类对象进行实例化

    public ProxyClothFactory(ClothFactory factory) {
        this.factory = factory;
    }

    @Override
    public void produceCloth() {
        System.out.println("代理工厂做一些准备工作");
        factory.produceCloth();
        System.out.println("代理工厂做一些后续的收尾工作");
    }
}

//被代理类
class NikeClothFactory implements ClothFactory{

    @Override
    public void produceCloth() {
        System.out.println("Nike工厂生产一批运动服");
    }
}

public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被代理类的对象
        ClothFactory nike = new NikeClothFactory();
        //创建代理类的对象
        ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
        proxyClothFactory.produceCloth();
    }
}

例えば図3に示すように、ダイナミックプロキシー。

動的プロキシの問題を達成するために対処する必要がありますか?

  • 一つの問題:どのようにメモリをプロキシクラスにロードされ、動的プロキシクラスを作成し、そのオブジェクト(たとえば、Proxy.newProxyInstance(によって実装))

  • 第二の問題:動的メソッド名を呼び出す方法、プロキシクラスのメソッドを呼び出すことにより、オブジェクトが同じプロキシクラスである(のInvocationHandlerインタフェース呼び出しを実装したクラスとそのメソッド())

interface Human{

    String getBelief();
    void eat(String food);
}

class SuperMan implements Human{

    @Override
    public String getBelief() {
        return "他有一个喜欢的人!";
    }

    @Override
    public void eat(String food) {
        System.out.println("她喜欢吃"+food);
    }
}

class ProxyFactory{
    //调用此方法,返回一个代理类的对象。解决问题一
    public static Object getProxInstance(Object obj){
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
    }
}

class  MyInvocationHandler implements InvocationHandler{

    private Object obj;

    public void bind(Object obj){
        this.obj = obj;
    }

    //当我们通过代理类的对象,调用方法a时,就会自动的调用如下方法:invoke();
    //将被代理类要执行的方法a的功能久声明在invoke中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        return method.invoke(obj,args);
    }
}

public class ProxyTest {

    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxInstance(superMan);
        String belief = proxyInstance.getBelief();
        System.out.println(belief);

        proxyInstance.eat("东坡肉");
    }
}
公開された67元の記事 ウォン称賛19 ビュー9868

おすすめ

転載: blog.csdn.net/qq_41530004/article/details/104367122