【JAVA反射机制】
一、Class类
Java.lang.Object
|-java.lang.Class<T>
构造方法:无。
常用方法:
|
|
getConstructor |
|
Constructor |
getConstructors |
getDeclaredConstructor |
|
|
getDeclaredConstructors |
getDeclaredField |
|
|
getDeclaredFields |
getDeclaredMethod |
|
|
getDeclaredMethods |
getField |
|
|
getFields |
getMethod |
|
|
getMethods |
newInstance |
二、Constructor
Java.lang.Object
|-java.lang.reflect.AccessibleObject
|-java.lang.reflect.Constructor<T>
- 构造方法:无。
- 常用方法:
newInstance |
|
toString |
三、Field
Java.lang.Object
|-java.lang.reflect.AccessibleObject
|-java.lang.reflect.Field
- 构造方法:无
- 常用方法:
getName |
|
|
set |
还有诸如getInt与setInt等操作基本数据类型的方法。
四、Method
Java.lang.Object
|-java.lang.reflect.AccessibleObject
|-java.lang.reflect.Method
1.构造方法:无
2.常用方法:
|
|
|
|
|
|
|
五、暴力访问
使用方法:Constructor、Field、Method三个类均为AccessibleObject类的子类,AccessibleObject类中有一个方法用于暴力访问类中私有的、受保护的构造方法、成员变量、普通方法。
|
|
|
|
前者为静态方法,用于为一组对象设置可访问标记的方法,后者为非静态方法,用于为特定的对象设置可访问标记的方法。
六、示例:
1 package p09.ReflectDemo.p01.Demo01; 2 3 /** 4 * @author kuangdaoyizhimei 5 * 6 */ 7 public class Person { 8 //两个字段 9 private int age; 10 private String name; 11 public String id; 12 //带参数构造方法 13 public Person(int age, String name) { 14 super(); 15 this.age = age; 16 this.name = name; 17 System.out.println("Person(int age,String name)run"); 18 } 19 //无参构造方法 20 public Person() { 21 super(); 22 System.out.println("Person()run"); 23 } 24 //公有无参数show方法 25 public void show() 26 { 27 System.out.println(name+"-----is show runnig---"+age); 28 } 29 //私有无参数method方法 30 private void method() 31 { 32 System.out.println("method is running"); 33 } 34 //私有带参数set方法 35 private void set(int age,String name) 36 { 37 this.age=age; 38 this.name=name; 39 System.out.println("set function is run,name is "+name+" ,age is "+age); 40 } 41 //公有静态无参数go方法。 42 public static void go() 43 { 44 System.out.println("static go function is running!"); 45 } 46 }
该类封装了一些成员变量和方法。
1 package p09.ReflectDemo.p01.Demo01; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.InvocationTargetException; 5 6 /** 7 * 该类为测试拿到字节码文件中的构造方法。 8 * @author kuangdaoyizhimei 9 * 10 */ 11 public class GetConstructorDemo { 12 13 public static void main(String[] args) throws Exception { 14 getAllConstructors(); 15 getNoneParameterConstructor(); 16 getParameterConstructor(); 17 } 18 19 /** 20 * 使用带参数构造方法创建本类实例 21 * @throws InstantiationException 22 * @throws IllegalAccessException 23 * @throws IllegalArgumentException 24 * @throws InvocationTargetException 25 * @throws NoSuchMethodException 26 * @throws SecurityException 27 * @throws ClassNotFoundException 28 */ 29 private static void getParameterConstructor() throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException, ClassNotFoundException { 30 Class<?> clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 31 Constructor<?> con=clazz.getConstructor(int.class,String.class); 32 Object obj=con.newInstance(24,"张三"); 33 } 34 35 /** 36 * 使用无参构造方法创建本类的实例。 37 * @throws NoSuchMethodException 38 * @throws SecurityException 39 * @throws ClassNotFoundException 40 * @throws InstantiationException 41 * @throws IllegalAccessException 42 * @throws IllegalArgumentException 43 * @throws InvocationTargetException 44 */ 45 private static void getNoneParameterConstructor() throws NoSuchMethodException, SecurityException, ClassNotFoundException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ 46 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 47 Constructor con=clazz.getConstructor(); 48 Object obj=con.newInstance(); 49 } 50 51 /** 52 * 得到字节码文件中定义的所有构造方法 53 * @throws ClassNotFoundException 54 * @throws NoSuchMethodException 55 * @throws SecurityException 56 * @throws InstantiationException 57 * @throws IllegalAccessException 58 * @throws IllegalArgumentException 59 * @throws InvocationTargetException 60 */ 61 private static void getAllConstructors() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 62 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 63 Constructor arr[]=clazz.getConstructors(); 64 for(Constructor con:arr) 65 { 66 System.out.println(con); 67 } 68 } 69 70 }
该类用于演示怎样使用反射机制获取Person.java中的构造方法,并使用获取到的构造方法创建对象(但参数构造方法与不带参数构造方法)。
1 package p09.ReflectDemo.p01.Demo01; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Method; 5 6 /** 7 * 该类用于拿到字节码文件中的字段。 8 * @author kuangdaoyizhimei 9 * 10 */ 11 public class GetFieldsDemo { 12 public static void main(String args[]) throws Exception 13 { 14 // getPublicFields(); 15 // getPublicSpecialField(); 16 // getPrivateSpecialField(); 17 } 18 private static void getPrivateSpecialField() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException { 19 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 20 // Field name=clazz.getField("name"); 21 Field name=clazz.getDeclaredField("name"); 22 name.setAccessible(true);//暴力访问 23 Object obj=clazz.newInstance(); 24 name.set(obj, "张三"); 25 System.out.println(name.get(obj)); 26 } 27 28 private static void getPublicSpecialField() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, InstantiationException { 29 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 30 Field field=clazz.getField("id"); 31 // System.out.println(field); 32 Object obj=clazz.newInstance(); 33 field.set(obj, "12345"); 34 System.out.println(field.get(obj)); 35 } 36 37 private static void getPublicFields() throws ClassNotFoundException { 38 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 39 Field f[]=clazz.getDeclaredFields();//得到所有的字段 40 // Field f[]=clazz.getFields();//得到公有的字段 41 for(Field field :f) 42 { 43 System.out.println(field); 44 } 45 } 46 }
该类用于演示怎样使用反射机制获取Person.java中的字段,并对字段赋值与获取。
1 package p09.ReflectDemo.p01.Demo01; 2 3 import java.lang.reflect.InvocationTargetException; 4 import java.lang.reflect.Method; 5 6 /** 7 * 该类用于测试拿到字节码文件对象中的普通方法 8 * @author kuangdaoyizhimei 9 * 10 */ 11 public class GetMethodsDemo { 12 13 public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 14 // showAllMethods(); 15 // getSpecialMethod(); 16 // getSpecialPrivateParameterMethod(); 17 getPublicStaticMethod(); 18 } 19 20 private static void getPublicStaticMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, InstantiationException { 21 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 22 Method method=clazz.getMethod("go", null); 23 Object obj=clazz.newInstance(); 24 method.invoke(obj, null); 25 } 26 private static void getSpecialPrivateParameterMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 27 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 28 Method method=clazz.getDeclaredMethod("set", int.class,String.class); 29 method.setAccessible(true);//暴力访问,如果不是私有方法,这里可以不使用该语句 30 Object obj=clazz.newInstance(); 31 method.invoke(obj, 23,"张三"); 32 } 33 34 private static void getSpecialMethod() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 35 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 36 Method method=clazz.getMethod("show",null); 37 Object obj=clazz.newInstance(); 38 method.invoke(obj, null); 39 } 40 41 private static void showAllMethods() throws ClassNotFoundException { 42 Class clazz=Class.forName("p09.ReflectDemo.p01.Demo01.Person"); 43 // Method methods[]=clazz.getMethods();//得到所有的公有方法,包括父类的 44 Method methods[]=clazz.getDeclaredMethods();//得到所有本类中的方法 45 for(Method method:methods) 46 { 47 System.out.println(method); 48 } 49 } 50 51 }
该类用于演示怎样使用反射机制获取Person.java中的普通方法,并调用特定的方法(带参数方法与不带参数方法)。
七、实例:模拟电脑运行过程
1 package p10.ReflectDemo.p02.Demo01; 2 3 /** 4 * 模拟主板 5 * 6 * @author kuangdaoyizhimei 7 * 8 */ 9 public class MainBoard { 10 public void run() { 11 System.out.println("主板已经通电,即将运行!"); 12 } 13 14 public void usePCI(PCI pci) { 15 if (pci != null) { 16 pci.open(); 17 pci.close(); 18 } 19 } 20 }
该类用于模拟主板对象。
1 package p10.ReflectDemo.p02.Demo01; 2 3 /** 4 * 模拟接口PCI 5 * @author kuangdaoyizhimei 6 * 7 */ 8 public interface PCI { 9 public void open(); 10 public void close(); 11 }
该接口模拟PCI接口。
1 package p10.ReflectDemo.p02.Demo01; 2 3 import java.io.File; 4 import java.io.FileInputStream; 5 import java.util.Properties; 6 7 /** 8 * 模拟电脑运行 9 * @author kuangdaoyizhimei 10 * 11 */ 12 public class Entry { 13 14 public static void main(String[] args) throws Exception { 15 MainBoard mb=new MainBoard(); 16 mb.run(); 17 18 //这种扩展方法烂透了,应当使用反射技术来完成,可以大大提高扩展性 19 // mb.usePCI(new SoundCard()); 20 21 File file=new File("pci.conf"); 22 FileInputStream fis=new FileInputStream(file); 23 Properties pro=new Properties(); 24 pro.load(fis); 25 if(pro.size()>=4) 26 for(int i=0;i<4;i++) 27 { 28 String pciname=pro.getProperty("pci"+(i+1)); 29 if(pciname.equals("")) 30 continue; 31 Class<?> clazz=Class.forName(pciname); 32 PCI pci=(PCI)clazz.newInstance(); 33 mb.usePCI(pci); 34 } 35 fis.close(); 36 } 37 }
该类模拟电脑运行过程。
1 pci1=p10.ReflectDemo.p02.Demo01.SoundCard 2 pci2= 3 pci3= 4 pci4=
该配置文件用于模拟给主板插上扩展硬件,如声卡、显卡等,默认有声卡
运行结果为:
如果想要添加一个显卡,则只需要改变配置文件为:
1 pci1=p10.ReflectDemo.p02.Demo01.SoundCard 2 pci2=p10.ReflectDemo.p02.Demo01.DisplayCard 3 pci3= 4 pci4=
同时需要在p10.ReflectDemo.p02.Demo01包下创建DisplayCard.java文件,该类实现了PCI接口。
1 package p10.ReflectDemo.p02.Demo01; 2 3 public class DisplayCard implements PCI { 4 5 @Override 6 public void open() { 7 System.out.println("显卡已经打开!"); 8 } 9 10 @Override 11 public void close() { 12 System.out.println("显卡已经关闭!"); 13 } 14 15 }
这样,就可以将该显卡安装到了主板上,电脑运行时就可以正常使用该显卡了。
运行结果是:
八、总结。
接口+配置文件是软件开发中非常有用的开发方式,使用这种开发范式可以极大扩展软件功能而不需要修改源代码。