JAVA基础-反射

1,什么是反射?

  Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。)语言的一个关键性质。

2,反射的作用

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

3,反射的具体实现

3.1 获取到 Class 三种方式。

//1、通过对象调用 getClass() 方法来获取,通常应用在:比如你传过来一个 Object
//  类型的对象,而我不知道你具体是什么类,用这种方法
  Person p1 = new Person();
  Class c1 = p1.getClass();

//2、直接通过 类名.class 的方式得到,该方法最为安全可靠,程序性能更高
//  这说明任何一个类都有一个隐含的静态成员变量 class
  Class c2 = Person.class;

//3、通过 Class 对象的 forName() 静态方法来获取,用的最多,
//   但可能抛出 ClassNotFoundException 异常
  Class c3 = Class.forName("com.ys.reflex.Person");

需要注意的是:一个类在 JVM 中只会有一个 Class 实例,即我们对上面获取的 c1,c2,c3进行 equals 比较,发现都是true

3.2 获取包名/类名等

Person aClass = Person.class;

aClass.getPackage().getName();
aClass.getSimpleName();
aClass.getName();
aClass.getTypeName();
aClass.getCanonicalName();

3.3 反射构建对象

Person aClass = Person.class;

Person person = aClass.newInstance();

这里必须有无参构造方法

3.4 构造方法

Person aClass = Person.class;

//获取所有 public 构造方法
aClass.getConstructors();
        
//获取无参构造方法
aClass.getConstructor();

//获取指定参数列表的构造方法        
Constructor<? extends Person> constructor = aClass.getConstructor(String.class, int.class);

//使用构造方法构造对象
Person p1 = constructor.newInstance("张三", 10);

3.5 属性

 Person aClass = Person.class;
 Person p1 = new Person();

 //获取指定属性
 Field field = aClass.getDeclaredField("name");
 
 //破坏属性 private,protected 等权限设置
 field.setAccessible(true);
 
 //获取 p1 对象的属性值
 System.out.println( field.get(p1) );

 //个 p1 对象的属性赋值
 field.set(p1, "李四");

 System.out.println(field.get(p1));

 Field num = aClass.getDeclaredField("num");

 //获取静态属性 num 的值
 System.out.println(num.get(null));
 num.set(null,10);
 
//静态属性值获取同样可以通过对象,也可以用 null
 System.out.println(num.get(null));
 System.out.println(num.get(p1));
 num.set(person,20);

 //静态属性值设置可以通过 null 来表示,也可以通过对象
 System.out.println(num.get(null));
 System.out.println(num.get(p1));
  • getDeclaredFields() 和 getFields() 区别在于,getDeclaredFields() 可以无视 private 等权限设置获取属性,getFields() 只能获取 publice 权限的属性。构造方法,方法和属性都是这个规律。

  • 如果通过 getDeclaredFields() 获取到的属性,需要通过 field.setAccessible(true) 将权限破坏,否则可能在使用的时候抛出权限异常。

  • 静态属性操作可以用 null 表示,通过某个实例也是可以的。

3.6 方法

//获取所有方法
aClass.getMethods();

//获取指定方法,第一个参数是方法名,第二个参数列表类型 Class ...
Method method = aClass.getMethod("run", String.class);

//执行方法,第一个参数对象,第二个参数列表
method.invoke(p1, "北京");

Method staticMethod = aClass.getMethod("staticMethod");

//执行静态方法
staticMethod.invoke(null);

//静态方法也可以通过实例来执行
staticMethod.invoke(p1);

3.7 获取注解

//获取指定类型注解。方法/属性等也有此操作,不再赘述。
Deprecated annotation = aClass.getAnnotation(Deprecated.class);

3.8 判断是否数组

Class aClass = Person.class;
getClass().isArray();

3.9 获取类加载器

aClass.getClassLoader()

3.10 获取父类

Class<?> superclass = aClass.getSuperclass();
posted @ 2024-02-19 10:37  primaryC  阅读(11)  评论(0编辑  收藏  举报