Java反射机制概念
1,什么是反射?
Reflection(反射):是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
2,Java 反射机制提供的功能
①,在运行时判断任意一个对象所属的类
②,在运行时构造任意一个类的对象
③,在运行时判断任意一个类所具有的成员变量和方法
④,在运行时获取泛型信息
⑤,在运行时调用任意一个对象的成员变量和方法
⑥,在运行时处理注解
⑦,生成动态代理
3,获取Class实例的三种常见方式
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命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。此过程就称为类的加载。加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。
②,换句话说,Class的实例就对应着一个运行时类
③,加载到内存中的运行时类,会缓存一定的时间,在此时间之内,我们可以通过不同的方式来获取此运行时类
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,调用运行时类中指定的结构:属性,方法/font>
属性:
//创建运行时类的对象
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接口的实现类及其方法invoke())
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("东坡肉");
}
}