Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。
优点:
- 增加程序灵活性。
- 提高代码复用性。
缺点:
- 反射操作的效率要比那些非反射操作低得多
ps:这肯定比你直接调用来慢得多。
反射大概比直接调用慢50~100倍,但是需要你在执行100万遍的时候才会有所感觉.
如果你只是偶尔调用一下反射,请忘记反射带来的性能影响
如果你需要大量调用反射,请考虑缓存。 - 模糊内部逻辑
ps:你发现没有是操作的 .class字节码
反射等绕过了源代码的技术,因而会带来维护问题 - 安全限制
反射技术要求程序必须在一个没有安全限制的环境中运行 - 内部暴露
ps:你发现没有,private 都不管用了。
由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法)
使用方法:
1.获取对象.class文件
Person p1 = new Person();
Class c1 = p1.getClass();
Class c2 = Person.class;
Class c3 = Class.forName(“com.ys.reflex.Person”);
2.通过方法,来执行你所要达到的要求.
常用方法:
//获得类完整的名字
String className = c2.getName();
System.out.println(className);//输出com.ys.reflex.Person
//获得类的public类型的属性。
Field[] fields = c2.getFields();
for(Field field : fields){
System.out.println(field.getName());//age
}
//获得类的所有属性。包括私有的
Field [] allFields = c2.getDeclaredFields();
for(Field field : allFields){
System.out.println(field.getName());//name age
}
//获得类的public类型的方法。这里包括 Object 类的一些方法
Method [] methods = c2.getMethods();
for(Method method : methods){
System.out.println(method.getName());//work waid equls toString hashCode等
}
//获得类的所有方法。 .invoke()的使用.
Method [] allMethods = c2.getDeclaredMethods();
for(Method method : allMethods){
System.out.println(method.getName());//work say
}
// 方法的反射操作
// a1.print(10, 20);方法的反射操作是用m对象来进行方法调用 和a1.print调用的效果完全相同
// 方法如果没有返回值返回null,有返回值返回具体的返回值
// Object o = m.invoke(a1,new Object[]{10,20});
Method m = c.getMethod("print", int.class, int.class); //print方法,参数是两个 int
Object o = m.invoke(a1, 10, 20);//调用方法,左边为方法返回值
// 获取方法print(String,String)
Method m1 = c.getMethod("print", String.class, String.class);
o = m1.invoke(a1, "hello", "WORLD");//调用
//获得指定的属性
Field f1 = c2.getField("age");
System.out.println(f1);
//获得指定的私有属性
Field f2 = c2.getDeclaredField("name");
//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
f2.setAccessible(true);
//创建这个类的一个对象
Object p2 = c2.newInstance();
//将 p2 对象的 f2 属性赋值为 Bob,f2 属性即为 私有属性 name
f2.set(p2,"Bob");
//使用反射机制可以打破封装性,导致了java对象的属性不安全。
System.out.println(f2.get(p2)); //Bob
动态代理:
/**
* 顶层接口
* @author yujie.wang
*
*/
public interface Person {
public void sayHello(String content, int age);
public void sayGoodBye(boolean seeAgin, double time);
}
/**
* 需要被代理的类 实现了一个接口Person
* @author yujie.wang
*
*/
public class Student implements Person{
@Override
public void sayHello(String content, int age) {
// TODO Auto-generated method stub
System.out.println("student say hello" + content + " "+ age);
}
@Override
public void sayGoodBye(boolean seeAgin, double time) {
// TODO Auto-generated method stub
System.out.println("student sayGoodBye " + time + " "+ seeAgin);
}
}
/**
* 动态代理,动态代理类不要显示的实现被代理类所实现的接口 ,实现InvocationHandler接口
* @author yujie.wang
*
*/
public class MyInvocationHandler implements InvocationHandler{
private Object object;
public MyInvocationHandler(Object object){
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
System.out.println("MyInvocationHandler invoke begin");
System.out.println("proxy: "+ proxy.getClass().getName());
System.out.println("method: "+ method.getName());
for(Object o : args){
System.out.println("arg: "+ o);
}
//通过反射调用 被代理类的方法
method.invoke(object, args);
System.out.println("MyInvocationHandler invoke end");
return ;
}
public static void main(String [] args){
//创建需要被代理的类
Student s = new Student();
//这一句是生成代理类的class文件,前提是你需要在工程根目录下创建com/sun/proxy目录,不然会报找不到路径的io异常
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//获得加载被代理类的 类加载器
ClassLoader loader = Thread.currentThread().getContextClassLoader();
//指明被代理类实现的接口
Class<?>[] interfaces = s.getClass().getInterfaces();
// 创建被代理类的委托类,之后想要调用被代理类的方法时,都会委托给这个类的invoke(Object proxy, Method method, Object[] args)方法
MyInvocationHandler h = new MyInvocationHandler(s);
//生成代理类
Person proxy = (Person)Proxy.newProxyInstance(loader, interfaces, h);
//通过代理类调用 被代理类的方法
proxy.sayHello("yujie.wang", 20);
proxy.sayGoodBye(true, 100);
System.out.println("end");
}
}