反射有性能損失,損失在哪裏?
反射的執行過程:
ClassLoader加載一個類會把類信息加載到JVM中,反射方法時,會動態解析Class需要獲取方法中的數據組成Method對象,反射執行的時候會通過Method對象執行需要執行的方法
整個過程會產生額外的對象,並且在執行方法時(Method.invoke),每次執行都會檢查方法的可見性,相當於用Method對象作爲中間者來執行,這種方式比直接執行慢。
反射是基於程序集和元數據的,在使用反射的時候,會搜索元數據,而元數據是基於字符串的,並且無法預編譯,所以這一系列操作對性能有影響
Method.invoke方法會對參數做裝箱拆箱操作,invoke方法的參數是Object可變長參數,如果方法參數是基本數據類型的話,需要在此裝箱,成爲基本類型的包裝類型,會產生額外對象,在native方法中,需要把包裝類拆箱成爲基本類型。當調用次數達到一定量的時候,還會觸發GC。
Method.invoke代碼
@CallerSensitive
// Android-changed: invoke(Object, Object...) implemented natively.
@FastNative
public native Object invoke(Object obj, Object... args)
throws IllegalAccessException, IllegalArgumentException, InvocationTargetException;
其實簡單少量的反射並不會對應用性能有太大影響,可以忽略不計,反射大概比直接調用慢50~100倍,但是需要你在執行100萬遍的時候纔會有所感覺,如果只是偶爾調用一下反射,請忘記反射帶來的性能影響。
可以參考這篇文章:反射是否真的會讓你的程序性能降低?
Class.getDeclaredMethod與Class.getMethod方法的區別是什麼?
getDeclaredMethod(String name, Class<?>… parameterTypes)
獲取當前類中的成員方法,不管是否是public,不包括父類繼承的方法
getMethod(String name, Class<?>… parameterTypes)
獲取public的成員方法,包括從父類繼承的方法
getDeclaredField(String name)
用於獲取當前類中的變量,不管是否是public,不包括父類繼承的方法
getField(String name)
用於獲取public的成員變量,包括從父類繼承的成員變量
附上
getMethod、getDeclaredMethod源碼
@CallerSensitive
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
return getMethod(name, parameterTypes, true);//true:遞歸獲取父類public方法
}
@CallerSensitive
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException {
return getMethod(name, parameterTypes, false);
}
private Method getMethod(String name, Class<?>[] parameterTypes, boolean recursivePublicMethods)
throws NoSuchMethodException {
if (name == null) {
throw new NullPointerException("name == null");
}
if (parameterTypes == null) {
parameterTypes = EmptyArray.CLASS;
}
for (Class<?> c : parameterTypes) {
if (c == null) {
throw new NoSuchMethodException("parameter type is null");
}
}
//getPublicMethodRecursive獲取public的成員方法,包括從父類繼承的方法
//getDeclaredMethodInternal獲取當前類中的成員方法,不管是否是public,不包括父類繼承的方法
Method result = recursivePublicMethods ? getPublicMethodRecursive(name, parameterTypes)
: getDeclaredMethodInternal(name, parameterTypes);
// Fail if we didn't find the method or it was expected to be public.
if (result == null ||
//檢查方法的可見性
(recursivePublicMethods && !Modifier.isPublic(result.getAccessFlags()))) {
throw new NoSuchMethodException(name + " " + Arrays.toString(parameterTypes));
}
return result;
}
//由getMethod方法調用,獲取public的成員方法,包括從父類繼承的方法
private Method getPublicMethodRecursive(String name, Class<?>[] parameterTypes) {
// search superclasses
for (Class<?> c = this; c != null; c = c.getSuperclass()) {
Method result = c.getDeclaredMethodInternal(name, parameterTypes);
if (result != null && Modifier.isPublic(result.getAccessFlags())) {
return result;
}
}
return findInterfaceMethod(name, parameterTypes);
}
getDeclaredField源碼
/**
* Returns a {@code Field} object that reflects the specified declared
* field of the class or interface represented by this {@code Class}
* object. The {@code name} parameter is a {@code String} that specifies
* the simple name of the desired field.
*/
@FastNative
public native Field getDeclaredField(String name) throws NoSuchFieldException;
getDeclaredFields 源碼
/**
* Returns an array of {@code Field} objects reflecting all the fields
* declared by the class or interface represented by this
* {@code Class} object. This includes public, protected, default
* (package) access, and private fields, but excludes inherited fields.
* 返回public、protected,default access和private字段,但是不包括繼承的字段
*/
@FastNative
public native Field[] getDeclaredFields();
getField 源碼
/**
* Returns a {@code Field} object that reflects the specified public member
* field of the class or interface represented by this {@code Class}
* object. The {@code name} parameter is a {@code String} specifying the
* simple name of the desired field.
*/
public Field getField(String name)
throws NoSuchFieldException {
if (name == null) {
throw new NullPointerException("name == null");
}
Field result = getPublicFieldRecursive(name);
if (result == null) {
throw new NoSuchFieldException(name);
}
return result;
}
/**
* The native implementation of the {@code getField} method.
*
* @throws NullPointerException
* if name is null.
* @see #getField(String)
*/
@FastNative
private native Field getPublicFieldRecursive(String name);
getFields()源碼
@CallerSensitive
public Field[] getFields() throws SecurityException {
List<Field> fields = new ArrayList<Field>();
getPublicFieldsRecursive(fields);
return fields.toArray(new Field[fields.size()]);
}
/**
* Populates {@code result} with public fields defined by this class, its
* superclasses, and all implemented interfaces.
*/
private void getPublicFieldsRecursive(List<Field> result) {
// search superclasses
for (Class<?> c = this; c != null; c = c.superClass) {
Collections.addAll(result, c.getPublicDeclaredFields());
}
// search iftable which has a flattened and uniqued list of interfaces
Object[] iftable = ifTable;
if (iftable != null) {
for (int i = 0; i < iftable.length; i += 2) {
Collections.addAll(result, ((Class<?>) iftable[i]).getPublicDeclaredFields());
}
}
}