Java反射机制

来源:互联网 发布:卖家对淘宝差评回复 编辑:程序博客网 时间:2024/06/11 19:58

Java反射机制是在运行状态中,对于任意一个类(class文件),都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取信息以及动态调用对象方法的功能成为java语言的反射机制。

一个经典的例子
tomcat就是实现反射机制的例子。tomcat对外提供了许多接口,就拿HttpServlet来说,我们只需要实现HttpServlet接口,然后让tomcat能够找到我们的实现类,做法是在web.xml文件中对我们的实现类进行配置,

<servlet>    <servlet-name>xxx</servlet-name>    <servlet-class>xxxxx</servlet-class>  </servlet>

然后tomcat就能通过反射机制对我们的实现类进行操作。

对Class的一些方法进行验证
这里写图片描述
wang.properties

pro1=wang

Person.java

package com.wang.reflection;public class Person {    public String sex;    private String name;    private int age;    public Person(){        System.out.println("person run");    }    public Person(String name,int age){        this.name = name;        this.age = age;    }    private Person(String name,int age,String sex){        this.name = name;        this.age = age;        this.sex = sex;    }    public class Student{        String name;        int age;    }    //私有内部类     class Teacher{        String name;        int age;    }    public void show(){        System.out.println(name+":"+age);    }    public void showAge(int age){}}

ReflectTest.java

package com.wang.reflection;import java.io.IOException;import java.io.InputStream;import java.lang.reflect.Constructor;import java.lang.reflect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;import java.util.Properties;import org.junit.Before;import org.junit.Test;public class ReflectTest {    private Class<?> personClass;    @Before    //返回与给定的字符串名称的类或接口相关的类对象。    public void forName() throws ClassNotFoundException, InstantiationException, IllegalAccessException{        personClass = Class.forName("com.wang.reflection.Person");    }    @Test    public void getClasses(){        //返回公共内部类的Class数组        Class<?>[] classes = personClass.getClasses();        for(Class clazz:classes){            System.out.println(clazz.getName());        }        //返回一个包括公共,保护,默认(包)访问和私有类和类中声明的接口的Class数组,但不包括继承的类和接口。        Class<?>[] classes1 = personClass.getDeclaredClasses();        for(Class clazz:classes1){            System.out.println(clazz.getName());        }    }    @Test    public void getContructor() throws NoSuchMethodException, SecurityException{        //获取无参构造方法        Constructor<?> constructor = personClass.getConstructor();        System.out.println(constructor.getName());        //获取带参构造方法        Constructor<?> constructor1 = personClass.getConstructor(String.class,int.class);        System.out.println(constructor1.getName());    }    @Test    //获取类的构造参数,并打印出所有构造函数的参数类型    public void getContructors(){        Constructor<?>[] constructors = personClass.getConstructors();        for(Constructor<?> c:constructors){            Class<?>[] parameterTypes = c.getParameterTypes();            if(parameterTypes.length==0){                System.out.println("无参构造函数");            }else{                System.out.println("构造函数有"+parameterTypes.length+"个参数,分别为:");                for(int i=0;i<parameterTypes.length;++i){                    System.out.println(parameterTypes[i].getName());                }            }            System.out.println("--------------------------------");        }        System.out.println("=======================================================");        //获取所有的构造函数,包括私有的构造函数        Constructor<?>[] constructors1 = personClass.getDeclaredConstructors();        for(Constructor<?> c:constructors1){            Class<?>[] parameterTypes = c.getParameterTypes();            if(parameterTypes.length==0){                System.out.println("无参构造函数");            }else{                System.out.println("构造函数有"+parameterTypes.length+"个参数,分别为:");                for(int i=0;i<parameterTypes.length;++i){                    System.out.println(parameterTypes[i].getName());                }            }            System.out.println("--------------------------------");        }    }    @Test    public void getField() throws NoSuchFieldException, SecurityException{        //只能获取公共成员        //Field field = personClass.getField("age");   //因为是私有成员,如果使用该方法会报错        Field field1 = personClass.getField("sex");        //System.out.println(field.toString());        System.out.println(field1.toString());        System.out.println("===============================");        //获取所有成员        Field field2 = personClass.getDeclaredField("age");        Field field3 = personClass.getDeclaredField("sex");        System.out.println(field2.toString());        System.out.println(field3.toString());    }    @Test    //获取修饰符    public void getModifiers(){        int modifiers = personClass.getModifiers();        String string = Modifier.toString(modifiers);        System.out.println(string);    }    @Test    public void getMethods() throws NoSuchMethodException, SecurityException{        //获取指定方法        Method method = personClass.getMethod("showAge", int.class);        System.out.println(method.getName());        System.out.println("==============================");        //获取所有方法        Method[] methods = personClass.getMethods();        for(Method method1:methods){            System.out.println(method1.getName());        }    }    @Test    public void getPackage(){        System.out.println(personClass.getPackage().getName());    }    @Test    //获取类装载器    public void getClassLoader() throws IOException{        ClassLoader classLoader = personClass.getClassLoader();        InputStream resourceAsStream = classLoader.getResourceAsStream("com/wang/reflection/wang.properties");        Properties properties = new Properties();        properties.load(resourceAsStream);        String property = properties.getProperty("pro1");        System.out.println(property);    }}

最后关于getResource方法和getResourceAsStream方法

首先,Java中的getResourceAsStream有以下几种: 1. Class.getResourceAsStream(String path) : path 不以’/'开头时默认是从此类所在的包下取资源,以’/'开头则是从ClassPath根下获取。其只是通过path构造一个绝对路径,最终还是由ClassLoader获取资源。 2. Class.getClassLoader.getResourceAsStream(String path) :默认则是从ClassPath根下获取,path不能以’/'开头,最终是由ClassLoader获取资源。 3. ServletContext. getResourceAsStream(String path):默认从WebAPP根目录下取资源,Tomcat下path是否以’/'开头无所谓,当然这和具体的容器实现有关。 4. Jsp下的application内置对象就是上面的ServletContext的一种实现。 其次,getResourceAsStream 用法大致有以下几种: 第一: 要加载的文件和.class文件在同一目录下,例如:com.x.y 下有类me.class ,同时有资源文件myfile.xml 那么,应该有如下代码: me.class.getResourceAsStream("myfile.xml"); 第二:在me.class目录的子目录下,例如:com.x.y 下有类me.class ,同时在 com.x.y.file 目录下有资源文件myfile.xml 那么,应该有如下代码: me.class.getResourceAsStream("file/myfile.xml"); 第三:不在me.class目录下,也不在子目录下,例如:com.x.y 下有类me.class ,同时在 com.x.file 目录下有资源文件myfile.xml 那么,应该有如下代码: me.class.getResourceAsStream("/com/x/file/myfile.xml"); 总结一下,可能只是两种写法 第一:前面有 “   / ” “ / ”代表了工程的根目录,例如工程名叫做myproject,“ / ”代表了myproject me.class.getResourceAsStream("/com/x/file/myfile.xml"); 第二:前面没有 “   / ” 代表当前类的目录 me.class.getResourceAsStream("myfile.xml"); me.class.getResourceAsStream("file/myfile.xml"); 
原创粉丝点击