一、反射是什么
通过反射,我们可以手动的动态的生成对象,获取对象的方法,在没有对象类的时候可以通过反射字节码的方式达到完全和有java类的时候的所有功能。
反射的核心就是,从字节码获取java对象。
归根到底,我们其实是要获取一个类的Class对象。
二、获取Class对象的方法
1.使用现有类的.class方法
@Test
public void test(){
Class cls = Person.class;
System.out.println(cls);
}
2.使用基类的getClass方法
Person p = new Person();
Class cls = p.getClass();
System.out.println(cls);
3.使用Class.forName方法
Class cls = Class.forName("cn.itcast.bean.Person");
System.out.println(cls);
三、Class对象的使用
3.1 获取基本信息
获取包名
Class cls = Class.forName("cn.itcast.bean.Person");
Package package1 = cls.getPackage();
System.out.println(package1);
3.2 获取属性字段
Class cls = Class.forName("cn.itcast.bean.Person");
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
System.out.println("修饰符:" + field.getModifiers() + ",字段名称:"
+ field.getName());
}
3.3 获取构造性创建实例
Class cls = Class.forName("cn.itcast.bean.Person");
Constructor cs = cls.getConstructor();
System.out.println("无参构造器:" + cs);
Constructor cs1 = cls.getConstructor(int.class);
System.out.println("有参构造器:" + cs1);
Constructor cs2 = cls.getConstructor(String.class, int.
System.out.println("有参构造器:" + cs2);
Person person = (Person) cs.newInstance();
System.out.println("无参构造器创建对象:" + person);
Person person1 = (Person) cs2.newInstance("zhangsan",20
System.out.println("有参构造器创建对象:" + person1);
3.4 获取并调用方法
3.4.1 获取方法
Class cls = Class.forName("cn.itcast.bean.Person");
Method[] methods = cls.getMethods();
for (Method method : methods) {
System.out.println("所有方法名称:" + method.getName());
}
System.out.println("===========================" );
Method[] declaredMethods = cls.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println("自定义声明的方法名称:" + method.getName());
}
3.4.2 调用方法
Class cls = Class.forName("cn.itcast.bean.Person");
Method method = cls.getMethod("sayHello",String.class);
Person person =(Person)cls.getConstructor(String.class,int.class).newInstance("lisi",12);
method.invoke(person, "hello,i am lisi, 12 years old.");
四、动态代理
java中的动态代理技术是指生成一个新的对象,可以对新的对象实现就老对象的完全功能并进行扩展,也是基于反射的,不过被代理的对象必须实现某个接口。
4.1 类加载器
获取当前类的加载器
Class cls = Class.forName("cn.itcast.bean.Person");
System.out.println(cls.getClassLoader().getClass().getName());
其实在java中有三种类类加载器。
1)Bootstrap ClassLoader 此加载器采用c++编写,一般开发中很少见。
2)Extension ClassLoader 用来进行扩展类的加载,一般对应的是jre\lib\ext目录中的类
3)AppClassLoader 加载classpath指定的类,是最常用的加载器。同时也是java中默认的加载器。
4.2 被代理对象和实现接口
如果要实现动态代理,需要创建一个类,实现接口
package cn.itcast.proxy;
public interface Human {
void say();
}
package cn.itcast.proxy;
public class Chinese implements Human {
@Override
public void say() {
System.out.println("我是中国人");
}
}
4.3 实现InvocationHandler接口
package cn.itcast.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ChineseInvocationHandler implements InvocationHandler {
private Chinese chinese;
public Object getProxyObject(Chinese chinese){
this.chinese = chinese;
return Proxy.newProxyInstance(Chinese.class.getClassLoader(), Chinese.class.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("被代理对象之前干一些事情:中国威武");
Object temp = method.invoke(this.chinese, args);
System.out.println("被代理对象之后干一些事情:日本辣鸡");
return temp;
}
}
这里要把被代理的对象传进去,是因为要使用被代理对象的功能,并且要增强一下被代理对象,就想我们要扩展一个类的时候,建立一个新的类,引用老的类一样。
4.4 测试代码
ChineseInvocationHandler handler = new ChineseInvocationHandler();
Human human = (Human)handler.getProxyObject(new Chinese());
human.say();
五、总结
这就是基本的反射的使用。