java反射特性学习

反射

1 反射和Class类

反射是什么

反射是通过对象获得一个类的Class对象。
Class对象是类加载时完成后,堆内存的方法区里字节码
的程序表现。
Class对象能够完整包含一个类的结构,包括所有的域,方法。

  • 优点:
    可以实现动态创建对象和编译,体现出很大的灵活性.
  • 缺点:
    对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,
    我们希望做什么并且它满足我们的要求。这类操作总是慢于直接执行相同的操作。

反射相关主要API

java.lang.Class :代表一个类

java.lang.reflect.Method:代表类的方法

java.lang.reflect.Field:代表类的成员变量

java.lang.reflect.Constructor:代表类的构造器

反射的几种获得方法:

  1. 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高。
  2. 已知某个类的实例,调用该实例的getClass()方法获取Class对象
  3. 已知一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException
  4. 基本数据类型的包装类.Type和.class的不同
        //      Class.forName("类路径")方法,此方法Class的泛型不能固定,常写为通配符<?>
        Class<?> c1 = Class.forName("com.reflection.test.ReflectionTest");

//        获得包名+类名
        System.out.println(c1.getName());

//        获得类名
        System.out.println(c1.getSimpleName());

        //        getClass()方法:
        ReflectionTest reflectionTest = new ReflectionTest();
        Class<? extends ReflectionTest> c2 = reflectionTest.getClass();

        //        类名.class方法:
        Class<ReflectionTest> c3 = ReflectionTest.class;

        //        基本数据类型的包装类.Type, 比较以下的不同
        Class<Integer> integerClass1 = Integer.class;   //返回本类型
        Class<Integer> integerClass2 = Integer.TYPE;    //返回包装的类型
        System.out.println("======================");
        System.out.println(integerClass1);
        System.out.println(integerClass2);


//        一个类只能获得一个Class对象:
        System.out.println("======================");
        System.out.println(c1 == c2);
        System.out.println(c2 == c3);

哪些类型可以有Class 对象?

  1. class:外部类,成员(成员内部类,静态内部类),局部内部类,匿名内部类。
  2. interface:接口
  3. [] :数组
  4. enum:枚举
  5. annotation:注解 @interface
  6. primitive type :基本数据类型
  7. void
//        类:
        Class<Object> objectClass = Object.class;
        System.out.println(objectClass);
//        接口:
        Class<?> comparableClass = Comparable.class;
        System.out.println(comparableClass);
//        数组:
        Class<String[]> aClass = String[].class;
        System.out.println(aClass);
//        二维数组:
        Class<String[][]> aClass1 = String[][].class;
        System.out.println(aClass1);
//        枚举:
        Class<ElementType> elementTypeClass = ElementType.class;
        System.out.println(elementTypeClass);
//        注解:
        Class<MyAnnotation> myAnnotationClass = MyAnnotation.class;
        System.out.println(myAnnotationClass);
//        基本数据类型:
        Class<Integer> integerClass = int.class;
        System.out.println(integerClass);
//        void:
        Class<Void> voidClass = void.class;
        System.out.println(voidClass);

2 通过反射获得类的所有结构

通过反射获得类的以下结构

Field、Method、Constructor、Superclass、Interface、Annotation

  1. 实现的全部接口
  2. 所继承的父类
  3. 全部的构造器,包括参数
  4. 全部的方法,包括返回值、参数、泛型
  5. 全部的Field
  6. 注解,包括注解内的值
        StudentTest studentTest = new StudentTest();
        Class<? extends StudentTest> c1 = studentTest.getClass();

//        获得父类
        Class<?> superclass = c1.getSuperclass();
        System.out.println("========================");
        System.out.println("SuperClass:" + superclass.getSimpleName());

//        获得全部的构造器
        Constructor<?>[] constructors = c1.getDeclaredConstructors();
        System.out.println("========================");
        System.out.println("Constructor:");
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor.getName() + ":");
            System.out.println(Arrays.toString(constructor.getParameterTypes()));
        }

