前言

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

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、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()

  • getField() 只能取的共有属性,不能取得私有属性
  • 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(): 返回class类型
  • getGenericType() : 返回Type类型

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

/**
     * 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

###

DTO (ConstructorPerson)

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

DTO (MethodPerson)

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));

}

ContactAuthor