一、概述
反向探知,在程序运行过程中动态的获取类的相关属性
定义
动态获取类的内容以及动态调用对象的方法和获取属性的机制
优点
增加程序的灵活性,可以避免将固定的逻辑写死在程序中
可以提高程序的复用性
缺点
相比于直接调用,反射的效率要低得多
类的内部暴漏,带来安全隐患
反射慢的原因
- 调用了native方法
- 每次newInstance都会做安全检查 比较耗时
@CallerSensitive
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
if (cachedConstructor == null) {
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw (InstantiationException)
new InstantiationException(getName()).initCause(e);
}
}
Constructor<T> tmpConstructor = cachedConstructor;
// Security check (same as in java.lang.reflect.Constructor)
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
return tmpConstructor.newInstance((Object[])null);
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}
使用反射和不使用反射对比
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
long l1 = System.currentTimeMillis();
for (int i = 0; i < 10000000; i++) {
new Admin();
}
long l2 = System.currentTimeMillis();
System.out.println("正常创建对象:" + (l2 - l1));
long l3 = System.currentTimeMillis();
Class<Admin> adminClass = Admin.class;
for (int i = 0; i < 10000000; i++) {
adminClass.newInstance();
}
long l4 = System.currentTimeMillis();
System.out.println("反射创建对象:" + (l4 - l3));
}
}
这里是创建10000000个对象,相差6.6倍,当创建对象的数量扩大为1000000000
可以看到正常创建仍然是5毫秒,而反射创建需要接近两秒。
可以发现,正常创建对象随着数量增加代价很小,而反射代价很大。原因就是前面提到的,每次创建都进行了检测。
二、基本操作
获取类对象
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
Class<Admin> adminClass1 = Admin.class;
Class<?> adminClass2 = Class.forName("fs.Admin");
Class<? extends Admin> adminClass3 = new Admin().getClass();
Class<?> adminClass4 = Main.class.getClassLoader().loadClass("fs.Admin");
}
}
这里演示的有四种方式
显示类的相关信息
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
Class<Admin> adminClass1 = Admin.class;
Class<?> adminClass2 = Class.forName("fs.Admin");
Class<? extends Admin> adminClass3 = new Admin().getClass();
Class<?> adminClass4 = Main.class.getClassLoader().loadClass("fs.Admin");
System.out.println(adminClass1.getModifiers());
System.out.println(adminClass1.getPackage());
System.out.println(adminClass1.getName());
System.out.println(adminClass1.getSuperclass());
System.out.println(adminClass1.getClassLoader());
System.out.println(adminClass1.getSimpleName());
System.out.println(adminClass1.getInterfaces());
System.out.println(adminClass1.getAnnotations());
}
}
1
package fs
fs.Admin
class java.lang.Object
sun.misc.Launcher$AppClassLoader@18b4aac2
Admin
[Ljava.lang.Class;@1b6d3586
[Ljava.lang.annotation.Annotation;@74a14482
- adminClass1.getModifiers():获取修饰符
- adminClass1.getPackage():获取包名
- adminClass1.getName():获取全类名
- adminClass1.getSuperclass():获取继承的类
- adminClass1.getClassLoader():获取构造器
- adminClass1.getSimpleName():获取类名
- adminClass1.getInterfaces():获取实现的接口
获取到的修饰符解释
/**
* The {@code int} value representing the {@code public}
* modifier.
*/
public static final int PUBLIC = 0x00000001;
/**
* The {@code int} value representing the {@code private}
* modifier.
*/
public static final int PRIVATE = 0x00000002;
/**
* The {@code int} value representing the {@code protected}
* modifier.
*/
public static final int PROTECTED = 0x00000004;
/**
* The {@code int} value representing the {@code static}
* modifier.
*/
public static final int STATIC = 0x00000008;
/**
* The {@code int} value representing the {@code final}
* modifier.
*/
public static final int FINAL = 0x00000010;
/**
* The {@code int} value representing the {@code synchronized}
* modifier.
*/
public static final int SYNCHRONIZED = 0x00000020;
/**
* The {@code int} value representing the {@code volatile}
* modifier.
*/
public static final int VOLATILE = 0x00000040;
/**
* The {@code int} value representing the {@code transient}
* modifier.
*/
public static final int TRANSIENT = 0x00000080;
/**
* The {@code int} value representing the {@code native}
* modifier.
*/
public static final int NATIVE = 0x00000100;
/**
* The {@code int} value representing the {@code interface}
* modifier.
*/
public static final int INTERFACE = 0x00000200;
/**
* The {@code int} value representing the {@code abstract}
* modifier.
*/
public static final int ABSTRACT = 0x00000400;
/**
* The {@code int} value representing the {@code strictfp}
* modifier.
*/
public static final int STRICT = 0x00000800;
// Bits not (yet) exposed in the public API either because they
// have different meanings for fields and methods and there is no
// way to distinguish between the two in this class, or because
// they are not Java programming language keywords
static final int BRIDGE = 0x00000040;
static final int VARARGS = 0x00000080;
static final int SYNTHETIC = 0x00001000;
static final int ANNOTATION = 0x00002000;
static final int ENUM = 0x00004000;
static final int MANDATED = 0x00008000;
这里可以看到,public为1,private为2…对于各类修饰符及关键字,这里都有相关常量的定义。
上面显示为1,显然是public修饰符
- 这里继续尝试,对类加上抽象
1025
输出结果变为了2015,查上面的数据,可以发现ABSTRACT= 0x00000400即1024,然后前面给的还有public,所以总和为1025.
由于可以推出,我们拿到任意的修饰符数字,都可以推出修饰符
类中的方法操作
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
Class<Admin> adminClass1 = Admin.class;
Admin admin = adminClass1.newInstance();
//获取当前类及父类中所有的共有的方法
Method[] methods = adminClass1.getMethods();
for (Method method : methods) {
System.out.println(method.getModifiers() + " " + method.getName());
}
System.out.println("--------------");
//获取本类中的所有方法
Method[] methods1 = adminClass1.getDeclaredMethods();
for (Method method : methods1) {
System.out.println(method.getModifiers() + " " + method.getName());
}
Method read = adminClass1.getDeclaredMethod("read");
//放开私用方法的调用
read.setAccessible(true);
read.invoke(admin);
//传参的方法调用
Method saying = adminClass1.getDeclaredMethod("saying", String.class);
saying.invoke(admin,"哈哈哈");
}
}
1 saying
1 getAge
1 setAge
1 getAdminName
1 setGrade
1 getGrade
1 study
1 setAdminName
17 wait
273 wait
17 wait
1 equals
1 toString
257 hashCode
273 getClass
273 notify
273 notifyAll
--------------
2 read
1 saying
1 getAge
1 setAge
1 getAdminName
1 setGrade
1 getGrade
1 study
1 setAdminName
admin reading
admin哈哈哈
构造器的操作
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
Class<Admin> adminClass1 = Admin.class;
//获取所有公共的构造器
Constructor<?>[] constructors = adminClass1.getConstructors();
for (Constructor<?> constructor : constructors) {
System.out.println(constructor.getModifiers() + " " + constructor);
}
System.out.println("-------------------");
Constructor<?>[] constructors1 = adminClass1.getDeclaredConstructors();
for (Constructor<?> constructor : constructors1) {
System.out.println(constructor.getModifiers() + " " + constructor.getName());
}
//直接通过newInstance创建对象
Admin admin = adminClass1.newInstance();
//获取对应的构造器创建对象
Constructor<Admin> declaredConstructor = adminClass1.getDeclaredConstructor();
Admin admin1 = declaredConstructor.newInstance();
//私有构造器调用需要先开放方法的权限
declaredConstructor.setAccessible(true);
Admin admin2 = declaredConstructor.newInstance();
}
}
1 public fs.Admin()
-------------------
1 fs.Admin
联想单例模式
常见的一种单例模式
将构造器私有,然后提供一个获得对象的方法
private static Admin admin = null;
private Admin(){}
public Admin getAdmin() {
if (admin == null){
admin = new Admin();
}
return admin;
}
可以发现,如果我们通过反射,会获得这个私有构造器的权限,从而创建对象,破坏单例。
解决方法
我们可以在私有构造器上,增加一个异常处理
private Admin(){
if (Admin.admin != null){
throw new RuntimeException("实例已经创建,不允许再创建了!");
}
}
public class Main {
public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, ClassNotFoundException {
Class<Admin> adminClass1 = Admin.class;
Constructor<Admin> declaredConstructor = adminClass1.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Admin admin1 = Admin.getAdmin();
Admin admin = declaredConstructor.newInstance();
admin.setAdminName("aaa");
}
}
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at fs.Main.main(Main.java:21)
Caused by: java.lang.RuntimeException: 实例已经创建,不允许再创建了!
at fs.Admin.<init>(Admin.java:22)
... 5 more