1 Class类
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
1.1 获取Class对象的三种方式:
public class Person { private String name; public int age; static{ System.out.println("静态代码块"); } public Person(){ System.out.println("空参构造"); } public Person(String name,int age){ this.name=name; this.age=age; System.out.println("Person(String name,int age)"); } private Person(String name){ this.name=name; System.out.println("Person(String name)"); } public void eat(){ System.out.println("公共空参方法"); } public void sleep(String name){ System.out.println("公共有参方法"); } public void smoke(){ System.out.println("私有空参构造"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } }
public class Demo01 { public static void main(String[] args) throws ClassNotFoundException { //1.通过getClass方法获取, 通过对象获取 Person p=new Person(); Class c1=p.getClass(); System.out.println(c1); //2.通过类名获取 Class c2=Person.class; System.out.println(c2); System.out.println(c1==c2); System.out.println(c1.equals(c2)); //3.通过完整的包名+类名获取 Class c3=Class.forName("com.oracle.demo03.Person"); System.out.println(c3); } }
2 通过反射获取构造方法并使用
在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示。其中,构造方法使用类Constructor表示。可通过Class类中提供的方法获取构造方法:
public class Demo02 { //构造方法 Constructor //成员变量 Field //成员方法 Method public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //反射获取构造方法 //1.获取Person.Class文件对象 Class c=Class.forName("com.oracle.demo03.Person"); //获取所有公共的构造方法(数组) /*Constructor[]cons=c.getConstructors(); //遍历 for(Constructor con:cons){ System.out.println(con); }*/ //获取某个公共构造方法 /*Constructor con1=c.getConstructor(String.class,int.class); System.out.println(con1); //通过构造方法创建对象 Object obj=con1.newInstance("张三",18); System.out.println(obj);*/ //获取所有构造方法数组 /*Constructor[]cons=c.getDeclaredConstructors(); for(Constructor con:cons){ System.out.println(con); }*/ //获取某个私有构造方法 Constructor con=c.getDeclaredConstructor(String.class); //System.out.println(con); //暴力反射 con.setAccessible(true); Object obj=con.newInstance("熊大"); System.out.println(obj); } }
3 通过反射获取成员变量和成员方法并使用
在反射机制中,把类中的成员变量使用类Field表示。可通过Class类中提供的方法获取成员变量:
在反射机制中,把类中的成员方法使用类Method表示。可通过Class类中提供的方法获取成员方法:
public class Demo01 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchMethodException, InstantiationException { //获取字节码文件对象 Class c=Class.forName("com.oracle.demo01.Person"); //获取所有的成员变量 /*Field[]fields=c.getDeclaredFields(); //遍历 for(Field field:fields){ System.out.println(field); }*/ //获取某个成员变量并赋值 /*Field field=c.getDeclaredField("age"); Object obj=new Person(); field.set(obj, 18); System.out.println(obj);*/ //获取所有成员方法 /*Method[]methods=c.getDeclaredMethods(); //遍历 for(Method method:methods){ System.out.println(method); }*/ //获取单个成员方法 Method method=c.getMethod("sleep", String.class); //调用方法 Object obj=c.newInstance(); method.invoke(obj, "张三"); } }
4 反射练习
4.1 泛型擦除
思考,将已存在的ArrayList<Integer>集合中添加一个字符串数据,如何实现呢?
其实程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除。那么,我们可以通过反射技术,来完成向有泛型约束的集合中,添加任意类型的元素
public class Demo02 { public static void main(String[] args) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException { //泛型擦除 ArrayList<Integer>arr=new ArrayList<Integer>(); //获取ArrayList的字节码文件对象 Class c=arr.getClass(); //通过反射的方式获取add方法 Method add=c.getMethod("add", Object.class); add.invoke(arr, "aaa"); System.out.println(arr); } }
4.2 反射配置文件
通过反射配置文件,运行配置文件中指定类的对应方法
读取properties文件中的数据,通过反射技术,来完成Person对象的创建
public class Demo01 { public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { //明确配置文件的路径 FileReader fr=new FileReader("src/com/oracle/demo02/config.properties"); //创建Properties集合 Properties pro=new Properties(); //从配置文件中读取键值对到集合中 pro.load(fr); //从集合中获取完整的包名+类名 String ClassName=pro.getProperty("ClassName"); //获取方法名 String MethodName=pro.getProperty("MethodName"); //通过反射获取字节码文件对象 Class c=Class.forName(ClassName); //创建对象 Object obj=c.newInstance(); //获取方法 Method method=c.getMethod(MethodName); //调用方法 method.invoke(obj); } }