什么是反射
动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制
什么时候使用反射
传一个对象
传一个字节码对象
传一个全限类名
优点
1、反射提高了程序的灵活性和扩展性。
2、降低耦合性,提高自适应能力。
3、它允许程序创建和控制任何类的对象,无需提前硬编码目标类。
缺点
1、性能问题:使用反射基本上是一种解释操作,用于字段和方法接入时要远慢于直接代码。因此反射机制主要应用在对灵活性和拓展性要求很高的系统框架上,普通程序不建议使用。
2、使用反射会模糊程序内部逻辑;程序员希望在源代码中看到程序的逻辑,反射却绕过了源代码的技术,因而会带来维护的问题,反射代码比相应的直接代码更复杂。
反射条件
运行状态
实例一
通过反射存放String类型的对象
import java.lang.reflect.Method; import java.util.ArrayList; /** * 通过反射存放String类型的对象 * * @author admin * */ public class Demo4 { public static void main(String[] args) { try { ArrayList<Integer> list = new ArrayList<>(); list.add(1000000); System.err.println(list); // 通过反射获取List集合的字节码对象 Class<?> clazz = Class.forName("java.util.ArrayList"); // 通过反射获取addMethod方法 Method method = clazz.getMethod("add", Object.class); // 通过反射调用method方法 method.invoke(list, "薛栋榕,我的小宝贝"); System.err.println(list); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
[1000000]
[1000000, 薛栋榕,我的小宝贝]
实例二
创建一个对象student
package cn.zbx.test.method; public class Student { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student [age=" + age + ", name=" + name + "]"; } }
方式一:
import java.lang.reflect.Field; public class Demo5 { public static void main(String[] args) { try { // 获取student类的字节码对象 Class<?> clazz = Class.forName("cn.zbx.test.method.Student"); // 1.利用反射创建一个空的对象 Student student = (Student) clazz.newInstance(); // 2.获取字段 Field ageField = clazz.getDeclaredField("age"); Field nameField = clazz.getDeclaredField("name"); // 3.设置私有属性 ageField.setAccessible(true); nameField.setAccessible(true); // 4.给字段设置值 ageField.set(student, 30); nameField.set(student, "jack"); System.out.println(student.toString()); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
Student [age=30, name=jack]
方式二:
import java.lang.reflect.Method; public class Demo6 { public static void main(String[] args) { try { // 获取student类的字节码对象 Class<?> clazz = Class.forName("cn.zbx.test.method.Student"); // 1.利用反射创建一个空的对象 Student student = (Student) clazz.newInstance(); // 2.通过反射获取set方法 Method setAgeMethod = clazz.getMethod("setAge", int.class); Method setNameMethod = clazz.getMethod("setName", String.class); // 3.赋值 setAgeMethod.invoke(student, 100); setNameMethod.invoke(student, "反射获取set方法"); System.out.println(student); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
Student [age=100, name=反射获取set方法]
方式三:
package cn.zbx.test.method; public class Student { public Student(int age, String name) { super(); this.age = age; this.name = name; } private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return "Student [age=" + age + ", name=" + name + "]"; } }
package cn.zbx.test.method; import java.lang.reflect.Constructor; public class Demo7 { public static void main(String[] args) { try { // 获取student的字节码文件 Class<Student> clazz = Student.class; // 获取有参构造 Constructor<Student> constructor = clazz.getConstructor(int.class, String.class); Student newInstance = constructor.newInstance(100, "李四"); // "李四被实例化"); System.out.println(newInstance); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
Student [age=100, name=李四]
创建一个类对象并调用对象的方法
package cn.zbx.test.method; public class Test1 { public void print(String str){ System.out.println("hello---------------"+str); } }
package cn.zbx.test.method; import java.lang.reflect.Method; public class Demo8 { public static void main(String[] args) { try { // 获取TEST1的字节码文件对象 Class<?> clazz = Class.forName("cn.zbx.test.method.Test1"); // 利用反射技术获取对象 Test1 newInstance = (Test1) clazz.newInstance(); // 利用反射技术获取print方法 Method printMethod = clazz.getMethod("print", String.class); // 利用反射调用print方法:printMethod.invoke(obj, args); printMethod.invoke(newInstance, "java工程师__薛文博"); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
hello---------------java工程师__薛文博
实例三
javaBean赋值
定义一个标准的JavaBean,名叫Person,包含属性name、age。
使用反射的方式创建一个实例、调用构造函数初始化name、age,使用反射方式调用setName方法对名称进行设置,
不使用setAge方法直接使用反射方式对age赋值
package cn.zbx.test.method; public class Person { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person(int age, String name) { super(); this.age = age; this.name = name; } @Override public String toString() { return "Person [age=" + age + ", name=" + name + "]"; } }
package cn.zbx.test.method; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Demo11 { public static void main(String[] args) { try { // 1.获取person的字节码文件 Class clazz = Person.class; // 2.利用反射获取有参构造方法 Constructor constructor = clazz.getConstructor(int.class, String.class); // 3.调用构造方法给属性初始化 Person person = (Person) constructor.newInstance(20, "薛文博1"); System.out.println("1--------" + person); // 4.利用反射调用setName()方法对名称初始化 Method setNameMethod = clazz.getMethod("setName", String.class); setNameMethod.invoke(person, "薛文博2"); System.out.println("2--------" + person); // 5.不是使用setAge方法直接反射方式对Age初始化 Field ageField = clazz.getDeclaredField("age"); ageField.setAccessible(true); ageField.set(person, 18); System.out.println("3--------" + person); } catch (Exception e) { e.printStackTrace(); } } }
运行结果:
1--------Person [age=20, name=薛文博1]
2--------Person [age=20, name=薛文博2]
3--------Person [age=18, name=薛文博2]