一、自我介绍

双非大三学生一枚,主要学习的是Java后端开发

二、技术分享

对Java反射较消耗性能的分析

  1. 调用了native方法
  2. 每次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;
}
}

上面就是一段jdk中关于反射的代码,发现每次newInstance的时候做了安全检查。

下面是关于使用反射和不使用反射的时间对比。

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));
}
}

HELLO,51CTO_java

而如果将循环的次数变大

HELLO,51CTO_System_02

就会发现上面的结果,反射创建对象的代价很大。因此非必要不反射。

对范型擦除的理解

  • 泛型的擦除:
  • 泛型只在编译阶段有效,编译之后JVM会采取​​去泛型化​​的措施.
  • 泛型在运行阶段是没有效果

这里可以使用反射来绕过

public class Demo01 {
public static void main(String[] args) throws Exception {
List<String> list = new ArrayList();
list.add("1");
list.add("hello");
list.add("World");
for (String s : list) {
System.out.println(s);
}
// 通过反射的方式添加数据到集合中
Class<? extends List> aClass = list.getClass();
Method method = aClass.getDeclaredMethod("add", Object.class);
method.invoke(list,new Object());
System.out.println(list);
}
}
1
hello
World
[1, hello, World, java.lang.Object@4554617c]

运行结果如上,发现是可以插入其他类型的,因此可以确定范型在程序运行阶段是没有的。某种程度上来说,可能是Java的一个缺陷,在程序运行阶段,没有范型,程序的安全性就难以保证。

三、立一个flag!

好好学习,努力找实习,每天刷点面试题,做点项目,在51CTO上发布自己遇到的bug,觉得好的题,冲!!!