Java的反射机制

一、如何获得Class对象

类是对象,类是java.lang.Class类的实例对象
任何一个类都是Class的实例对象,这个实例对象的表示方式
三种表示方式
1.Class c1 = 类名.Class;
2.Class c2 = 对象.getClass();
3.Class c3= Class.forName(“类路径”);
c1、c2、c3我们称为该类的类类型。
对于第一种方法和第二种方法都是直接根据类来取得该类的Class对象,相比之下,第二种方式有如下两种优势。
(1)代码更安全。程序在编译阶段就可以检查需要访问的Class对象是否存在。
(2)程序性能更好。因为这种方式无须调用方法,所以性能更好。
一旦获得了某个类所对应的Class对象之后,程序就可以调用Class对象的方法来获得该对象和该类的真实信息了。
注意:
一个类只可能是Class类的一个实例对象
Class.forName(“类的全称”)
不仅表示了类的类类型,还代表了动态加载类
1) 在面向对象的世界里,万事万物皆对象。(java语言中,静态的成员、普通数据类型除外)
类是不是对象呢?类是(哪个类的对象呢?)谁的对象呢?
类是对象,类是java.lang.Class类的实例对象
2)这个对象到底如何表示
3 )Class.forName(“类的全称”)
不仅表示了,类的类类型,还代表了动态加载类
请大家区分编译、运行
编译时刻加载类是静态加载类、运行时刻加载类是动态加载类
4)基本的数据类型
void关键字 都存在类类型
5)为什么使用反射?
问题:程序在运行时接收外部传入的一个对象,该对象的编译类型是Object,但程序又需要调用该对象运行时类型的方法。
方法:编译时根本无法预知该对象和类可能属于哪些类,程序只依靠运行时信息来发现该对象和类的真实信息,这就必须是反射。

二、成员方法的反射

1)如何获取某个方法
方法的名称和方法的参数列表才能唯一决定某个方法。
获得 Class的对象时,可调用它的getMethod()的方法(指定Class的某个方法)或getMethods()(返回Class的所有方法)
2)方法反射的操作( 方法的签名)
method.invoke(Object obj,Object…args)
参数obj:Class对象
参数args:方法参数
3)通过Class,Method来认识泛型的本质

public class Person {
    private String name;
    private int age;
    public Person(){
        System.out.println("构造函数");
    }
    private String sleep(String name) {
        System.out.println(name+"睡觉了");
        return name;
    }
    public String toString() {
        return "Person[name:" + name + ",age:" + age + "]";
    }
}

//输出类中所有方法的基本信息
public static void printMethodMsg(Object obj) {
        Class<?> clazz = obj.getClass();
        Method[] methods = clazz.getMethods();
        for (int i = 0; i < methods.length; i++) {
            // 方法的名称
            System.out.println("方法的名称:" + methods[i].getName());
            // 返回值的类型
            Class<?> returnType = methods[i].getReturnType();
            System.out.println("返回值的类型:" + returnType.getName());
            // 参数的类型
            Class<?>[] paramTypes = methods[i].getParameterTypes();
            for (Class c1 : paramTypes) {
                System.out.println("参数的类型:" + c1.getName());
            }
        }
    }
//调用类中的指定方法
public class MethodTest {

