はじめに
リフレクションが出現する前は、Javaクラスがある場合、クラス外のクラスでプライベート構造を使用できません。たとえば、プライベートコンストラクターやプライベートメソッドなどを呼び出すことはできません。しかし、リフレクションの後、プライベートを含むこのクラスの任意の構造を呼び出すことができます。
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class ReflectionTest {
@Test
public void test1(){
Person p = new Person("tom",23);
p.show();
}
@Test
public void test2() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
//1.获取类对象
Class<Person> personClass = Person.class;
//2.获取类对象的构造器
Constructor constructor = personClass.getConstructor(String.class, int.class);
Object tom = constructor.newInstance("Jerry", 23);
//3.获取类方法
Method show = personClass.getDeclaredMethod("show");
show.invoke(tom);
//反射的特殊功能,可以调用私有的类结构
Constructor<Person> cons1 = personClass.getDeclaredConstructor(String.class);
cons1.setAccessible(true);
Person wanglei = cons1.newInstance("wanglei");
wanglei.show();
}
}
リフレクションとシングルトンモード
シングルトンパターンはコンストラクターをプライベート化します。このクラスのインスタンスを1つだけ作成する必要があることを願っています。その時までに、リフレクションはそれが使用できるかどうかの問題を解決することであり、シングルトンモードはあなたの文章を提案することです。
java.lang.Classの理解
反射のソースとしてのクラス
(1)クラスの読み込みプロセス:プログラムがjavac.exeによってコンパイルされた後、1つ以上のバイトコードファイルが生成されます。クラスが終了すると、java.exeの解釈により、各javaクラスはバイトコードファイルに対応し、特定のコードを実行しますMianメソッドのバイトコードファイル。これは、このバイトコードファイルをメモリにロードすることと同じで、このプロセスはクラスロードと呼ばれます。メモリに記録されたクラスはランタイムクラスと呼ばれ、このランタイムクラスはClassのインスタンスとして使用されます。つまり、Classのインスタンスはランタイムクラスに対応します。
Classオブジェクトを取得する4つの方法
//方式一:调用运行时类的属性:.class
Class clazz1 = Person.class;
System.out.println(clazz1);
//方式二:通过运行时类的对象,调用getClass()
Person p1 = new Person();
Class clazz2 = p1.getClass();
System.out.println(clazz2);
//方式三:调用Class的静态方法:forName(String classPath)
Class clazz3 = Class.forName("com.atguigu.java.Person");
// clazz3 = Class.forName("java.lang.String");
System.out.println(clazz3);
System.out.println(clazz1 == clazz2);
System.out.println(clazz1 == clazz3);
//方式四:使用类的加载器:ClassLoader (了解)
ClassLoader classLoader = ReflectionTest.class.getClassLoader();
Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
System.out.println(clazz4);
System.out.println(clazz1 == clazz4);
3つのステップ:
ロード:クラスのクラスファイルをメモリに追加し、Classオブジェクトを作成します。このプロセスは、クラスローダーによって実行されます。
リンク:Classファイルのバイトストリームに含まれる情報が現在の仮想マシンの要件を満たし、仮想マシン自体のセキュリティを危険にさらしていないことを確認してください。
初期化:クラスファイルをコンパイルして生成すると、コンパイラーは2つのメソッドを生成してクラスファイルに追加します。1つはクラス初期化メソッドclinitで、もう1つはインスタンス初期化メソッドinitです。clinitはクラスコンストラクターを参照します。主な役割は、クラスの読み込みプロセスの初期化フェーズで実行することです。実行内容には、静的変数の初期化と静的ブロックの実行が含まれます。
はじめに
プロキシパターンは、23のデザインパターンの1つであり、これはより重要な知識であり、Springフレームワークのより重要なAOP(アスペクト指向プログラミング)も動的プロキシに基づいています。
エージェントの理解
エージェントの理解について例を挙げましょう。20年前、レノボのコンピューターを購入する方法は、レノボの工場に行き、工場がコンピューターを販売し、アフターサービスを提供するというものでした。
これらの数十年の発展の間に、いくつかのディーラーが現れました。彼らはLenovo工場から商品を購入して私たちに販売しました。コンピューターが壊れたとき、私たちはディーラーの店にも行き、彼を見つけました、そして彼は工場に行きました。工場との接続は実際に壊れていました。
2020年にラップトップを購入する場合は、Tmall、Suning、JD.comなどの大手代理店に直接コンピュータを購入します。問題が発生した場合は、理由のない限り7日間返品します。
ここではクライアントクライアント、これらのディーラーはエージェントとも呼ばれ、Lenovo工場はエージェントと呼ばれます。このようなプロセスはエージェントです。
動的プロキシ
動的プロキシの特性:バイトコードはいつでも作成およびロードされ、いつでもロードされます。
動的エージェントの役割:ソースコードを変更せずにメソッドを拡張する
動的エージェントの分類:2つのタイプ、1つはインターフェースに基づく動的エージェント、もう1つはサブクラスに基づく動的エージェント
インターフェイスベースの動的プロキシ
JDKが提供するプロキシクラスの実装では、プロキシクラスが少なくとも1つのインターフェースを実装する必要があります。実装プロセスは次のとおりです
(1)最初にLenovoクラスを作成してインターフェースを実装する
package com.alibaba200408.动态代理;
public class Lenovo implements ILenovo {
@Override
public void sale(Double money) {
System.out.println("拿到"+money+"元,电脑发货");
}
@Override
public void afterService(Double money) {
System.out.println("拿到"+money+"元,售后服务开始");
}
}
コードは非常にシンプルで、1つはコンピューターを販売する方法、もう1つはコンピューターを修理する方法です。
インターフェースのコードは以下の通りです
package com.alibaba200408.动态代理;
public interface ILenovo {
void sale(Double money);
void afterService(Double money);
}
(2)動的プロキシオブジェクトをインスタンス化し、プロキシオブジェクトを介してメソッドを呼び出す
package com.alibaba200408.动态代理;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
//联想厂家
ILenovo lenovo = new Lenovo();
//创建代理对象
ILenovo proxyInstance = (ILenovo) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(),
lenovo.getClass().getInterfaces(),
new InvocationHandler() {
/**
* invoke方法的作用是调用任何被代理对象的方法都会被这个invoke方法拦截
* proxy:表示当前代理对象的引用
* method:表示当前正在执行的方法
* args:表示当前执行的方法的参数
*
* 返回值就是当前方法的返回值
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//提供增强的代码
Double money = (Double) args[0];
if ("sale".equals(method.getName())){
method.invoke(lenovo, money * 0.8);
}else {
method.invoke(lenovo,args);
}
return null;
}
});
proxyInstance.afterService(10000.0);
}
}
サブクラスに基づく動的エージェント
この実装では、最終的に変更されたクラスにサブクラスを含めることができないため、プロキシクラスをfinalにすることはできません。次に、このメソッドにはサードパーティのcglibが必要です。ここでは繰り返しません。