前言

Github:https://github.com/HealerJean

博客:http://blog.healerjean.com

一、泛型

1、Class

1.1、获取 Class的几种方法

/**
 * 获取Class
 */
@Test
public void test1() throws ClassNotFoundException {

    Class reflectClass = Class.forName("com.healerjean.proj.reflect.ReflectDTO");

    reflectClass = ReflectDTO.class;

    reflectClass = new ReflectDTO().getClass();
}

1.2、Class.forName

类已加载并且这个类已连接,这是正是class的静态方法forName()完成的工作。

public class ClassMain {

    // 静态的参数初始化  //只会执行一次
    static {
        System.out.println("--静态的参数初始化--");
    }
    // 非静态的参数初始化   //动态 new 或者 newInstance 实例化对象的时候执行,可执行多次
    {
        System.out.println("--非静态的参数初始化--");
    }

    public ClassMain() {
        System.out.println("ClassTest!");
    }

    
    
     public static void main(String[] args) throws ClassNotFoundException {
        //类已加载并且这个类已连接,这是正是class的静态方法forName()完成的工作。
        Class clazz = Class.forName("com.healerjean.proj.reflect._class.ClassMain");
        System.out.println(clazz);

      
    }
   

    // --静态的参数初始化--
    // class com.healerjean.proj.reflect._class.ClassMain

1.3、new Object()class.newInstance()

1、使用newInstance可以解耦。使用newInstance的前提是,类已加载并且这个类已连接,这是正是class的静态方法forName()完成的工作。newInstance实际上是把new 这个方式分解为两步,即,首先调用class的加载方法加载某个类,然后实例化

2、newInstance: 弱类型。低效率。只能调用无参构造。 new Object(): 强类型。相对高效。能调用任何public构造。

public class ClassMain {

    // 静态的参数初始化  //只会执行一次
    static {
        System.out.println("--静态的参数初始化--");
    }
    // 非静态的参数初始化   //动态 new 或者 newInstance 实例化对象的时候执行,可执行多次
    {
        System.out.println("--非静态的参数初始化--");
    }
    public static void main(String[] args) throws Exception {
        // 下面二者的是一样的结果


        // Class.forName("com.healerjean.proj.reflect._class.ClassMain").newInstance();
        // --静态的参数初始化--
        // --非静态的参数初始化--
        // ClassTest!

        new ClassMain();
        // --静态的参数初始化--
        // --非静态的参数初始化--
        // ClassTest!

    }
    
}

1.4、非静态的参数实例化

非静态的参数初始化,动态 new 或者 newInstance 实例化对象的时候执行,可执行多次

 public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
      Class.forName("com.healerjean.proj.reflect._class.ClassMain").newInstance();
      new ClassMain();

      // --静态的参数初始化--
      //  --非静态的参数初始化--
      // ClassTest!
      //  --非静态的参数初始化--
      // ClassTest!
  }

1.5、Java 动态加载类和静态加载类的区别

new 创建对象的方式称作为静态加载

Class.forName("XXX") 称作为动态加载

1.5.1、Java 动态加载类和静态加载类的区别

它们俩本质的区别在于静态加载的类的源程序在编译时期加载(必须存在),而动态加载的类在编译时期可以缺席(源程序不必存在)。

1.5.2、为什么需要动态加载类

动态加载类增加了程序的灵活性。比如一个程序中有50个功能,但你可能只会使用其中的一个,如果你用的是静态加载的方式,你必须在编译前提供100个功能的所有定义,否则无法编译通过,若你使用的是动态加载机制,则不需要如此大费周章,用哪一个就定义哪一个即可

2、Field

2.1、DTO

1、祖父 GrandFatherDTO

@Data
public class GrandFatherDTO {

    private Long privateId;

    private String privateName;

    private String privateGrandVar;

    public Long publicId;

    public String publicName;

    public String publicGrandVar;
}

2、父亲 FatherDTO

@Data
public class FatherDTO extends GrandFatherDTO {

    private Long privateId;

    private String privateName;

    private String privatefatherVar;

    public Long publicId;

    public String publicName;

    public String publicFatherVar;
}

3、ReflectDTO

@Data
public class ReflectDTO extends FatherDTO {

    private Long privateId;

    private String privateName;

