反射与注解

254 阅读2分钟

获取Class类的实例

a) 若已知具体的类,通过类的class属性获取,该方法最为安全可靠,程序性能最高

Class clazz = Person.class;

b) 若已知某个类的实例,调用该实例的getClass()方法获取Class对象

Class clazz = person.getClass();

c)已知一个类的全类名,且该类在类路径下,可以通过Class的静态方法forName()获取,可能会抛出ClassNotFoundException

Class clazz = Class.forName("com.test.Person");

d) 内置基本数据类型可以直接使用类名.Type

e) 还可以使用ClassLoader我们之后讲解

反射大致使用

public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        Class clazz = Class.forName("org.example.reflection.User");
        Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class,int.class);
        User user = (User)constructor.newInstance("huskyui",18,1);
        System.out.println(user);
        // getMethod 入参是null,并且是public

        Method getName = clazz.getMethod("getName",null);
        System.out.println(getName.invoke(user,null));

        // setName 入参是String类型,但是是private修饰的,我们需要使用declaredMethod(),并且使用setAccessible(true)
        Method method = clazz.getDeclaredMethod("setName", String.class);
        method.setAccessible(true);
        method.invoke(user,"adios");
        System.out.println(user);
        System.out.println(getName.invoke(user,null));
    }

注解

// 元注解 用于修饰注解  在java.lang.annotationb包下注解
@Target 
// 需要传入当前注解的,里面的值有 TYPE(class 用),FIELD(字段),METHOD.....
@Document
// 如果有这个注解,会其注释成为带注释元素的公共API的一部分
@Retention
// 指示注解要保留多长时间,默认是RetentionPolicy.ClASS,一般写是RetentionPolicy.RUNIME
@Inherited
// 

举例

@Target(ElementType.FIELD)
@Retention(value= RetentionPolicy.RUNTIME)
public @interface FieldWang {
    String fieldName();
    String type();
    int length();
    String value() default "hhhh";
}

@Target(value = {ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface TableWang {
    String value();
}

@TableWang("db_user")
public class User {

    @FieldWang(fieldName = "user_name",type = "varchar",length = 10)
    private String name;
    @FieldWang(fieldName = "user_age",type = "int",length=10)
    private int age;
    @FieldWang(fieldName = "user_id",type = "int",length=11)
    private int id;

    public User(String name, int age, int id) {
        this.name = name;
        this.age = age;
        this.id = id;
    }

    @Override
    public String toString() {
        final StringBuilder sb = new StringBuilder("User{");
        sb.append("name='").append(name).append('\'');
        sb.append(", age=").append(age);
        sb.append(", id=").append(id);
        sb.append('}');
        return sb.toString();
    }

    public String getName() {
        return name;
    }

    private void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}


public static void main(String[] args) throws ClassNotFoundException {


        Class clazz = Class.forName("org.example.reflection.User");

        if(clazz.isAnnotationPresent(TableWang.class)){
            TableWang tableWang = (TableWang) clazz.getAnnotation(TableWang.class);
            System.out.println(tableWang.value());
        }


        for (Field field : clazz.getDeclaredFields()) {
            if (field.isAnnotationPresent(FieldWang.class)) {
                FieldWang fieldWang = (FieldWang)field.getAnnotation(FieldWang.class);
                System.out.println(field.getName()+ " "+ fieldWang.fieldName() + " " + fieldWang.type() + " " + fieldWang.length());
            }
        }



 }
// 输出
/**

db_user
name user_name varchar 10
age user_age int 10
id user_id int 11
*/

举例Mybatis中的@Select

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Repeatable(Select.List.class)
public @interface Select {
  /**
   * Returns an SQL for retrieving record(s).
   *
   * @return an SQL for retrieving record(s)
   */
  String[] value();

  /**
   * @return A database id that correspond this statement
   * @since 3.5.5
   */
  String databaseId() default "";

  /**
   * The container annotation for {@link Select}.
   * @author Kazuki Shimizu
   * @since 3.5.5
   */
  @Documented
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.METHOD)
  @interface List {
    Select[] value();
  }

}

@Select("select * from test where id = 1 for update")
Test selectForUpdate();


// 我们来看mybatis中的org.apache.ibatis.builder.annotation.MapperAnnotationBuilder中的方法void parseStatement(Method method)

  void parseStatement(Method method) {
    final Class<?> parameterTypeClass = getParameterType(method);
    final LanguageDriver languageDriver = getLanguageDriver(method);

    getAnnotationWrapper(method, true, statementAnnotationTypes).ifPresent(statementAnnotation -> {
     	// 这里获取到Annotation
        final SqlSource sqlSource = buildSqlSource(statementAnnotation.getAnnotation(), parameterTypeClass, languageDriver, method);
。。。。
        }   
                                                                           
// 我们可以看到annotation.value()方法
    private SqlSource buildSqlSource(Annotation annotation, Class<?> parameterType, LanguageDriver languageDriver,
      Method method) {
    if (annotation instanceof Select) {
      return buildSqlSourceFromStrings(((Select) annotation).value(), parameterType, languageDriver);