首页 > 技术文章 > JAVA-反射

DQGonoes 2021-12-16 15:58 原文

1.获取Class对象的方式

1.源文件阶段(引入了一个.class文件但是没有加载过)

//1.源文件阶段要获取Class对象
        Class aClass = Class.forName("java_20211216.User");

2.Class对象阶段(.class文件通过类加载器加载过了)

//2.Class对象阶段获取Class对象
        Class<User> userClass = User.class;

3.在对象运行阶段获取Class对象

//3.在对象运行阶段获取Class对象
        User u1 = new User();
        Class<? extends User> aClass1 = u1.getClass();

2.Class对象API

(1)获取字段对象

获取所有字段的方法:

1.得到类的所有public字段
Field[] getFields() 

2. 返回类中所有的字段,包括:私、保、默、公
Field[] getDeclaredFields()   

获取指定字段的方法:

1.获取某个"公有的"字段:
public Field getField(String fieldName);

2.获取某个字段(可以是私有的) 
public Field getDeclaredField(String fieldName)

++ Field对象API

(1)获取字段的数据类型和修饰符

Field age = aClass1.getDeclaredField("age");

        Class type = age.getType();//放回字段类型的Class对象

        Type genericType = age.getGenericType();//对象从新封装成一个描述对象
        String typeName = genericType.getTypeName();//=》java.lang.String

/**
         * 如果只有一个修饰符返回单个修饰符的int值
         * 如果多个则返回相加的值
         */
        int modifiers = age.getModifiers();
//0:default 1:public 2:private  4:protected 8:static 16:final

(2)得到对象的属性值:get方法

User u1 = new User();
        u1.name = "123";

        User u2 = new User();
        u2.name = "456";

        Class<? extends User> aClass1 = u1.getClass();

        Field name = aClass1.getDeclaredField("name");

        String o = (String)name.get(u2);

        System.out.println(o);

(3)给对象的属性赋值:set方法(对象的引用,要赋值的数值,不能给static修饰的类变量赋值)

User u1 = new User();
        u1.name = "123";

        User u2 = new User();
        u2.name = "456";

        Class<? extends User> aClass1 = u1.getClass();

        Field age = aClass1.getDeclaredField("age");

        age.setAccessible(true);//不管访问权限,或者是否是常量都能修改值
	//如果给私有变量或者访问权限不够的变量以及final变量赋值不设置此选项就会抛出java.lang.IllegalArgumentException异常

        age.set(u2,123);

        System.out.println(u2.getAge());

(4)常见问题:

set(Object obj, Object value) 时,新value和原value的类型不一致导致,如下:无法转换类型导致的 java.lang.IllegalArgumentException(注意:反射获取或者修改一个变量的值时,编译器不会进行自动装/拆箱,所以int 和Integer需手动修改)
    
set(Object obj, Object value) 时,修改 final类型的变量导致的 IllegalAccessException。由于 Field 继承自 AccessibleObject , 我们可以使用 AccessibleObject.setAccessible() 方法告诉安全机制,这个变量可以访问即可解决,如field.setAccessible(true)。
    
getField(String name) 或getFields() 获取非 public 的变量,编译器会报 java.lang.NoSuchFieldException 错。

(2)获取构造器对象

 //1.获取所有public修饰的构造器
        Constructor[] constructors = userClass.getConstructors();

        //2.获取所有构造器(私有、公共、默认)
        Constructor[] declaredConstructors = userClass.getDeclaredConstructors();

        //3.获取某个公共构造器(通过参数列表类型判断)
        Constructor constructor = userClass.getConstructor(String.class);

        //4.获取某个(私有、公共、默认)构造器(通过参数列表类型判断)
        Constructor constructor2 = userClass.getDeclaredConstructor(String.class);

++Constructor 对象API

(1)获取构造器对象所在的类的Class对象

Constructor constructor2 = userClass.getDeclaredConstructor(String.class);

        Class declaringClass = constructor2.getDeclaringClass();

(2)获取构造器的修饰符

int getModifiers()
    //0:default 1:public 2:private  4:protected 

(3)以字符串形式返回Constructor对象所表示得构造方法的名称。

String getName() 

(4)返回由Constructor对象所表示的构造方法的形参类型对应Class对象组成的数组此

Class[] parameterTypes = constructor2.getParameterTypes();

        System.out.println(Arrays.toString(parameterTypes));

(5)调用构造器对象创建对象方法 (newInstance)

Class<Math> mathClass = Math.class;

        Constructor<Math> constructor = mathClass.getDeclaredConstructor();

        constructor.setAccessible(true);

        Math math = constructor.newInstance();

        System.out.println(math);

(3)获取成员方法对象

1.批量的:
public Method[] getMethods(): 获取所有"公有方法";(包含了父类的方法也包含Object类)
public Method[] getDeclaredMethods():获取所有的成员方法,包括私有的(不包括继承的)

    2.获取单个的:
public Method getMethod(String name,Class<?>... parameterTypes):
参数:
name : 方法名;
Class ... : 形参的Class类型对象
public Method getDeclaredMethod(String name,Class<?>... parameterTypes)


 Method aa = userClass.getDeclaredMethod("aa", String.class, int.class);

++Method对象常用API

(1)调用方法invoke(无返回值情况)

Class userClass = User.class;

        Method aa = userClass.getDeclaredMethod("aa", String.class, int.class);

        aa.setAccessible(true);

        User u1 = new User();

        aa.invoke(u1, "高靖博", 12);

(2)调用方法invoke(有返回值情况)

Object cc = aa.invoke(u1, "高靖博", 12);

        System.out.println(cc);

(3)获取方法的修饰符、返回值类型、参数列表、抛出异常类型

Class userClass = User.class;

        Method cc = userClass.getDeclaredMethod("aa",String.class,int.class);

        int modifiers = cc.getModifiers();//方法的修饰符:
//0:default 1:public 2:private  4:protected 8:static 16:final 1024:abstract  32:synchronized

        Class [] parameterTypes = cc.getParameterTypes();//获取方法的参数列表Class对象

        Class returnType = cc.getReturnType();//获取方法的放回值类型Class对象

        Class [] exceptionTypes = cc.getExceptionTypes();//获取方法抛出的异常Class对象

        String name = cc.getName();//获取的只有方法的名称

        String s = cc.toGenericString();

        System.out.println(s);

获取方法名:
 String getName() 
          以 String 形式返回此 Method 对象表示的方法名称。
把方法转成字符串
 String toGenericString() 
          返回描述此 Method 的字符串,包括类型参数。

(4)得到方法描述的Type类型方法

Type[] getGenericParameterTypes() 
          按照声明顺序返回 Type 对象的数组,这些对象描述了此 Method 对象所表示的方法的形参类型的。 
 Type[] getGenericExceptionTypes() 
          返回 Type 对象数组,这些对象描述了声明由此 Method 对象抛出的异常。 
 Type getGenericReturnType() 
          返回表示由此 Method 对象所表示方法的正式返回类型的 Type 对象。

(5)判断的方法

判断方法:
 boolean isBridge() 
          如果此方法是 bridge 方法,则返回 true;否则,返回 false。 
 boolean isSynthetic() 
          如果此方法为复合方法,则返回 true;否则,返回 false。 
 boolean isVarArgs() 
          如果将此方法声明为带有可变数量的参数,则返回 true;否则,返回 false。


推荐阅读