JAVA反射认识

2020-03-07  本文已影响0人  QM

什么是反射

Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。这样动态获取新的以及动态调用对象方法的功能就叫做反射。

反射的作用

我们知道反射机制允许程序在运行时取得任何一个已知名称的class的内部信息,包括包括其modifiers(修饰符),fields(属性),methods(方法)等,并可于运行时改变fields内容或调用methods。那么我们便可以更灵活的编写代码,代码可以在运行时装配,无需在组件之间进行源代码链接,降低代码的耦合度;还有动态代理的实现等等;但是需要注意的是反射使用不当会造成很高的资源消耗!

1 Class类

得到 Class 的三种基本方式

Class c1 = Test.class; //这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的()
Class c2 = test.getClass();// test是Test类的一个对象,这种方式是通过一个类的对象的getClass()方法获得的 (对于基本类型无法使用这种方法)
Class c3 = Class.forName("com.catchu.me.reflect.Test"); //这种方法是Class类调用forName方法,通过一个类的全量限定名获得(基本类型无法使用此方法)

通过 Class 类获取成员变量、成员方法、接口、超类、构造方法等

//获得类完整的名字
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等
}
        
//获得类的所有方法。
Method [] allMethods = c2.getDeclaredMethods();
for(Method method : allMethods){
    System.out.println(method.getName());//work say
}
        
//获得指定的属性
Field f1 = c2.getField("age");
System.out.println(f1);
//获得指定的私有属性
Field f2 = c2.getDeclaredField("name");
//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
f2.setAccessible(true);
System.out.println(f2);
                
//创建这个类的一个对象
Object p2 =  c2.newInstance();
//将 p2 对象的  f2 属性赋值为 Bob,f2 属性即为 私有属性 name
f2.set(p2,"Bob");
//使用反射机制可以打破封装性,导致了java对象的属性不安全。 
System.out.println(f2.get(p2)); //Bob
        
//获取构造方法
Constructor [] constructors = c2.getConstructors();
for(Constructor constructor : constructors){
    System.out.println(constructor.toString());//public com.ys.reflex.Person()
}

通过反射调用方法

  • 注意:如果方法是private的,可以使用method.setAccessible(true)方法绕过权限检查
  • 被调用的方法本身所抛出的异常在反射中都会以InvocationTargetException抛出。换句话说,反射调用过程中如果异常InvocationTargetException抛出,说明反射调用本身是成功的,因为这个异常是目标方法本身所抛出的异常。
Class<?> c = Cat.class;
 try {
     //构造Cat实例
     Constructor constructor = c.getConstructor(String.class, int.class);
     Object cat = constructor.newInstance( "Jack", 3);
     //调用无参方法
     Method sleep = c.getDeclaredMethod("sleep");
     sleep.invoke(cat);
     //调用定项参数方法
     Method eat = c.getDeclaredMethod("eat", String.class);
     eat.invoke(cat, "grass");
     //调用不定项参数方法
     //不定项参数可以当成数组来处理
     Class[] argTypes = new Class[] { String[].class };
     Method varargsEat = c.getDeclaredMethod("eat", argTypes);
     String[] foods = new String[]{
          "grass", "meat"
     };
     varargsEat.invoke(cat, (Object)foods);
  } catch (InstantiationException | IllegalAccessException | NoSuchMethodException | InvocationTargetException e) {
     e.printStackTrace();
 }

反射缺点

性能问题。因为反射是在运行时而不是在编译时,所有不会利用到编译优化,同时因为是动态生成,因此,反射操作的效率要比那些非反射操作低得多。
安全问题。使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。
代码问题。由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用--代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。

参考链接:https://www.jianshu.com/p/10c29883eac1

上一篇下一篇

猜你喜欢

热点阅读