    public static void main(String[] args) {
        Person p= new Person ();
        Class<?> clazz = p.getClass();
        Method m = null;
        try {
        //参数一:方法的名称  参数二:参数类型
            m = clazz.getDeclaredMethod("sleep",String.class);
            // 通过反射访问一个类的私有方法需要设置权限
            m.setAccessible(true);
            String name=(String)m.invoke(p,"张三");
            System.out.println(name);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

}

补充:java8新增的方法参数反射
int getParameterCount():获取该构造器或方法的形参个数。
Parameter[] getParameters():获取该构造器或方法的所有形参。
每个Parameter对象代表方法或构造器的一个参数。Parameter也提供大量方法来获取声明该参数的泛型信息,还提供如下常用方法来获取参数信息。
getModifiers():获取修饰该形参的修饰符。
String getName():获取形参名。
Type getParameterizedType():获取带泛型的形参类型。
Class< ? > getType():获取形参类型。
boolean isNamePresent():该方法返回该类的class文件中是否包含了方法的形参名信息。
boolean isVarArgs():该方法用于判断该参数是否为个数可变的形参。

class Test {
    public void replace(final String str, List<String> list) {
    }
}

public class MethodParameterTest {
    public static void main(String[] args) throws NoSuchMethodException,
            SecurityException {
        Class<?> clazz = Test.class;
        Method replace = clazz.getMethod("replace", String.class, List.class);
        // 获取形参的个数
        System.out.println("replace方法形参的个数:" + replace.getParameterCount());
        // 获取replace所有的形参信息
        Parameter[] parameters = replace.getParameters();

        for (Parameter p : parameters) {
            if (p.isNamePresent()) {
                System.out.println("形参名:" + p.getName());
                System.out.println("形参类型:" + p.getType());
                System.out.println("泛型类型:" + p.getParameterizedType());
                System.out.println("形参修饰符:" + p.getModifiers());
            } else {
                System.out.println("默认生成的class文件不包含方法形参名的信息");
            }
        }

    }
}

三、成员变量的反射

通过Class对象的getFields()或getField()方法可以获取全部成员变量h或指定成员变量。
读取或设置成员变量:
getXxx(Object obj):获取Obj对象的该成员变量的值。此处的Xxx对应8种基本类型。如果该成员变量的类型是引用类型,则取消get后面的Xxx。
setXxx(Object obj,Xxx val):将obj对象的该成员变量设置成val值。此处的Xxx对应8种基本类型,如果该成员变量的类型是引用类型,则取消set后面的Xxx

//输出成员变量的基本信息
public static void printFieldMsg(Object obj) {
        Class<?> clazz = obj.getClass();
        Field[] fields = clazz.getDeclaredFields();
        for (Field f : fields) {
            // 得到成员变量的类型的类类型
            Class<?> fieldType = f.getType();
            // 成员变量的类型名称
            System.out.println("成员变量的类型名称" + fieldType.getName());
            // 成员变量的名称
            System.out.println("成员变量的名称:" + f.getName());
        }
    }
//获取指定的成员变量。
public class FieldTest {

    public static void main(String[] args) throws Exception, SecurityException {
        Person p = new Person();
        // 获取Person类对应的class对象
        Class<Person> personClazz = Person.class;
        // 获取Person的名为name的Field
        // 使用getDeclaredField,表明可获取各种访问控制符d field
        Field nameField = personClazz.getDeclaredField("name");
        // 设置通过反射访问该Field时取消访问权限检测
        nameField.setAccessible(true);
        // 调用set方法为p对象的name Field设置值
        nameField.set(p, "tom");
        Field ageField = personClazz.getDeclaredField("age");
        // 设置通过反射访问该Field时取消访问权限检测
        ageField.setAccessible(true);
        ageField.setInt(p, 30);
        System.out.println(p);
    }

}

四、构造函数的反射

//构造函数的基本信息
public static void printConstruct(Object obj) {
        Class<?> clazz = obj.getClass();
        Constructor<?>[] cons = clazz.getConstructors();
        for (Constructor<?> con : cons) {
            System.out.println("构造函数的名称:" + con.getName());
            Class<?>[] paramTypes = con.getParameterTypes();
            for (Class<?> c1 : paramTypes) {
                System.out.println("构造函数的参数类型名称:" + c1.getName());
            }

        }

    }
// 构造函数的调用
        Constructor<?> constructor = null;
        try {
            constructor = clazz.getDeclaredConstructor();
            Person p= (Person ) constructor.newInstance();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

五、getField()和getDeclaredField()的区别

getField()只能访问修饰符为public的变量,
getDeclaredField()都不受访问权限的限制。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值