Java笔记(27):反射
Posted 花醉红尘
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java笔记(27):反射相关的知识,希望对你有一定的参考价值。
1、获取class文件对象的三种方式
1 package cn.itcast_01; 2 3 public class Person { 4 private String name; 5 int age; 6 public String address; 7 8 public Person() { 9 } 10 11 private Person(String name) { 12 this.name = name; 13 } 14 15 Person(String name, int age) { 16 this.name = name; 17 this.age = age; 18 } 19 20 public Person(String name, int age, String address) { 21 this.name = name; 22 this.age = age; 23 this.address = address; 24 } 25 26 public void show() { 27 System.out.println("show"); 28 } 29 30 public void method(String s) { 31 System.out.println("method " + s); 32 } 33 34 public String getString(String s, int i) { 35 return s + "---" + i; 36 } 37 38 private void function() { 39 System.out.println("function"); 40 } 41 42 @Override 43 public String toString() { 44 return "Person [name=" + name + ", age=" + age + ", address=" + address 45 + "]"; 46 } 47 48 }
1 package cn.itcast_01; 2 3 /* 4 * 反射:就是通过class文件对象,去使用该文件中的成员变量,构造方法,成员方法。 5 * 6 * Person p = new Person(); 7 * p.使用 8 * 9 * 要想这样使用,首先你必须得到class文件对象,其实也就是得到Class类的对象。 10 * Class类: 11 * 成员变量 Field 12 * 构造方法 Constructor 13 * 成员方法 Method 14 * 15 * 获取class文件对象的方式: 16 * A:Object类的getClass()方法 17 * B:数据类型的静态属性class 18 * C:Class类中的静态方法 19 * public static Class forName(String className) 20 * 21 * 一般我们到底使用谁呢? 22 * A:自己玩 任选一种,第二种比较方便 23 * B:开发 第三种 24 * 为什么呢?因为第三种是一个字符串,而不是一个具体的类名。这样我们就可以把这样的字符串配置到配置文件中。 25 */ 26 public class ReflectDemo { 27 public static void main(String[] args) throws ClassNotFoundException { 28 // 方式1 29 Person p = new Person(); 30 Class c = p.getClass(); 31 32 Person p2 = new Person(); 33 Class c2 = p2.getClass(); 34 35 System.out.println(p == p2);// false 36 System.out.println(c == c2);// true 37 38 // 方式2 39 Class c3 = Person.class; 40 // int.class; 41 // String.class; 42 System.out.println(c == c3); 43 44 // 方式3 45 // ClassNotFoundException 46 Class c4 = Class.forName("cn.itcast_01.Person"); 47 System.out.println(c == c4); 48 } 49 }
2、通过反射获取无参构造方法并使用
1 package cn.itcast_02; 2 3 import java.lang.reflect.Constructor; 4 5 import cn.itcast_01.Person; 6 7 /* 8 * 通过反射获取构造方法并使用。 9 */ 10 public class ReflectDemo { 11 public static void main(String[] args) throws Exception { 12 // 获取字节码文件对象 13 Class c = Class.forName("cn.itcast_01.Person"); 14 15 // 获取构造方法 16 // public Constructor[] getConstructors():所有公共构造方法 17 // public Constructor[] getDeclaredConstructors():所有构造方法 18 // Constructor[] cons = c.getDeclaredConstructors(); 19 // for (Constructor con : cons) { 20 // System.out.println(con); 21 // } 22 23 // 获取单个构造方法 24 // public Constructor<T> getConstructor(Class<?>... parameterTypes) 25 // 参数表示的是:你要获取的构造方法的构造参数个数及数据类型的class字节码文件对象 26 Constructor con = c.getConstructor();// 返回的是构造方法对象 27 28 // Person p = new Person(); 29 // System.out.println(p); 30 // public T newInstance(Object... initargs) 31 // 使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。 32 Object obj = con.newInstance(); 33 System.out.println(obj); 34 35 // Person p = (Person)obj; 36 // p.show(); 37 } 38 }
3、通过反射获取带参构造方法并使用
1 package cn.itcast_02; 2 3 import java.lang.reflect.Constructor; 4 5 /* 6 * 需求:通过反射去获取该构造方法并使用: 7 * public Person(String name, int age, String address) 8 * 9 * Person p = new Person("林青霞",27,"北京"); 10 * System.out.println(p); 11 */ 12 public class ReflectDemo2 { 13 public static void main(String[] args) throws Exception { 14 // 获取字节码文件对象 15 Class c = Class.forName("cn.itcast_01.Person"); 16 17 // 获取带参构造方法对象 18 // public Constructor<T> getConstructor(Class<?>... parameterTypes) 19 Constructor con = c.getConstructor(String.class, int.class, 20 String.class); 21 22 // 通过带参构造方法对象创建对象 23 // public T newInstance(Object... initargs) 24 Object obj = con.newInstance("林青霞", 27, "北京"); 25 26 System.out.println(obj); 27 } 28 }
4、通过反射获取私有构造方法并使用
1 package cn.itcast_02; 2 3 import java.lang.reflect.Constructor; 4 5 /* 6 * 需求:通过反射获取私有构造方法并使用 7 * private Person(String name){} 8 * 9 * Person p = new Person("风清扬"); 10 * System.out.println(p); 11 */ 12 public class ReflectDemo3 { 13 public static void main(String[] args) throws Exception { 14 // 获取字节码文件对象 15 Class c = Class.forName("cn.itcast_01.Person"); 16 17 // 获取私有构造方法对象 18 // NoSuchMethodException:每个这个方法异常 19 // 原因是一开始我们使用的方法只能获取公共的,下面这种方式就可以了。 20 Constructor con = c.getDeclaredConstructor(String.class); 21 22 // 用该私有构造方法创建对象 23 // IllegalAccessException:非法的访问异常。 24 // 暴力访问 25 con.setAccessible(true);// 值为true则指示反射的对象在使用时应该取消Java语言访问检查。 26 Object obj = con.newInstance("风清扬"); 27 28 System.out.println(obj); 29 } 30 }
5、通过反射获取成员变量并使用
1 package cn.itcast_03; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Field; 5 6 /* 7 * 通过发生获取成员变量并使用 8 */ 9 public class ReflectDemo { 10 public static void main(String[] args) throws Exception { 11 // 获取字节码文件对象 12 Class c = Class.forName("cn.itcast_01.Person"); 13 14 // 获取所有的成员变量 15 // Field[] fields = c.getFields(); 16 // Field[] fields = c.getDeclaredFields(); 17 // for (Field field : fields) { 18 // System.out.println(field); 19 // } 20 21 /* 22 * Person p = new Person(); p.address = "北京"; System.out.println(p); 23 */ 24 25 // 通过无参构造方法创建对象 26 Constructor con = c.getConstructor(); 27 Object obj = con.newInstance(); 28 System.out.println(obj); 29 30 // 获取单个的成员变量 31 // 获取address并对其赋值 32 Field addressField = c.getField("address"); 33 // public void set(Object obj,Object value) 34 // 将指定对象变量上此 Field 对象表示的字段设置为指定的新值。 35 addressField.set(obj, "北京"); // 给obj对象的addressField字段设置值为"北京" 36 System.out.println(obj); 37 38 // 获取name并对其赋值 39 // NoSuchFieldException 40 Field nameField = c.getDeclaredField("name"); 41 // IllegalAccessException 42 nameField.setAccessible(true); 43 nameField.set(obj, "林青霞"); 44 System.out.println(obj); 45 46 // 获取age并对其赋值 47 Field ageField = c.getDeclaredField("age"); 48 ageField.setAccessible(true); 49 ageField.set(obj, 27); 50 System.out.println(obj); 51 } 52 }
6、通过反射获取成员方法并使用
1 package cn.itcast_04; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5 6 public class ReflectDemo { 7 public static void main(String[] args) throws Exception { 8 // 获取字节码文件对象 9 Class c = Class.forName("cn.itcast_01.Person"); 10 11 // 获取所有的方法 12 // Method[] methods = c.getMethods(); // 获取自己的包括父亲的公共方法 13 // Method[] methods = c.getDeclaredMethods(); // 获取自己的所有的方法 14 // for (Method method : methods) { 15 // System.out.println(method); 16 // } 17 18 Constructor con = c.getConstructor(); 19 Object obj = con.newInstance(); 20 21 /* 22 * Person p = new Person(); p.show(); 23 */ 24 25 // 获取单个方法并使用 26 // public void show() 27 // public Method getMethod(String name,Class<?>... parameterTypes) 28 // 第一个参数表示的方法名,第二个参数表示的是方法的参数的class类型 29 Method m1 = c.getMethod("show"); 30 // obj.m1(); // 错误 31 // public Object invoke(Object obj,Object... args) 32 // 返回值是Object接收,第一个参数表示对象是谁,第二参数表示调用该方法的实际参数 33 m1.invoke(obj); // 调用obj对象的m1方法 34 35 System.out.println("----------"); 36 // public void method(String s) 37 Method m2 = c.getMethod("method", String.class); 38 m2.invoke(obj, "hello"); 39 System.out.println("----------"); 40 41 // public String getString(String s, int i) 42 Method m3 = c.getMethod("getString", String.class, int.class); 43 Object objString = m3.invoke(obj, "hello", 100); 44 System.out.println(objString); 45 // String s = (String)m3.invoke(obj, "hello",100); 46 // System.out.println(s); 47 System.out.println("----------"); 48 49 // private void function() 50 Method m4 = c.getDeclaredMethod("function"); 51 m4.setAccessible(true); 52 m4.invoke(obj); 53 } 54 }
7、通过反射运行配置文件内容
配置文件class.txt的内容:
className=cn.itcast.test.Student
methodName=love
1 package cn.itcast.test; 2 3 public class Student { 4 public void love() { 5 System.out.println("爱生活,爱烨儿"); 6 } 7 }
1 package cn.itcast.test; 2 3 public class Teacher { 4 public void love() { 5 System.out.println("爱生活,爱青霞"); 6 } 7 }
1 package cn.itcast.test; 2 3 public class Worker { 4 public void love() { 5 System.out.println("爱生活,爱娘子"); 6 } 7 }
1 package cn.itcast.test; 2 3 import java.io.FileReader; 4 import java.lang.reflect.Constructor; 5 import java.lang.reflect.Method; 6 import java.util.Properties; 7 8 /* 9 * 通过配置文件运行类中的方法 10 * 11 * 反射: 12 * 需要有配置文件配合使用。 13 * 用class.txt代替。 14 * 并且你知道有两个键。 15 * className 16 * methodName 17 */ 18 public class Test { 19 public static void main(String[] args) throws Exception { 20 // 反射前的做法 21 // Student s = new Student(); 22 // s.love(); 23 // Teacher t = new Teacher(); 24 // t.love(); 25 // Worker w = new Worker(); 26 // w.love(); 27 // 反射后的做法 28 29 // 加载键值对数据 30 Properties prop = new Properties(); 31 FileReader fr = new FileReader("class.txt"); 32 prop.load(fr); 33 fr.close(); 34 35 // 获取数据 36 String className = prop.getProperty("className"); 37 String methodName = prop.getProperty("methodName"); 38 39 // 反射 40 Class c = Class.forName(className); 41 42 Constructor con = c.getConstructor(); 43 Object obj = con.newInstance(); 44 45 // 调用方法 46 Method m = c.getMethod(methodName); 47 m.invoke(obj); 48 } 49 }
8、通过反射越过泛型检查
1 package cn.itcast.test; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 import java.util.ArrayList; 6 7 /* 8 * 我给你ArrayList<Integer>的一个对象,我想在这个集合中添加一个字符串数据,如何实现呢? 9 */ 10 public class ArrayListDemo { 11 public static void main(String[] args) throws NoSuchMethodException, 12 SecurityException, IllegalAccessException, 13 IllegalArgumentException, InvocationTargetException { 14 // 创建集合对象 15 ArrayList<Integer> array = new ArrayList<Integer>(); 16 17 // array.add("hello"); 18 // array.add(10); 19 20 Class c = array.getClass(); // 集合ArrayList的class文件对象 21 Method m = c.getMethod("add", Object.class); 22 23 m.invoke(array, "hello"); // 调用array的add方法,传入的值是hello 24 m.invoke(array, "world"); 25 m.invoke(array, "java"); 26 27 System.out.println(array); 28 } 29 }
9、通过反射写一个通用的设置某个对象的某个属性为指定的值
1 package cn.itcast.test; 2 3 public class ToolDemo { 4 public static void main(String[] args) throws NoSuchFieldException, 5 SecurityException, IllegalArgumentException, IllegalAccessException { 6 Person p = new Person(); 7 Tool t = new Tool(); 8 t.setProperty(p, "name", "林青霞"); 9 t.setProperty(p, "age", 27); 10 System.out.println(p); 11 System.out.println("-----------"); 12 13 Dog d = new Dog(); 14 15 t.setProperty(d, "sex", ‘男‘); 16 t.setProperty(d, "price", 12.34f); 17 18 System.out.println(d); 19 } 20 } 21 22 class Dog { 23 char sex; 24 float price; 25 26 @Override 27 public String toString() { 28 return sex + "---" + price; 29 } 30 } 31 32 class Person { 33 private String name; 34 public int age; 35 36 @Override 37 public String toString() { 38 return name + "---" + age; 39 } 40 }
10、动态代理的概述和实现
1 package cn.itcast_06; 2 3 import java.lang.reflect.InvocationHandler; 4 import java.lang.reflect.Method; 5 6 public class MyInvocationHandler implements InvocationHandler { 7 private Object target; // 目标对象 8 9 public MyInvocationHandler(Object target) { 10 this.target = target; 11 } 12 13 @Override 14 public Object invoke(Object proxy, Method method, Object[] args) 15 throws Throwable { 16 System.out.println("权限校验"); 17 Object result = method.invoke(target, args); 18 System.out.println("日志记录"); 19 return result; // 返回的是代理对象 20 } 21 }
1 package cn.itcast_06; 2 3 /* 4 * 用户操作接口 5 */ 6 public interface UserDao { 7 public abstract void add(); 8 9 public abstract void delete(); 10 11 public abstract void update(); 12 13 public abstract void find(); 14 }
1 package cn.itcast_06; 2 3 public class UserDaoImpl implements UserDao { 4 5 @Override 6 public void add() { 7 System.out.println("添加功能"); 8 } 9 10 @Override 11 public void delete() { 12 System.out.println("删除功能"); 13 } 14 15 @Override 16 public void update() { 17 System.out.println("修改功能"); 18 } 19 20 @Override 21 public void find() { 22 System.out.println("查找功能"); 23 } 24 25 }
1 package cn.itcast_06; 2 3 import java.lang.reflect.Proxy; 4 5 public class Test { 6 public static void main(String[] args) { 7 UserDao ud = new UserDaoImpl(); 8 ud.add(); 9 ud.delete(); 10 ud.update(); 11 ud.find(); 12 System.out.println("-----------"); 13 // 我们要创建一个动态代理对象 14 // Proxy类中有一个方法可以创建动态代理对象 15 // public static Object newProxyInstance(ClassLoader loader,Class<?>[] 16 // interfaces,InvocationHandler h) 17 // 我准备对ud对象做一个代理对象 18 MyInvocationHandler handler = new MyInvocationHandler(ud); 19 UserDao proxy = (UserDao) Proxy.newProxyInstance(ud.getClass() 20 .getClassLoader(), ud.getClass().getInterfaces(), handler); 21 proxy.add(); 22 proxy.delete(); 23 proxy.update(); 24 proxy.find(); 25 // System.out.println("-----------"); 26 // 27 // StudentDao sd = new StudentDaoImpl(); 28 // MyInvocationHandler handler2 = new MyInvocationHandler(sd); 29 // StudentDao proxy2 = (StudentDao) Proxy.newProxyInstance(sd.getClass() 30 // .getClassLoader(), sd.getClass().getInterfaces(), handler2); 31 // proxy2.login(); 32 // proxy2.regist(); 33 } 34 }
以上是关于Java笔记(27):反射的主要内容,如果未能解决你的问题,请参考以下文章