    private Integer privateAge;

    private BigDecimal privateMoney;

    private Date privateDate;


    public Long publicid;

    public String publicName;

    public Integer publicAge;

    public BigDecimal publicMoney;

    public Date publicDate;


}

2.1、getFields()getDeclaredFields()

Class<?> demoClass = Class.forName("com.reflect.Demo");  

2.1.1、getFields()

1、能访问类中声明为 public 的字段

2、能访问其它类继承来的 public 的字段

(父亲(包括祖父)和自己内部有同一个字段名,都能获取到),

/** 1、getFields()
 * 1、能访问类中声明为public的字段**
 * 2、能访问其它类继承来的public的字段**
 *(父亲(包括祖父)和自己内部有同一个字段名,都能获取到),**
 */
@Test
public void testGetFields() {
    Class reflectDTOClass = ReflectDTO.class;

    Field[] fields = reflectDTOClass.getFields();
    Arrays.stream(fields).forEach(field -> log.info(field.getName()));

    // publicId
    // publicName
    // publicAge
    // publicMoney
    // publicDate
    // publicId
    // publicName
    // publicFatherVar
    // publicId
    // publicName
    // publicGrandVar
}

2.1.2、getDeclaredFields()

1、能够访问类中所有的字段

2、不能访问其他类继承的字段

/**
 * 1.2、getDeclaredFields :能够访问类中所有的字段,不能方位其他类继承的字段
 */
@Test
public void testGetDeclaredFields() {
    Class reflectDTOClass = ReflectDTO.class;

    Field[] fields = reflectDTOClass.getDeclaredFields();
    Arrays.stream(fields).forEach(field -> log.info(field.getName()));

    // privateId
    // privateName
    // privateAge
    // privateMoney
    // privateDate
    // publicid
    // publicName
    // publicAge
    // publicMoney
    // publicDate
}

2.1.3、通过反射获取一个类包括父类中来的所有的字段

/**
 * 1.3、反射获取该类所有字段属性的值(包括从父类继承来的)
 */
@Test
public void getAllFiled() throws IllegalAccessException {
    ReflectDTO obj = new ReflectDTO();
    obj.setPrivateId(0L);
    obj.setPrivateName("");

    Set<Field> allFields = new HashSet<>();
    Class tempClass = obj.getClass();//这样就获取了这个对象的一些值了
    while (tempClass != null && !tempClass.getName().toLowerCase().equals("java.lang.object")) {
        allFields.addAll(Arrays.asList(tempClass.getDeclaredFields()));
        tempClass = tempClass.getSuperclass();
    }
    Set<String> nameSet = new HashSet<>();
    if (!EmptyUtil.isEmpty(allFields)) {
        for (Field field : allFields) {
            field.setAccessible(true);
            if (nameSet.add(field.getName())) {
                if (!"serialVersionUID".equals(field.getName()) && field.get(obj) != null) {
                    log.info("字段名:【{}】;值:【{}】", field.getName(), field.get(obj));
                }
            }
        }
    }
}

2.2、getField()getDeclaredField()

1、getField() 只能取的共有属性,不能取得私有属性

2、getDeclaredField() 通过暴力反射可以获取私有属性

 /**
* 2、getField() getDeclaredField()
* getField 只能取的共有属性,不能取得私有属性
* getDeclaredField 通过暴力反射可以获取私有属性
*/
@Test
public void test4() throws NoSuchFieldException, IllegalAccessException {
    ReflectDTO obj = new ReflectDTO();
    obj.setPrivateName("privateName_VALUE");
    obj.setPublicName("publicName_VALUE");

    Field publicFieldName = obj.getClass().getField("publicName");
    log.info("getField获取公有属性:【{}】", publicFieldName.get(obj));//publicName_VALUE

    Field privateFieldName = obj.getClass().getDeclaredField("privateName");
    //提示有,但是取不出来,报错,所以下面加上暴力反射可以获取 java.lang.IllegalAccessException: Class com.healerjean.proj.reflect.field.D01_FieldMain can not access a member of class com.healerjean.proj.reflect.ReflectDTO with modifiers "private"
    privateFieldName.setAccessible(true);
    log.info("getDeclaredField获取私有属性:【{}】", privateFieldName.get(obj));//privateName_VALUE


    // Field fieldName = obj.getClass().getField("privateName");
    // 下面抛出异常getField 不能获取私有属性 java.lang.NoSuchFieldException: privateName
    // log.info("getField获取私有属性:【{}】", fieldName.get(obj));

}