//        获得全部的方法
        Method[] methods = c1.getDeclaredMethods();
        System.out.println("========================");
        System.out.println("Methods:");
        for (Method method : methods) {
            System.out.println(method.getName() + ":");
            System.out.println(Arrays.toString(method.getParameterTypes()));
        }

//        获得全部的field
//        定义的所有方法
        Field[] declaredFields = c1.getDeclaredFields();
        System.out.println("========================");
        System.out.println("DeclareFields:");
        for (Field field : declaredFields) {
            System.out.println(field.getName());
        }

//        所有能找到的public方法和父类的方法
        Field[] fields = c1.getFields();
        System.out.println("========================");
        System.out.println("PublicFields+superFields:");
        for (Field field : fields) {
            System.out.println(field.getName());
        }

反射获取注解,ORM练习

Object Relationship Mapping对象关系映射

该性质是数据库建立的基础

  1. 类和表结构对应
  2. 属性和字段对应
  3. 对象和记录对应
        Class<?> classPerson = Class.forName("com.reflection.test.PersonTest");
        System.out.println("========================");
//        获得类的注解
        Annotation[] annotations = classPerson.getAnnotations();
        for (Annotation annotation : annotations) {
            System.out.println("ClassAnnotation:" + annotation);
            System.out.println("注解名:" + annotation.annotationType().getSimpleName());
        }

//        获得注解的值
        MyTable annotation = classPerson.getAnnotation(MyTable.class);  //填写需要的注解的类
        String value = annotation.value();
        System.out.println("MyTable注解的值:" + value);

//        获得类中域的注解
//        获得所有域
        System.out.println("========================");
        System.out.println("获得所有域的注解、和值:");
        Field[] classPersonDeclaredFields = classPerson.getDeclaredFields();

        for (Field classPersonDeclaredField : classPersonDeclaredFields) {
//            取出每个域的注解
            MyField ann = classPersonDeclaredField.getAnnotation(MyField.class);
//            取出注解的值
            String columnName = ann.columnName();
            String type = ann.type();
            int length = ann.length();
            boolean isNull = ann.isNull();
            System.out.println(classPersonDeclaredField.getName() + ":\n"
                    + " columnName:" + columnName
                    + " type:" + type
                    + " length:" + length
                    + " isNull" + isNull);
        }
    }
}

3 使用Class对象创建新实例

使用Class对象创建新实例

  1. 通过Class类的getDeclaredConstructor(Class … parameterTypes)取得本类的指定形参类型的构造器
  2. 向构造器的形参中传递Class对象,里面包含了构造器中所需的各个参数
  3. 通过Constructor实例化对象

public class GetNewInstance03 {
    public static void main(String[] args)
            throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException, NoSuchFieldException {
        Class<?> c1 = Class.forName("com.reflection.test.PersonTest");
        
//        获得指定参数的构造器
        Constructor<?> personConstructor = c1.getDeclaredConstructor(int.class, String.class, String.class);
        
//        已知类名,强转(从Object->PersonTest)高转低,用constructor.newInstance(构造参数)获得新的对象
        PersonTest person = (PersonTest) personConstructor.newInstance(15, "tsh", "student");
        System.out.println(person);

通过反射调用方法、修改私有属性

//        通过反射调用方法、修改私有属性
        Method setName = c1.getDeclaredMethod("setName", String.class);
//        方法调用, methodName.invoke(对象, 参数列表)
        setName.invoke(person, "tsh_test");
        System.out.println(person);

//        设置setAccessible(true);可以访问私用方法、属性。
//        并且效率更高。
        System.out.println("=============================");
        Field age = c1.getDeclaredField("age");
//        设置可访问private
        age.setAccessible(true);
        age.set(person, 50);
        System.out.println(person);
    }
}
posted @ 2021-11-01 13:20  Rabianp  阅读(40)  评论(0)    收藏  举报