什么是反射?
Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。
主要实现
Class类
public final Class getClass()
此方法返回值类型是一个Class类,Class类是Java反射的源头。每一个对象实例都能记得自己是被哪个Class实例所生成的,所以我们可以通过Class类获得一个类的完整结构。
/**
* 我们创建了一个类 通过编译(javac.exe),生成对应的.class文件,然后使用java.exe加载(JVM的类加载器).class文件
* 此.class文件加载到内存以后就是一个运行时类,存在缓存区中。那么这个运行时类本身就是一个Class的实例。一个运行时类只被加载一次
*/
@Test
public void test() {
Person p = new Person();
Class clazz = p.getClass();
System.out.println(clazz);
}
实例化Class类对象的四种方式
1)前提:若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高
实例:Class clazz = String.class;
2)前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象
实例:String str = new String("123");
Class clazz =str.getClass();
3)前提:已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
实例:Class clazz= Class.forName(“java.lang.String”);
4)其他方式
ClassLoader cl =this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“类的全类名”);
通过反射创建类对象
①通过调用类的无参构造器创建类对象
前提:Person类存在无参的构造器,且必须有足够的权限(public)
@Test
public void test2() throws Exception {
Class clazz = Class.forName("com.wya.j2se.reflection.Person");
System.out.println(clazz);
Object obj = clazz.newInstance();
Person p = (Person)obj;
System.out.println(p);
}
②通过调用无参构造创建类的对象
/**
* 通过有参构造创建类的对象
* @throws Exception
*/
@Test
public void test3() throws Exception {
Class clazz = Class.forName("com.wya.j2se.reflection.Person");
//获取类的有参构造器
Constructor con = clazz.getConstructor(String.class,Integer.class);
//传入参数,通过有参构造器创建类对象
Object obj = con.newInstance("jack",21);
//获取对象实例
Person p = (Person)obj;
System.out.println(p);
}
通过反射获取运行时类的属性
@Test
public void test4() throws Exception {
Class clazz = Person.class;
//getFields()方法只能获取运行时类及其父类中的public的属性
Field[] fields = clazz.getFields();
for(Field f : fields){
System.out.println(f);
}
//getFields()方法只能获取运行时类中的所有的属性
fields = clazz.getDeclaredFields();
for(Field f : fields){
System.out.println(f);
}
}
public java.lang.String com.wya.j2se.reflection.Person.name
public java.lang.String com.wya.j2se.reflection.Person.name
private java.lang.Integer com.wya.j2se.reflection.Person.age
/**
* 获取类的属性的修饰符、类型、名称
* @throws Exception
*/
@Test
public void test5() throws Exception {
Class clazz = Person.class;
//getFields()方法只能获取运行时类中的所有的属性
Field[] fields = clazz.getDeclaredFields();
for(Field f : fields){
int m = f.getModifiers();
System.out.print("修饰符:"+Modifier.toString(m));
Class t = f.getType();
System.out.print("变量类型:"+t.getName());
System.out.print("变量名:"+f.getName());
System.out.println();
}
}
修饰符:public变量类型:java.lang.String变量名:name
修饰符:private变量类型:java.lang.Integer变量名:age
通过反射获取类的方法
/**
* 获取类的方法
* @throws Exception
*/
@Test
public void test6() throws Exception {
Class clazz = Person.class;
//getMethods()方法只能获取运行时类及其父类中的public的方法
Method[] methods = clazz.getMethods();
for(Method m : methods){
System.out.println(m);
}
//getDeclaredMethods()方法只能获取运行时类中的所有的方法
methods = clazz.getDeclaredMethods();
for(Method m : methods){
System.out.println(m);
}
}
/**
* 获取类的方法的注解 权限修饰符 返回值类型 方法名 形参列表 异常
* @throws Exception
*/
@Test
public void test7() throws Exception {
Class clazz = Person.class;
Method[] methods = clazz.getDeclaredMethods();
for(Method m : methods){
Annotation[] anns = m.getAnnotations();
for(Annotation ann : anns){
System.out.print("注解:"+ann);
}
int i = m.getModifiers();
System.out.print("权限修饰符:"+Modifier.toString(i));
Class type = m.getReturnType();
System.out.print("返回值类型:"+type.getName());
System.out.print("方法名:"+m.getName());
System.out.print("参数列表(");
Class[] params = m.getParameterTypes();
for(int j =0 ;j<params.length;j++ ){
System.out.print(params[j].getName()+"args-"+j+" ");
}
System.out.print(")");
System.out.print("异常:");
Class[] exs = m.getExceptionTypes();
for(Class ex : exs){
System.out.print(ex.getName());
}
System.out.println();
}
}
权限修饰符:public返回值类型:java.lang.String方法名:toString参数列表()异常:
权限修饰符:public返回值类型:java.lang.String方法名:getName参数列表()异常:
权限修饰符:public返回值类型:void方法名:setName参数列表(java.lang.Stringargs-0 )异常:
权限修饰符:public返回值类型:void方法名:setAge参数列表(java.lang.Integerargs-0 )异常:
权限修饰符:public返回值类型:java.lang.Integer方法名:getAge参数列表()异常:
权限修饰符:public返回值类型:void方法名:display参数列表()异常:java.lang.Exception
获取运行时类的构造器
@Test
public void test8() throws Exception {
Class clazz = Person.class;
Constructor[] cons = clazz.getDeclaredConstructors();
for(Constructor con : cons){
System.out.println(con);
}
}
public com.wya.j2se.reflection.Person()
public com.wya.j2se.reflection.Person(java.lang.String,java.lang.Integer)
/**
* 获取父类
* @throws Exception
*/
@Test
public void test9() throws Exception {
Class clazz = Person.class;
Class superClazz = clazz.getSuperclass();
System.out.println(superClazz);
}
/**
* 获取带泛型的父类
* @throws Exception
*/
@Test
public void test10() throws Exception {
Class clazz = Person.class;
Type type = clazz.getGenericSuperclass();
System.out.println(type);
}
/**
* 获取父类的泛型
* @throws Exception
*/
@Test
public void test11() throws Exception {
Class clazz = Person.class;
Type type = clazz.getGenericSuperclass();
ParameterizedType pt = (ParameterizedType)type;
Type[] types = pt.getActualTypeArguments();
System.out.println((Class)types[0]);
}
获取运行时类实现的接口
/**
* 获取实现的接口
* @throws Exception
*/
@Test
public void test12() throws Exception {
Class clazz = Person.class;
Class[] clazzs = clazz.getInterfaces();
for(Class c : clazzs){
System.out.println(c);
}
}
获取其他
/**
* 获取所在的包
* @throws Exception
*/
@Test
public void test13() throws Exception {
Class clazz = Person.class;
Package p = clazz.getPackage();
System.out.println(p);
}
/**
* 获取注解,只能获取runtime的注解
* @throws Exception
*/
@Test
public void test14() throws Exception {
Class clazz = Person.class;
Annotation[] anns = clazz.getAnnotations();
for(Annotation ann : anns){
System.out.println(ann);
}
}
调用指定的属性
/**
* 调用指定的属性
* @throws Exception
*/
@Test
public void test15() throws Exception {
Class clazz = Person.class;
Field name = clazz.getField("name");
Person p = (Person)clazz.newInstance();
name.set(p, "tom");
Field age = clazz.getDeclaredField("age");
//私有的属性需要设置权限
age.setAccessible(true);
age.set(p, 22);
System.out.println(p);//Person [name=tom, age=22]
}
调用指定的方法
/**
* 调用指定方法
* @throws Exception
*/
@Test
public void test16() throws Exception {
Class clazz = Person.class;
Person p = (Person)clazz.newInstance();
//getMethod(String name, Class<?>... parameterTypes)
Method m = clazz.getMethod("display", String.class);
// invoke(Object obj, Object... args) 参数必须与getMethod的方法数量相同否则抛出异常//私有方法需要设置操作权限m.setAccessible(true);
m.invoke(p, "jeff");
//调用静态方法
Method m2 = clazz.getMethod("info");
m2.invoke(Person.class);
}
i am person my name is jeff
hello world
反射与动态代理
特征是代理类和目标对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能。
动态代理
使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上。
实现动态代理需要一个类:Proxy, 专门完成代理的操作类,是所有动态代理类的父类。通过此类为一个或多个接口动态地生成实现类。
package com.wya.j2se.reflection;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//接口
interface Subject{
public void action();
}
//被代理类
class MySubject implements Subject{
@Override
public void action() {
System.out.println("我被代理了");
}
}
//接口
interface Human{
public void fly();
}
//被代理类
class Superman implements Human{
@Override
public void fly() {
System.out.println("我会飞了");
}
}
//创建一个实现接口InvocationHandler的类,它必须实现invoke方法,以完成代理的具体操作。
class MyInvocationHandler implements InvocationHandler{
//被代理类的声明
private Object obj;
//给被代理类实例化并返回该代理类的对象
public Object blind(Object obj){
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
//执行代理类重写的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object returnValue = method.invoke(obj, args);
return returnValue;
}
}
public class TestProxy {
public static void main(String[] args) {
//创建实现了InvocationHandler的类对象
MyInvocationHandler handler = new MyInvocationHandler();
//创建被代理类的对象
MySubject mySubject = new MySubject();
//动态绑定并返回一个同样实现了MySubject实现的接口的实现类
Object obj = handler.blind(mySubject);
//此时subject就是被代理类的对象
Subject subject = (Subject)obj;
subject.action();
//创建被代理类的对象
Superman superman = new Superman();
obj = handler.blind(superman);
Human human = (Human)obj;
human.fly();
}
}
我被代理了
我会飞了
package com.wya.j2se.reflection;
public class MyUtil {
public static void method1(){
System.out.println("通用方法1");
}
public static void method2(){
System.out.println("通用方法2");
}
}
重写invoke方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MyUtil.method1();
Object returnValue = method.invoke(obj, args);
MyUtil.method2();
return returnValue;
}
通用方法1
我被代理了
通用方法2
通用方法1
我会飞了
通用方法2
类加载机制