2.3、getType()getGenericType()

如果属性是一个泛型,从 getType()只能得到这个属性的接口类型。但从 getGenericType()还能得到这个泛型的参数类型,所以一般情况下使用 getGenericType

1、 getType(): 返回 class类型

2、getGenericType() : 返回 Type 类型

/**
 * 4、获取字段类型
 * getType(): 获取属性声明时类型对象(返回class对象)
 * getGenericType() : 返回属性声的Type类型
 * 如果属性是一个泛型,从getType()只能得到这个属性的接口类型。但从getGenericType()还能得到这个泛型的参数类型。
 * 所以一般情况下使用 getGenericType
 */
@Test
public void getType() throws NoSuchFieldException {
  ReflectDTO obj = new ReflectDTO();

  Field nameField = obj.getClass().getField("publicName");
  log.info("String类型:getType :" + nameField.getType().toString());//class java.lang.String
  log.info("String类型:getGenericType :" + nameField.getGenericType().toString());//class java.lang.String

  Field dataField = obj.getClass().getField("publicDate");
  log.info("Date类型:getType :" + dataField.getType());//:class java.util.Date
  log.info("Date类型:getGenericType :" + dataField.getGenericType());//class java.util.Date


  Field listFile = obj.getClass().getField("list");
  log.info("List类型:getType :" + listFile.getType().toString());//interface java.util.List
  log.info("List类型:getGenericType :" + 
           listFile.getGenericType().toString());//java.util.List<java.lang.String>

}


String类型getType :class java.lang.String 
String类型getGenericType :class java.lang.String 
Date类型getType :class java.util.Date 
Date类型getGenericType :class java.util.Date
List类型getType :interface java.util.List
List类型getGenericType :java.util.List<java.lang.String> 

2.4、其他基本方法

2.4.1、 field.getName() 获取属性名

2.4.2、 field.get(obj) 获取属性的值


public class Point {  
  
    private int x;  
    public int y;  
    public Point(int x, int y) {  
        super();  
        this.x = x;  
        this.y = y;  
    }  
      
}


Point p = new Point(3,5);         
Field fieldY = p.getClass().getField("y"); 
System.out.println(fieldY.get(pt1)); // 5  

2.4.3、field.set(obj, value);

2.5、给利用 Field 反射给对象赋值


/**
 * 4、给对象赋值
 */
@Test
public void setValue() {
    ReflectDTO obj = new ReflectDTO();
    Field[] fields = obj.getClass().getDeclaredFields();
    Map<String, String> map = new HashMap<>();
    map.put("publicName", "publicName_value");
    map.put("privateName", "privateName_value");
    Set<String> fieldNames = map.keySet();
    for (String fieldName : fieldNames) {
        for (Field field : fields) {
            if (field.getName().equals(fieldName)) {
                setFieldValue(field, obj, map.get(fieldName));
            }
        }
    }
    log.info("obj:{}", obj);
}

/**
 * 为属性赋值
 *
 * @param field 要赋值的属性
 * @param obj   属性所属对象
 * @param value 值
 */
private void setFieldValue(Field field, Object obj, String value) {
    try {
        if (field == null || obj == null || value == null || "".equals(value)) {
            return;
        }
        field.setAccessible(true);

        String fieldType = field.getGenericType().toString();
        if ("class java.lang.String".equals(fieldType)) {
            field.set(obj, value);
        }
        if ("class java.lang.Integer".equals(fieldType)) {
            Integer val = Integer.valueOf(value);
            field.set(obj, val);
        }
        if ("class java.math.BigDecimal".equals(fieldType)) {
            BigDecimal bde = new BigDecimal(value);
            field.set(obj, bde);
        }
        if ("class java.util.Date".equals(fieldType)) {
            SimpleDateFormat df = new SimpleDateFormat("yyyyMMdd");
            Date date = df.parse(value);
            field.set(obj, date);
        }
    } catch (Exception ex) {
        log.error("对象赋值失败", ex);
        throw new BusinessException("处理失败");
    }

}

