1.通过例子了解Java反射机制
1 package java_reflect; 2 3 public class Person { 4 public String name; 5 private int age; 6 7 8 static{ 9 System.out.println("我是static的静态代码块!!"); 10 } 11 public Person(){} 12 public Person(String name,int age){ 13 this.name=name; 14 this.age=age; 15 } 16 private Person(String name){ 17 this.name=name; 18 } 19 @Override 20 public String toString() { 21 return "Person [name=" + name + ", age=" + age + "]"; 22 } 23 public void eat(){ 24 System.out.println("人在吃饭!"); 25 } 26 private void sleepPrivate(){ 27 System.out.println("我正在睡觉!!!!!"); 28 } 29 30 public boolean action(String name,int age){ 31 32 System.out.println("我是带有参数的方法,通过反射能执行!"); 33 return true; 34 } 35 36 private void playGame(String name,int age){ 37 System.out.println("人在打游戏:"+name+" "+age); 38 } 39 40 }
1 package java_reflect; 2 /** 3 * 获取一个类class文件对象的三种方式: 4 * 1.类名字 5 * 2.对象 6 * 3.class类的静态方法获取 7 * */ 8 public class ReflectDemo { 9 10 public static void main(String[] args) throws ClassNotFoundException { 11 //1.对象获取 12 Person p=new Person(); 13 Class c=p.getClass(); 14 System.out.println(c); 15 16 //2.类名获取 17 //每一个类型,包括基本和引用,都会赋予这个类型一个静态的属性,属性名字class 18 Class c1= Person.class; 19 System.out.println(c1); 20 21 //person这个类的class文件只有一个,虚拟机只会给这个文件创建一个唯一的Class类 22 //所以c1和p的内存地址都是相等的 23 System.out.println(c1==c);//true 24 System.out.println(c1.equals(c));//true 25 26 //3.Class类的静态方法获取forname(字符串的类名) 27 Class c3=Class.forName("java_reflect.Person"); 28 System.out.println(c3); 29 30 //这三个方法拿到的对象都是唯一的一个对象 31 } 32 }
1 package java_reflect; 2 3 import java.lang.reflect.Constructor; 4 5 /** 6 * 通过反射获取class文件中的构造方法,运行构造方法 7 * 运行构造方法,创建对象 8 * 获取class文件对象 9 * 从class文件对象中,获取需要的成员 10 * 11 * Constructor 描述构造方法对象的类 12 * */ 13 public class ReflectDemo2 { 14 15 public static void main(String[] args) throws Exception, NoSuchMethodException { 16 Class c=Class.forName("java_reflect.Person"); 17 //使用Class文件对象,获取类中的构造方法,找到类class,获取构造器 18 //getConstructors()获取class文件对象中的所有公共的构造方法 19 System.out.println("获得共有的所有的构造方法:"); 20 Constructor[] cons= c.getConstructors(); 21 for(Constructor con:cons){ 22 System.out.println(con); 23 /** 24 * public java_reflect.Person() 25 public java_reflect.Person(java.lang.String,int) 26 * */ 27 System.out.println("获取指定的构造方法!"); 28 //空参数的构造方法 29 System.out.println("空参数:"); 30 Constructor conss= c.getConstructor(); 31 System.out.println(conss); 32 //运行空参数的构造方法,newInstence 33 Object objPerson=conss.newInstance(); 34 System.out.println(objPerson); 35 Object obj1=conss.newInstance(); 36 System.out.println(obj1); 37 } 38 } 39 }
1 package java_reflect; 2 /** 3 *关于反射和new:知识点 4 *1.ram和rom 2.对内存和栈内存的区别,以及数据结构的方式,以及存储的到底是什么 5 *3.new 和反射是2中不同的设计方式:关键字;动态开辟一个对象和直接开辟多个对象 6 * 7 * */ 8 import java.lang.reflect.Constructor; 9 10 public class ReflectDemo3 { 11 12 public static void main(String[] args) throws Exception { 13 Class c=Class.forName("java_reflect.Person"); 14 //Class...parameterTypes基本数据类型的Class文件 15 //1.获取带有参数的构造函数的参数列表 16 Constructor con= c.getConstructor(String.class,int.class); 17 System.out.println(con); 18 //2.运行构造方法:initargs(实际参数) 19 Person p=(Person) con.newInstance("haha",35); 20 System.out.println(p); 21 } 22 }
1 package java_reflect; 2 /** 3 * 反射获取构造方法并运行,有快捷的方式 4 * 有前提: 5 * 被反射的类,必须是有空参数构造方法 6 * 构造方法的权限必须是public 7 * */ 8 public class ReflectDemo4 { 9 10 public static void main(String[] args) throws Exception{ 11 Class c=Class.forName("java_reflect.Person"); 12 //Class类中定义了一个方法,newInstance() 13 14 //注意这个Class类中的方法newInstance是不能传递参数的 15 //这样也使得构造方法必须是有一个空参数的构造方法 16 //所以我们在写类的时候如果用到反射,最好也是写上空参数构造器 17 Object obj=c.newInstance(); 18 System.out.println(obj); 19 } 20 }
1 package java_reflect; 2 3 import java.lang.reflect.Constructor; 4 5 /** 6 * 反射获取私有的构造方法运行 7 * 不推荐,破坏了程序的封装性 8 * 9 * 我们可以使用暴力反射,强行打破Java中的类在运行时的权限 10 * */ 11 public class ReflectDemo6 { 12 13 public static void main(String[] args) throws Exception { 14 Class c=Class.forName("java_reflect.Person"); 15 //获得私有的构造器getDeclaredConstructors() 16 Constructor [] cons=c.getDeclaredConstructors(); 17 for(Constructor con:cons){ 18 System.out.println(con); 19 } 20 System.out.println("私有的指定的一个私有构造器!"); 21 Constructor conPrivate=c.getDeclaredConstructor(String.class); 22 System.out.println(conPrivate); 23 // Person p2=(Person)conPrivate.newInstance("李泽博!"); 24 //错误,main中无法访问私有的构造器 25 26 //1.使用暴力反射 27 /** 28 * AccessibleObject 类是 Field、Method 和 Constructor 对象的基类。它提供了将反射的对象标记为在使用时取消默认 Java 语言访问控制检查的能力。 29 * 对于公共成员、默认(打包)访问成员、受保护成员和私有成员, 30 * 在分别使用 Field、Method 或 Constructor 31 * 对象来设置或获取字段、调用方法,或者创建和初始化类的新实例的时候, 32 * 会执行访问检查。 33 * */ 34 Constructor con=c.getDeclaredConstructor(String.class); 35 con.setAccessible(true); 36 //运行私有的构造器!! 37 con.newInstance("李泽博!!!!!!!!!"); 38 } 39 }
1 package java_reflect; 2 3 import java.lang.reflect.Field; 4 5 public class ReflectDemo7 { 6 7 public static void main(String[] args) throws Exception{ 8 Class c=Class.forName("java_reflect.Person"); 9 Object obj=c.newInstance(); 10 //获取成员变量的Clas变量的方法getField class文件中所有公共的成员变量 11 //返回值是Field[] Fiel类描述成员变量对象的类 12 13 //拿的是公有的成员变量 14 System.out.println("拿的是私有的成员变量"); 15 Field[] fields= c.getFields(); 16 for(Field field:fields){ 17 System.out.println(field); 18 } 19 //私有的,公有的一起,也即是声明了的变量 20 System.out.println("私有的 :"); 21 Field [] fiels1=c.getDeclaredFields(); 22 for(Field fiels:fiels1){ 23 System.out.println(fiels); 24 } 25 //获取指定的一个成员变量 26 System.out.println("获取指定的一个成员变量"); 27 Field fieldss=c.getField("name"); 28 System.out.println(fieldss); 29 30 System.out.println("改掉变量值为'王五'"); 31 fieldss.set(obj, "王五!!"); 32 33 System.out.println(obj); 34 //这里如果我们不是用obj,上面创建的对象,那么使用c.newInstance()会使得 35 //你创建了2个对象,使得结果是null,0 36 } 37 }
1 package java_reflect; 2 3 import java.lang.reflect.Method; 4 5 public class ReflectDemo8 { 6 7 public static void main(String[] args) throws Exception { 8 Class c=Class.forName("java_reflect.Person"); 9 Object obj=c.newInstance(); 10 //获取到成员方法 11 //Method []getMethods()获取的是Class文件的所有公共的成员方法,包括继承的 12 //Method是描述成员方法的对象类 13 System.out.println("成员方法:"); 14 Method [] methods= c.getMethods(); 15 for(Method method:methods){ 16 System.out.println(method); 17 } 18 System.out.println("利用反射使用method:"); 19 Method method= c.getMethod("eat"); 20 System.out.println(method); 21 method.invoke(obj); 22 } 23 }
1 package java_reflect; 2 3 import java.lang.reflect.Constructor; 4 import java.lang.reflect.Method; 5 6 public class ReflectDemo9 { 7 8 public static void main(String[] args) throws Exception { 9 Class c=Class.forName("java_reflect.Person"); 10 Object obj=c.newInstance(); 11 12 Method method= c.getMethod("action", String.class,int.class); 13 boolean bool=(Boolean) method.invoke(obj,"李泽博",23); 14 System.out.println(bool); 15 //通过反射获取私有的带参数的方法 16 System.out.println("通过反射获取私有的带参数的方法"); 17 Object obj1=c.newInstance(); 18 Method method1=c.getDeclaredMethod("playGame", String.class,int.class); 19 //在使用反射式,取消Java中权限 20 method1.setAccessible(true); 21 method1.invoke((Person)obj1, "李泽博sdf",23); 22 23 } 24 }
反射进行的泛型擦除:
1 package java_reflect; 2 3 import java.lang.reflect.Method; 4 import java.util.ArrayList; 5 6 /** 7 * 定义集合类,泛型String 8 * 要求向集合中添加Integer类型 9 * 10 * 反射方式,获取 出集合ArrayList类的class文件对象 11 * 通过class文件都对象,通过调用add()方法 12 * 13 *为什么可以使用这种方式:因为在编译器中是没有泛型这种类型的,所以在.class文件对象中可以使用这种方式 14 * */ 15 public class ReflectDemo10 { 16 17 public static void main(String[] args) throws Exception{ 18 ArrayList<String> array=new ArrayList<String>(); 19 array.add("例子莪"); 20 //反射方式进行泛型擦除,在ArrayList源码中其实是一个对象数组,所以可以进行储存各种类型, 21 //但是通过泛型又有了约束 22 Class c=Class.forName("java.util.ArrayList"); 23 Method method= c.getMethod("add",Object.class); 24 System.out.println(method); 25 System.out.println("使用反射技术~运行方法"); 26 27 //Object obj=c.newInstance(); 28 method.invoke(array, 1500); 29 method.invoke(array, 200); 30 System.out.println(array); 31 } 32 }
使用反射可以让代码变得很灵活,比如读取配置文件,只需要修改配置文件的键值对就可以让程序运行不同的类和方法
1 package java_reflect_two; 2 3 public class Person { 4 5 public void eat(){ 6 System.out.println("人在吃饭~"); 7 } 8 }
1 package java_reflect_two; 2 3 public class Student { 4 5 public void study(){ 6 System.out.println("学生在学习!"); 7 } 8 }
1 package java_reflect_two; 2 3 public class Worker { 4 5 public void job(){ 6 System.out.println("上班族在工作!"); 7 } 8 }
1 #className=java_reflect_two.Person 2 #methodName=eat 3 4 #className=java_reflect_two.Student 5 #methodName=study 6 7 className=java_reflect_two.Worker 8 methodName=job
1 package java_reflect_two; 2 3 import java.io.FileReader; 4 import java.lang.reflect.Method; 5 import java.util.Properties; 6 7 /** 8 * 调用Person方法,调用Student,调用Worker中的方法,也就是说 9 * 运行哪个类是不确定的,类不清楚,方法也不清楚。 10 * 11 * 通过配置文件实现此功能,以键值对的形式,写在文本中 12 * 运行那个类,读取配置文集那即可 13 * 实现步骤: 14 * 1.准备配置文件,键值对 15 * 2.IO流读取配置文件 Reader 16 * 3.文件中的价值对存储到集合中:Properties 17 * 4.直接用反射获取指定类的,class文件的对象 18 * 5.获取方法,执行方法 19 */ 20 public class Test { 21 22 public static void main(String args[]) throws Exception{ 23 24 //IO读取配置文件 25 FileReader r=new FileReader("config.properties"); 26 //创建集合对象 27 Properties pro=new Properties(); 28 pro.load(r); 29 r.close(); 30 //通过键获取值 31 32 String className=pro.getProperty("className"); 33 String methodName=pro.getProperty("methodName"); 34 //测试:System.out.println(className+": "+methodName); 35 36 Class c=Class.forName(className); 37 Object obj=c.newInstance(); 38 Method method=c.getMethod(methodName); 39 method.invoke(obj); 40 } 41 }