网站推广活动方案,怎么创立网站 优帮云,大型网站开发的书,网站建设背景怎么设置成文章目录 介绍Class类与instanceof的区别 访问字段调用方法调用构造方法获取继承关系动态代理 介绍
反射reflection#xff0c;是指在程序运行期间可以拿到一个对象的所有信息。 正常情况下获取一个对象信息#xff0c;需要import该类#xff0c;反射可以在对某个实例一无所… 文章目录 介绍Class类与instanceof的区别 访问字段调用方法调用构造方法获取继承关系动态代理 介绍
反射reflection是指在程序运行期间可以拿到一个对象的所有信息。 正常情况下获取一个对象信息需要import该类反射可以在对某个实例一无所知的情况下调用其方法。 Class类
除了基本类型外Java的其他类型全是class除了interface
class由JVM执行过程中动态加载JVM第一次读取到一种class类型时将其加载进内存。
每加载一种classJVM就为其创建一个Class类型的实例并关联起来。Class类型是一个名叫Class的class
public final class Class {private Class() {}
}以String类为例当JVM加载String类时它首先读取String.class文件到内存然后为String类创建一个Class实例并关联起来
Class cls new Class(String);由于JVM为每个加载的class创建了对应的Class实例并在实例中保存了该class的所有信息包括类名、包名、父类、实现的接口、所有方法、字段等因此如果获取了某个Class实例就可以通过这个Class实例获取到该实例对应的class的所有信息。 这种通过Class实例获取class信息的方法称为反射Reflection。
获取class的Class实例
public class reflection {public static void main(String[] args) {
// 1、直接通过一个class的静态变量class获取Class clsString.class;// 2、如果有一个实例变量可以通过该实例提供的getClass()方法获取String sHello;Class cls2s.getClass();// 3、如果知道一个class的完整类名可以通过静态方法Class.forName()获取Class cls3null;try{cls3Class.forName(java.lang.String);}catch (Exception e){System.out.println(e);}System.out.println(cls);System.out.println(cls2);System.out.println(cls3);
//class java.lang.String
//class java.lang.String
//class java.lang.String}
}与instanceof的区别
Class cls1 String.class;String s Hello;
Class cls2 s.getClass();boolean sameClass cls1 cls2; // trueInteger n new Integer(123);boolean b1 n instanceof Integer; // true因为n是Integer类型
boolean b2 n instanceof Number; // true因为n是Number类型的子类boolean b3 n.getClass() Integer.class; // true因为n.getClass()返回Integer.class
boolean b4 n.getClass() Number.class; // false因为Integer.class!Number.class用instanceof不但匹配指定类型还匹配指定类型的子类。而用判断class实例可以精确地判断数据类型但不能作子类型比较。 访问字段
Class类提供了以下几个方法来获取字段
Field getField(name)根据字段名获取某个public的field包括父类Field getDeclaredField(name)根据字段名获取当前类的某个field不包括父类Field[] getFields()获取所有public的field包括父类Field[] getDeclaredFields()获取当前类的所有field不包括父类
一个Field对象包含了一个字段的所有信息
getName()返回字段名称例如“name” private无法访问调用Field.setAccessible(true)的意思是别管这个字段是不是public一律允许访问。 getType()返回字段类型也是一个Class实例例如String.classgetModifiers()返回字段的修饰符它是一个int不同的bit表示不同的含义。
此外setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager那么它会根据规则进行检查有可能阻止setAccessible(true)。
设置字段值 通过Field实例既然可以获取到指定实例的字段值自然也可以设置字段的值。
设置字段值是通过Field.set(Object, Object)实现的其中第一个Object参数是指定的实例第二个Object参数是待修改的值。
调用方法
可以通过Class实例获取所有Method信息。Class类提供了以下几个方法来获取Method
Method getMethod(name, Class…)获取某个public的Method包括父类Method getDeclaredMethod(name, Class…)获取当前类的某个Method不包括父类Method[] getMethods()获取所有public的Method包括父类Method[] getDeclaredMethods()获取当前类的所有Method不包括父类
一个Method对象包含一个方法的所有信息
getName()返回方法名称例如“getScore”getReturnType()返回方法返回值类型也是一个Class实例例如String.classgetParameterTypes()返回方法的参数类型是一个Class数组例如{String.class, int.class}getModifiers()返回方法的修饰符它是一个int不同的bit表示不同的含义。
public class Main {public static void main(String[] args) throws Exception {// String对象:String s Hello world;// 获取String substring(int)方法参数为int:Method m String.class.getMethod(substring, int.class);// 在s对象上调用该方法并获取结果:String r (String) m.invoke(s, 6);// 打印调用结果:System.out.println(r);}
}调用静态方法 如果获取到的Method表示一个静态方法调用静态方法时由于无需指定实例对象所以invoke方法传入的第一个参数永远为null。 调用非public方法 通过Method.setAccessible(true)允许其调用 public class Main {public static void main(String[] args) throws Exception {Person p new Person();Method m p.getClass().getDeclaredMethod(setName, String.class);m.setAccessible(true);m.invoke(p, Bob);System.out.println(p.name);}
}class Person {String name;private void setName(String name) {this.name name;}
}setAccessible(true)可能会失败。如果JVM运行期存在SecurityManager那么它会根据规则进行检查有可能阻止setAccessible(true)。
多态 使用反射调用方法时仍然遵循多态原则即总是调用实际类型的覆写方法如果存在。
调用构造方法
通过Class实例获取Constructor的方法如下
getConstructor(Class…)获取某个public的ConstructorgetDeclaredConstructor(Class…)获取某个ConstructorgetConstructors()获取所有public的ConstructorgetDeclaredConstructors()获取所有Constructor。
public class Main {public static void main(String[] args) throws Exception {// 获取构造方法Integer(int):Constructor cons1 Integer.class.getConstructor(int.class);// 调用构造方法:Integer n1 (Integer) cons1.newInstance(123);System.out.println(n1);// 获取构造方法Integer(String)Constructor cons2 Integer.class.getConstructor(String.class);Integer n2 (Integer) cons2.newInstance(456);System.out.println(n2);}
}获取继承关系
Class getSuperclass()获取父类类型Class[] getInterfaces()获取当前类实现的所有接口。
动态代理
不编写实现类直接在运行期创建某个interface实例
动态代理dynamic proxy机制可以在运行期动态创建某个interface的实例。
正常写法 public interface Hello {void morning(String name);
}public class HelloWorld implements Hello {public void morning(String name) {System.out.println(Good morning, name);}
}Hello hello new HelloWorld();
hello.morning(Bob);动态代理写法 public class Main {public static void main(String[] args) {InvocationHandler handler new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println(method);if (method.getName().equals(morning)) {System.out.println(Good morning, args[0]);}return null;}};Hello hello (Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(), // 传入ClassLoadernew Class[] { Hello.class }, // 传入要实现的接口handler); // 传入处理调用方法的InvocationHandlerhello.morning(Bob);}
}interface Hello {void morning(String name);
}
在运行期动态创建一个interface实例的方法如下
1、定义一个InvocationHandler实例它负责实现接口的方法调用 2、通过Proxy.newProxyInstance()创建interface实例它需要3个参数 - 使用的ClassLoader通常就是接口类的ClassLoader - 需要实现的接口数组至少需要传入一个接口进去 - 用来处理接口方法调用的InvocationHandler实例。 3、将返回的Object强制转型为接口。