3、Constructor

public class ConstructorPerson {
	String str ;

	public String getStr() {
		return str;
	}

	public void setStr(String str) {
		this.str = str;
	}

	public ConstructorPerson() {

		System.out.println("无参构造器");

	}

	public ConstructorPerson(String str) {
		System.out.println("有参 String str 构造器");
 		this.str = str;
	}
    
	/**
	 * 私有构造函数
	 */
	private ConstructorPerson(String str1,int n) {
		System.out.println("有参 私有构造器");
 		this.str = str1;
	}
	
}

3.1、 无参构造器

//反射构造函数:public Person()   无参构造器 
public static void test1() throws Exception{  
        
      Class clazz = Class.forName("com.hlj.reflex.ConstructorPerson");  
       Constructor c = clazz.getConstructor();   
    //  Constructor c = clazz.getConstructor(null);  //一样
      
      System.out.println(c);   //打印 public com.hlj.reflex.ConstructorPerson() 
  
  }  

3.2、有参构造器

//反射构造函数:public Person(String name)  
public static void test2() throws Exception{  

    Class clazz = Class.forName("com.hlj.reflex.ConstructorPerson");  
    Constructor c = clazz.getConstructor(String.class);  
    System.out.println(c);   
    ConstructorPerson person = (ConstructorPerson)c.newInstance("测试成功"); 

    System.out.println(person.str); 
}  

/打印 
public com.hlj.reflex.ConstructorPerson(java.lang.String)
有参 String str 构造器 
测试成功  

3.3、私有构造器,暴力反射

  //反射私有的构造函数:private Person(String  str1 ,int n )  
  public static void test3() throws Exception{  
      Class clazz = Class.forName("com.hlj.reflex.ConstructorPerson");  
      Constructor c = clazz.getDeclaredConstructor(String.class,int.class);  
      c.setAccessible(true);//暴力反射  
       
      ConstructorPerson p = (ConstructorPerson) c.newInstance("私有构造器",2);  
        
      System.out.println(p.str);  
  }  

4、Method

public class MethodPerson {
   private String name;//名字
   private String type;//类型
   private int camp;//0,近卫;1,天灾
   public MethodPerson(){}
   public MethodPerson(String name, String type, int camp) {
       super();
       this.name = name;
       this.type = type;
       this.camp = camp;
   }
 
   @Override
   public String toString() {
       return "MethodPerson [\n name=" + name + ", \n type=" + type + ", \n camp=" + camp + "\n]";
   }
    
}

4.1、获取全部的公开的方法

private static void getMethods() {
Class<?> methodPersonClass = MethodPerson.class;
  Method[] methods = methodPersonClass.getMethods();
  for (Method method : methods) {
      System.out.println(method);
      System.out.println(method.getName());
  }
}

4.2、获取某个方法,并执行

private static void getMethodSome() {
  Class<?> methodPersonClass = MethodPerson.class;
  MethodPerson methodPerson = (MethodPerson)methodPersonClass.newInstance();

  Method setNameMethod = methodPersonClass.getMethod("setName",String.class);
  Method getNameMethod = methodPersonClass.getMethod("getName");

  setNameMethod.invoke(methodPerson,"setNameMethod.setName变量");

  System.out.println("调用get方法:"+getNameMethod.invoke(methodPerson));

}

二、工具类

@Slf4j
public final class ReflectUtils {

  /**
   * 反射获取Class字段列表
   *
   * @param clazz Class<?>
   * @return Class字段列表
   */
  public static List<String> getFieldNameList(Class<?> clazz) {
      List<String> fieldNameList = new ArrayList<>();
      getFieldList(clazz).forEach(f -> fieldNameList.add(f.getName()));
      return fieldNameList;
  }

  /**
   * 获取class所有Field对象
   *
   * @param clazz Class
   * @return Field列表
   */
  public static List<Field> getFieldList(Class<?> clazz) {
      List<Field> fieldList = new ArrayList<>();
      while (null != clazz) {
          Field[] fieldArr = clazz.getDeclaredFields();
          fieldList.addAll(Arrays.asList(fieldArr));
          clazz = clazz.getSuperclass();
      }
      return fieldList;
  }
}

ContactAuthor