目录
反射是java被视为动态语言的关键,反射机制允许程序在执行期间借助于反射API获取任何类的内部信息,并且能够直接操纵任意对象的内部属性和方法(精髓:先获取后操纵)
反射本质:一个对象在创建时会加载该类的信息到方法区,在堆中产生一个该类的字节码对象(一个类只有一个字节码对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子可以看到类的结构,所以我们形象的称之为反射

对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪个接口。对于每个类而言,JRE都为其保留一个不变的Class类型对象。一个Class对象包含了特定的某个结构(class/interface/enum/annotation/primitive type/void/[])的有关信息
注意:

- //通过包名与类名获得
- Class aClass = Class.forName("包名.类名");
- //通过对象获得
- Class aClass = 具体对象.getClass();
- //通过类名获得
- Class aClass = 类名.class;
- //基本内置类型包装类的Type属性
- Class aClass = Integer.Type;
- Class
- Class
c2 = Comparable.class;//接口 - Class
c3 = String[].class;//一维数组 - Class<int[][]> c4 = int[][].class;//二维数组
- Class
c5 = Override.class;//注解 - Class
c6 = ElementType.class;//基本数据类型 - Class
c7 = Integer.class;//基本数据类型 - Class
c8 = void.class;//void - Class
c9 = Class.class;//Class
语法:ClassLoader classloader=字节码对象.getClassLoader()
- Class> c1 = Class.forName("reflact.Test03");
- //获得对应的类加载器
- ClassLoader cl = c1.getClassLoader();
- //获得当前系统类加载器
- ClassLoader cl2 = ClassLoader.getSystemClassLoader();
- //获得系统类加载器的加载路径
- String property = System.getProperty("java.class.path");
语法:Class superclass = 字节码对象.getSuperclass();
- Class
c1 = People.class; - Class super People> superclass = c1.getSuperclass();
- System.out.println(superclass);
语法:Class>[] interfaces = 字节码对象.getInterfaces();
- Class
c1 = People.class; - Class<?>[] interfaces = c1.getInterfaces();
- //获得当前类接口的字节码对象
- for (Class<?> anInterface : interfaces) {
- System.out.println(anInterface);
- }
String getName():获得包名.类名
String getSimpleName():获得类名
- Class
c1 = People.class; - System.out.println("获得包名和类名"+c1.getName());//包名.类名
- System.out.println("获得类的名字"+c1.getSimpleName());//类名
Field[] getFields():获得字节码对象对应类包括其父类的所有public属性
Field[] getDeclaredFields():获得字节码对象对应类的所有修饰符的所有属性
Field getField(String name):获得字节码对象对应类或父类的名字为name的public属性,如果当前类和父类都有该属性,那么就获取当前类的属性
Field getDeclaredField(String name):获得字节码对象对应类的名字为name的属性
- Class
c1 = People.class; - Field[] fields = c1.getFields();//只能获取public属性,也包括静态的和父类的
- for (Field field : fields) {
- System.out.println(field);
- }
- System.out.println("------------");
- Field[] fields1 = c1.getDeclaredFields();//可以获取全部属性,只能获取当前类的
- for (Field field : fields1) {
- System.out.println(field);
- }
- System.out.println("------------");
- //获取本类及父类public的名叫name的属性
- Field name = c1.getField("money");//public java.lang.String reflact.People.name
- System.out.println(name);
- //暴力获取本类private的名叫age的属性
- Field age = c1.getDeclaredField("age");
- System.out.println(age);
Method[] getMethods():获取对应类及对应父类的所有public方法
Method[] getDeclaredMethods():获取本类的所有方法
Method getMethod(String name,[类型.class,类型.class]):获得本类或父类对应方法名为name,参数类型为对应类型的public方法
Method getDeclaredMethod(String name):获取本类的名为name没有参数的方法
- Class
c1 = People.class; - //获取类及父类的public修饰的所有方法
- Method[] methods = c1.getMethods();
- for (Method method : methods) {
- System.out.println(method);
- }
- System.out.println("--------------");
- //获取本类的所有方法
- Method[] methods1 = c1.getDeclaredMethods();
- for (Method method : methods1) {
- System.out.println(method);
- }
- System.out.println("--------------");
- //获取当前类或父类中的eat中有2个int类型参数的被public修饰的方法
- Method eat = c1.getMethod("eat", int.class, int.class);
- System.out.println(eat);
- //获得本类的无参方法say
- Method say = c1.getDeclaredMethod("say");
- System.out.println(say);
Constructor[] getConstructors():获得本类所有被public修饰的构造器
Constructor[] getDeclaredConstructors():获得本类的所有构造器
Constructor getConstructor():获得本类被public修饰的的空参构造器
Constructor getDeclaredConstructor([类型.class,类型.class]):获得本类对应参数类型的构造器
注意:普通反射之所以可以获取父类中的资源,主要是因为其在父类中继承了该资源,而构造器是不能被继承的,所以普通反射中不可以获取父类的构造器
- Class
c1 = People.class; - //获得所有的本类被public修饰的构造方法
- Constructor>[] constructors = c1.getConstructors();
- for (Constructor> constructor : constructors) {
- System.out.println(constructor);
- }
- System.out.println("----------------");
- //获得本类的所有构造器
- Constructor>[] constructors1 = c1.getDeclaredConstructors();
- for (Constructor> constructor : constructors1) {
- System.out.println(constructor);
- }
- System.out.println("----------------");
- //获得本类被public修饰的空参构造器
- Constructor
constructor = c1.getConstructor(); - System.out.println(constructor);
- //获得本类的被private修饰的有参构造器
- Constructor
constructor1 = c1.getDeclaredConstructor(String.class, int.class, String.class); - System.out.println(constructor1);
语法:属性.setAccessible(true)——默认为false
注意:如果要操纵权限的私有属性(或者本身不可达的属性),那么就必须关闭权限检测
语法:People people = 字节码对象.newInstance();
注意:此种创建对象方式不能获取本类的被private修饰(其他修饰的可以,但是无参构造器创建方式不可以)的无参构造器所创建的对象
- Class
c1 = People.class; - People people = c1.newInstance();
- System.out.println(people);
语法:
- People people = 无参构造器.newInstance();
- People people = 有参构造器.newInstance(对应有参构造器类型的参数值列表);
注意:如果获取的构造器是私有的,那么你想创建对象需要关闭权限检测
- Class
c1 = People.class; - //获取本类被public修饰的无参构造
- Constructor
constructor = c1.getConstructor(); - //通过无参构造创建无参对象
- People people = constructor.newInstance();
- System.out.println(people);
- //获取本类的被private修饰的有参构造
- Constructor
constructor1 = c1.getDeclaredConstructor(String.class, int.class, String.class); - //给与有参构造修改的权限
- constructor1.setAccessible(true);
- //通过有参构造创建有参对象
- People people1 = constructor1.newInstance("nana", 18, "女");
- System.out.println(people1);
语法:获取到的方法.invoke(方法所在的对象,[方法参数列表])——返回值为null
注意:在调用私有方法前需要关闭权限检测
- Class
c1 = People.class; - //因为我有非private无参构造
- People people = c1.newInstance();
- System.out.println(people);
- //普通方法调用
- people.eat(2,3);
- Method eat = c1.getMethod("eat", int.class, int.class);
- //不用设置权限
- eat.invoke(people,1,1);
- //获取私有方法
- Method say = c1.getDeclaredMethod("say");
- say.setAccessible(true);
- //调用私有方法,因为该方法为无参方法,如果有参,后面需加参数列表
- say.invoke(people,null);
获取属性值:Object o = 获取到的属性.get(属性所在的对象);
设置属性值:获取到的属性.set(属性所在的对象, 你要设置的属性值);
注意:在获取或设置属性时,需要关闭权限检测
- Class
c1 = People.class; - People people = c1.newInstance();
- //直接获取非私有属性
- System.out.println(people.name);
- //设置非私有属性
- people.name="lan";
- System.out.println(people.name);
- //获取私有属性对象
- Field age = c1.getDeclaredField("age");
- //关闭权限检测
- age.setAccessible(true);
- Object o = age.get(people);
- System.out.println(o);
- //为私有属性age赋值
- age.set(people, 23);
- System.out.println(age.get(people));
总结:普通方法执行>关闭权限检测执行>不关闭权限检测执行
获取方法所有的参数类型及泛型信息
语法:Type[] types = 获得到的方法.getGenericParameterTypes();
获取泛型中的真实类型
语法:Type[] at = 参数化类型泛型.getActualTypeArguments();
- public class Test05 {
- private void test1(Map<String,People> map, List
list ){ - System.out.println("test1");
- }
- public static void main(String[] args) throws NoSuchMethodException {
- Class<Test05> c = Test05.class;
- //获取方法,因为本类
- Method test1 = c.getDeclaredMethod("test1", Map.class, List.class);
- //通过方法来获得参数类型集
- Type[] types = test1.getGenericParameterTypes();
- for (Type type : types) {
- System.out.println(type);//java.util.Map
,java.util.List - //判断泛型的类型是否属于参数化类型
- if (type instanceof ParameterizedType){
- //获得他们真实类型
- Type[] at = ((ParameterizedType) type).getActualTypeArguments();
- for (Type type1 : at) {
- System.out.println(type1);
- }
- }
- }
- }
- }
语法:Type returnType = 获得的方法.getGenericReturnType();
- public class Test05 {
- public Map<String,People> test2(){
- System.out.println("test2");
- return null;
- }
- public static void main(String[] args) throws NoSuchMethodException {
- Class<Test05> c = Test05.class;
- //获取方法,因为本类
- Method test2 = c.getMethod("test2");
- //获得泛型返回值类型信息
- Type returnType = test2.getGenericReturnType();
- //是否返回值类型属于参数化类型
- if (returnType instanceof ParameterizedType){
- //获取参数化类型的真实类型
- Type[] at = ((ParameterizedType) returnType).getActualTypeArguments();
- for (Type type : at) {
- System.out.println(type);
- }
- }
- }
- }
语法:Annotation[] annotations = 字节码对象.getAnnotations();
语法:Sign annotation = 字节码对象.getAnnotation(Sign.class);
获取指定注解的值:String value = 获得到的注解.注解属性名();
- Class> c = Class.forName("reflact.Childern");
- //获得该类上的所有注解
- Annotation[] annotations = c.getAnnotations();
- for (Annotation annotation : annotations) {
- System.out.println(annotation);
- }
- //获得该类上的指定注解
- Sign annotation = c.getAnnotation(Sign.class);
- //获取注解的值
- String value = annotation.value();
- System.out.println(value);
以FieldSign为例——字段上的特定注解名
语法:FieldSign annotation = 获得到的字段.getAnnotation(FieldSign.class);
- Class> c = Class.forName("reflact.Childern");
- //获取字段属性
- Field name = c.getDeclaredField("name");
- //在字段中获取注解
- FieldSign annotation = name.getAnnotation(FieldSign.class);
- //以下三个为我在注解内定义的3个属性
- System.out.println(annotation.column());
- System.out.println(annotation.length());
- System.out.println(annotation.type());
以MethodSign为例——方法上的特定注解名
语法:MethodSign annotation = 获得到的方法.getAnnotation(MethodSign.class);
- Class> c = Class.forName("reflact.Childern");
- //获取方法
- Method eat = c.getDeclaredMethod("eat");
- //获得方法上的注解
- MethodSign annotation = eat.getAnnotation(MethodSign.class);
- //通过注解获取里面的值
- String spot = annotation.spot();
- System.out.println(spot);
- @Sign("db_Children")
- class Childern{
- @FieldSign(column = "db_id",type = "int",length = 10)
- private int id;
- @FieldSign(column = "db_age",type = "int",length = 10)
- private int age;
- @FieldSign(column = "db_name",type = "varchar",length = 3)
- private String name;
- @MethodSign(spot = "db_spot")
- private void eat(){
- System.out.println("干饭");
- }
-
- }
-
- @Target(ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- @interface Sign{
- String value();
- }
-
- @Target(ElementType.FIELD)
- @Retention(RetentionPolicy.RUNTIME)
- @interface FieldSign{
- String column();
- String type();
- int length();
- }
- @Target(ElementType.METHOD)
- @Retention(RetentionPolicy.RUNTIME)
- @interface MethodSign{
- String spot();
- }