反射笔记
Java反射机制主要提供以下功能:
● 1.在JVM运行时判断任意一个对象所属的类;
● 2.在JVM运行时构造任意一个类的对象;
● 3.在JVM运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法);
● 4.在JVM运行时调用任意一个对象的方法
● 5.生成动态代理
java.lang.Class类和java.lang.reflect包中的Field、Constructor、Method、Array类。
Class是java反射的起源,对任何想探测的类必须产生一个Class类的对象;Class类的实例表示正在运行的Java应用程序中的类和接口。
Field类提供有关的类和接口的属性,和动态访问权限。(封装反射类的属性)
Constructor类(封装反射类的构造方法);Method类封装反射类的方法;Array类封装静态方法。
反射的核心是JVM在运行时才动态加载类或调用方法/访问属性,它不需要事先(写代码的时候或编译期)知道运行对象是谁。
反射:程序运行时,需要动态的加载一些类,这些类可能之前用不到所以不用加载到jvm,而是在运行时根据需要才加载。例如我们的项目底层数据库使用mysql或者oracle,需要动态加载驱动类,假设 com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection这两个类我们要用,这时候我们的程序就写得比较动态化,通过Class tc =Class.forName(“com.java.dbtest.TestConnection”);通过类的全类名让jvm在服务器中找到并加载这个类,而如果是oracle则传入的参数就变成另一个了。这时候就可以看到反射的好处了,这个动态性就体现出java的特性了!用spring当你配置各种各样的bean时,是以配置文件的形式配置的,你需要用到哪些bean就配哪些,spring容器就会根据你的需求去动态加载。(–某大佬的解释)
获得Class对象:
- Object类中的getClass()方法:
- Class类中的forName()静态方法
- 直接获取某对象的class:
创建实例: - 调用无参的构造方法创建指定名称的类的对象,Class对象的newInstance()方法来创建Class对象对应类的实例。
Class c =Class.forName(“java.util.Date”);
List list=(List)c.newInstance(); - 使用带参构造方法创建指定类的对象,先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。
//1.获取String所对应的Class对象
Class c = String.class;
//2.获取String类带一个String参数的构造器
Constructor constructor = c.getConstructor(String.class);
//3.根据构造器创建实例
Object obj = constructor.newInstance(“23333”);
System.out.println(obj);
调用方法: - getDeclaredMethods()方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
public Method[] getDeclaredMethods() throws SecurityException - getMethods()方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。
public Method[] getMethods() throws SecurityException - getMethod()方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象
public Method getMethod(String name, Class<?>… parameterTypes)
栗子:public static void main(String[] args) {
Class<?> c = methodClass.class;
Object object = c.newInstance();
Method[] methods = c.getMethods();
Method[] declaredMethods = c.getDeclaredMethods();
// 获取methodClass类的add方法
Method method = c.getMethod(“add”, int.class, int.class);
// getMethods()方法获取的所有方法
System.out.println(“getMethods获取的方法:”);
for (Method m : methods)
System.out.println(m);
// getDeclaredMethods()方法获取的所有方法
System.out.println(“getDeclaredMethods获取的方法:”);
for (Method m : declaredMethods)
System.out.println(m);
}
// 调用无参的构造方法创建指定名称的类的对象
public static void main(String[] args) {
Date currentDate = (Date) newInstance("java.util.Date");
System.out.println(currentDate);
}
public static Object newInstance(String className) {
Object obj = null;
// 获取指定名称类的Class对象
obj = Class.forName(className).newInstance();
return obj;
}
// 利用反射使用带参构造方法创建指定类的对象
public static void main(String[] args) {
Class claszz;
claszz = Class.forName("java.util.Date");
// 获取具有指定参数类型的构造方法
Constructor constructor = claszz.getConstructor(long.class);
// 给指定的构造方法传参数,创建对象.
Date date = (Date) constructor.newInstance(123456789000L);
System.out.println(date);
}
package testReflection;
public class ReflectInvokeMethodTest {
// 动态调用指定类的指定方法
public static void main(String[] args) {
Class clazz = Class.forName("testReflection.Product");
// 创建Product对象
Product product = (Product) clazz.newInstance();
// 获取名为setName,带一个string类型参数的成员方法所对应的对象代表
Method method = clazz.getDeclaredMethod("setName", String.class);
// 在product对象上调用setName并传值给他,返回值为空
Object returnValue = method.invoke(product, "java");
System.out.println("返回值" + returnValue);
// 获取名为displayInfo,不带参数的成员方法
Method method2 = clazz.getDeclaredMethod("displayInfo");
// 取消访问检查
method2.setAccessible(true);
// 在Product对象上调用私有的displayInfo方法
method2.invoke(product);//incoke()真正执行
}
}
class Product {
private static long count = 0;
private long id;
private String name = "无名氏";
public Product() {id = ++count;}
public long getId() {return id;}
public void setId(long id) {this.id = id;}
public String getName() {return name;}
public void setName(String name) {
System.out.println("调用setName方法");
this.name = name;
}
private void displayInfo() {
System.out.println(getClass().getName() + "id=" + id + "name=" + name);
}
}
public class ReflectFiledTest {
// 动态获取或设置指定对象的指定成员变量的值
@SuppressWarnings({ "deprecation", "rawtypes" })
public static void main(String[] args) {
Class c = Class.forName("testReflection.Product");
// 使用无参构造方法创建对象
Product prod = (Product) c.newInstance();
// 获取私有属性
Field iField = c.getDeclaredField("id");
iField.setAccessible(true);// 取消本字段的访问检查
// 设置prod对象的iField成员变量的值为100
iField.setLong(prod, 100);
// 获取prod对象的IFiled成员变量的值
System.out.println("id:" + iField.getLong(prod));
Field nameField = c.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(prod, "赵四");
System.out.println("name" + nameField.get(prod));
}
}
public class ReflectArrayTest {
// 反射获取数组信息
public static void main(String[] args) {
int[] iArr = new int[5];
double[] dArr = new double[5];
String[] sArr = new String[5];
// iArr.getClass().getName();先用getComponentType()获取对象;
System.out.println("数组限定名:" + iArr.getClass().getComponentType().getName());
System.out.println("数组限定名:" + dArr.getClass().getComponentType().getName());
System.out.println("数组限定名:" + sArr.getClass().getComponentType().getName());
// 动态创建数组
Class<?> cla1 = Class.forName("java.lang.String");
Object array = Array.newInstance(cla1, 25);
// 加数据
for (int i = 0; i < 5; i++) {
Array.set(array, i, "number:" + i);
}
// 拿数据
System.out.println(Array.get(array, 3));
}
}
由于反射会额外消耗一定的系统资源,因此如果不需要动态地创建一个对象,那么就不需要用反射。
另外,反射调用方法时可以忽略权限检查,因此可能会破坏封装性而导致安全问题。