一.什么是反射
Java反射是指在运行时动态地获取和操作类的信息以及调用对象的方法和属性,而不需要在编译期间知道类名或者其成员变量和方法具体等的信息。
通过Java反射机制,可以实现动态创建对象、调用对象的方法、修改对象的属性值等操作,这为程序的灵活性和扩展性提供了很大的便利。
二.反射的作用
- 动态获取类的信息:JavaEE应用程序通常需要处理大量的类和对象。有时候,我们需要在代码中获取一个类的名字、父类、接口、构造函数列表、方法列表、属性列表等信息。通过反射机制,我们可以在运行时动态地获取这些信息,从而使得程序更加灵活和可扩展。
- 动态创建对象:有时候,我们不知道程序运行时需要创建哪些类的对象。通过反射机制,我们可以在运行时动态地创建对象,并调用它们的方法或修改它们的属性。
- 动态调用方法:JavaEE开发中的许多技术(如Servlet和JSP)都使用了反射机制来动态地调用方法。通过反射机制,我们可以在运行时动态地调用一个对象的方法,而不需要提前知道这个方法的具体名称、参数类型和返回值类型。
- 动态修改属性值:有时候,我们需要在程序运行时动态修改对象的属性值。通过反射机制,我们可以在程序运行时得到一个对象的属性列表,然后像访问和修改普通属性一样来处理它们。
三.类类的作用
- Class 类:Class 类是 Java 反射机制的核心。代表一个类。
- Constructor 类:Constructor 类用于描述 Java 类中的构造函数。表类的构造方法。
- Method 类:Method 类用于描述 Java 类中的方法。代表类的成员方法。
- Field 类:Field 类用于描述 Java 类中的属性。代表类的成员变量(属性)。
- Modifier 类:Modifier 类用于描述 Java 类中修饰符的信息。获取修饰符的名称、值以及与修饰符相关的一些操作。
四.类类的读取
创建一个实体类:
package junlinyi_reflect; /** * 实体类 * @author: 君临沂 * */ public class Student { private String sid; private String sname; public Integer age; static{ System.out.println("加载进jvm中!"); } public Student() { super(); System.out.println("调用无参构造方法创建了一个学生对象"); } public Student(String sid) { super(); this.sid = sid; System.out.println("调用带一个参数的构造方法创建了一个学生对象"); } public Student(String sid, String sname) { super(); this.sid = sid; this.sname = sname; System.out.println("调用带二个参数的构造方法创建了一个学生对象"); } @SuppressWarnings("unused") private Student(Integer age) { System.out.println("调用Student类私有的构造方法创建一个学生对象"); this.age = age; } public String getSid() { return sid; } public void setSid(String sid) { this.sid = sid; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public void hello() { System.out.println("你好!我是" + this.sname); } public void hello(String name) { System.out.println(name + "你好!我是" + this.sname); } @SuppressWarnings("unused") private Integer add(Integer a, Integer b) { return new Integer(a.intValue() + b.intValue()); } }
4.1类对象三种获取方式
- Class.forName(' 完整类名 ')
- 类名.class
- 对象.getClass()
代码如下:
package junlinyi_reflect; /** * 类类的获取方式 * Class.for Name * 类实例.getClass() * 类名.class * @author: 君临沂 * */ public class demo1 { public static void main(String[] args) throws Exception { Student stu = new Student(); //java.lang.Class 类类,应用在jdbc数据库链接中 Class c1 = Class.forName("junlinyi_reflect.Student"); System.out.println(c1); //通用增删改 Class c2 = stu.getClass(); System.out.println(c2); //通用查询 Class c3 = Student.class; System.out.println(c3); } }
结果为:
五.反射实例化
- 调用无参构造器反射实例化
- 调用有一个参数的构造器反射实例化
- 调用有两个参数的构造器反射实例化
- 调用私有的带有一个参数的有参构造器实例化
package junlinyi_reflect; import java.lang.reflect.Constructor; /** * 反射实例化 * 所有实体类,添加了有参构造器,一定记得补无参构造器 * @author: 君临沂 * */ public class demo2 { public static void main(String[] args) throws Exception { //一切反射从类类开始 Student stu = new Student(); // 添加了有参构造器,一定记得补无参构造器 // 调用无参构造器反射实例化 Class c1 = Class.forName("junlinyi_reflect.Student"); Student s1 = (Student) c1.newInstance(); System.out.println(s1); // 调用有一个参数的构造器反射实例化 //parameterTypes:代表了参数的类别 Constructor cr1 = c1.getConstructor(String.class); Student s2 = (Student) cr1.newInstance("one1"); System.out.println(s2); // 调用有两个参数的构造器反射实例化 Constructor cr2 = c1.getConstructor(String.class, String.class); Student s3 = (Student) cr2.newInstance("two2","非常nice"); System.out.println(s3); // 调用私有的带有一个参数的有参构造器实例化 //getConstructor方法只能获取到公有的构造器对象 Constructor cr3 = c1.getDeclaredConstructor(Integer.class); cr3.setAccessible(true);//打开权限 Student s4 = (Student) cr3.newInstance(18);//私有构造器不能直接反射实例化,没有权限 System.out.println(s4); } }
六.反射动态方法调用
- 反射调用无参方法
- 反射调用有参方法
- 反射调用私有的有参方法
package junlinyi_reflect; import java.lang.reflect.Method; /** * 反射动态方法调用 * @author: 君临沂 * */ public class demo3 { public static void main(String[] args) throws Exception { Class c = Student.class; Student stu = (Student) c.newInstance();// 获取方法对象 // 反射调用无参方法,先获取到方法对象 // name:方法名 parameterTypes:调用这个方法要传的参数类型------.getMethod(name, parameterTypes); Method m1 = c.getMethod("hello");// 此处是无参方法,所以parameterTypes处不传 // obj:类实例 args:参数值----.invoke(obj, args); // invoke:方法的返回值 Object invoke = m1.invoke(stu);// 无参,参数值无需传 System.out.println(invoke); //反射调用有参方法 Method m2 = c.getMethod("hello", String.class); Object invoke2 = m2.invoke(stu, "三星大头"); System.out.println(invoke2); // 反射调用私有的有参方法 Method m3 = c.getDeclaredMethod("add",Integer.class,Integer.class); m3.setAccessible(true);//打开权限 Object invoke3 = m3.invoke(stu, 999,998); System.out.println(invoke3); } }
七.反射读写属性
- 通过反射获取对象中的所有属性
- 通过反射修改对象属性值
package junlinyi_reflect; import java.lang.reflect.Field; /** * 反射读写属性 * @author: 君临沂 * */ public class demo4 { public static void main(String[] args) throws Exception{ Class clz = Student.class; Student stu = new Student("three3","nice"); stu.age = 18; //需求: 获取到该学生stu的sid值以及sname值-->获取某一个对象中的所有属性 System.out.println(stu.getSid()); System.out.println(stu.getSname()); System.out.println("**************************"); Field snameField = clz.getDeclaredField("sname"); snameField.setAccessible(true); snameField.set(stu, "大头来了"); //Field:属性对象 Field[] fields = clz.getDeclaredFields(); for (Field f : fields) { f.setAccessible(true); System.out.println(f.getName()+":"+f.get(stu)); } } }