定义
JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。
用途
在日常的第三方应用开发过程中,经常会遇到某个类的某个成员变量、方法或是属性是私有的或是只对系统应用开放,这时候就可以利用Java的反射机制通过反射来获取所需的私有成员或是方法。当然,也不是所有的都适合反射,之前就遇到一个案例,通过反射得到的结果与预期不符。阅读源码发现,经过层层调用后在最终返回结果的地方对应用的权限进行了校验,对于没有权限的应用返回值是没有意义的缺省值,否则返回实际值起到保护用户的隐私目的
Class类
Class代表类的实体,在运行的Java应用程序中表示类和接口。在这个类中提供了很多有用的方法,
获得类相关的方法
获得类中属性相关的方法
获得类中注解相关的方法
获得类中构造器相关的方法
获得类中方法相关的方法
类中其他重要的方法
获取Class对象的四种方式
体验AI代码助手 代码解读复制代码package cn.string.demo.reflection;
public class TestMain {
// 获取Class对象的四种方式;
public void method1() throws ClassNotFoundException {
// 方法一:调用运行时类本身的.class属性;
Class<Person> class1 = Person.class;
System.out.println("方法一:" + class1.getName());
// 方法二:通过运行时类的对象获取;
Person person = new Person();
Class class2 = person.getClass();
System.out.println("方法二:" + class2.getName());
// 方法三:通过Class的静态方法获取;
Class class3 = Class.forName("cn.string.demo.reflection.Person");
System.out.println("方法三:" + class3.getName());
// 方法四:通过类加载器;
ClassLoader classLoader = this.getClass().getClassLoader();
Class class4 = classLoader.loadClass("cn.string.demo.reflection.Person");
System.out.println("方法四:" + class4.getName());
}
}
类加载器classloader
调用构造方法、获取继承关系
体验AI代码助手 代码解读复制代码import java.lang.reflect.Constructor;
public class TestReflection1 {
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 i = Integer.class;
Class n = i.getSuperclass();
System.out.println(n);
Class o = n.getSuperclass();
System.out.println(o);
System.out.println(o.getSuperclass());
// 获取interface
Class s = Integer.class;
Class[] is = s.getInterfaces();
for (Class j : is) {
System.out.println(j);
}
}
}
继承关系
当我们判断一个实例是否是某个类型时,正常情况下,使用instanceof操作符:
体验AI代码助手 代码解读复制代码Object n = Integer.valueOf(123);
boolean isDouble = n instanceof Double; // false
boolean isInteger = n instanceof Integer; // true
boolean isNumber = n instanceof Number; // true
boolean isSerializable = n instanceof java.io.Serializable; // true
如果是两个Class实例,要判断一个向上转型是否成立,可以调用isAssignableFrom():
体验AI代码助手 代码解读复制代码// Integer i = ?
Integer.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Integer
// Number n = ?
Number.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Number
// Object o = ?
Object.class.isAssignableFrom(Integer.class); // true,因为Integer可以赋值给Object
// Integer i = ?
Integer.class.isAssignableFrom(Number.class); // false,因为Number不能赋值给Integer
动态代理
我们来比较Java的class和interface的区别:
可以实例化class(非abstract);
不能实例化interface。
所有interface类型的变量总是通过向上转型并指向某个实例的:
体验AI代码助手 代码解读复制代码CharSequence cs = new StringBuilder();
有没有可能不编写实现类,直接在运行期创建某个interface的实例呢?
这是可能的,因为Java标准库提供了一种动态代理(Dynamic Proxy)的机制:可以在运行期动态创建某个interface的实例。
什么叫运行期动态创建?听起来好像很复杂。所谓动态代理,是和静态相对应的。我们来看静态代码怎么写:
定义接口:
体验AI代码助手 代码解读复制代码public interface Hello {
void morning(String name);
}
编写实现类:
体验AI代码助手 代码解读复制代码public class HelloWorld implements Hello {
public void morning(String name) {
System.out.println("Good morning, " + name);
}
}
创建实例,转型为接口并调用:
体验AI代码助手 代码解读复制代码Hello hello = new HelloWorld();
hello.morning("Bob");
这种方式就是我们通常编写代码的方式。
还有一种方式是动态代码,我们仍然先定义了接口Hello,但是我们并不去编写实现类,而是直接通过JDK提供的一个Proxy.newProxyInstance()创建了一个Hello接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。
一个最简单的动态代理实现如下:
体验AI代码助手 代码解读复制代码import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
InvocationHandler handler = new InvocationHandler() {
@Override
public 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(), // 传入ClassLoader
new Class[] { Hello.class }, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
hello.morning("Bob");
}
}
interface Hello {
void morning(String name);
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。