1.反射基础
https://blog.csdn.net/u014294681/article/details/86441130
import com.cheniixin.Son;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
//获得class 对象<br /> //方法1 或者static Class forName(String name, boolean initialize, ClassLoader loader)<br /> //Class<?> son = Class.forName("com.cheniixin.Son");<br /> //方法2<br /> //Class<?> son = Son.class;<br /> //方法3 通过对象<br /> Class<?> son = new Son("","").getClass();<br /> <br /> // 通过class获得 对象<br /> // 方法1 无参数<br /> // Object sonObject = son.newInstance();
// 方法2 有参数<br /> //Constructor constructor = son.getConstructor(String.class,String.class);<br /> // 若构造器为私有<br /> //constructor.setAccessible(true);<br /> //Object sonObject = constructor.newInstance("111","22");<br /> <br /> <br /> <br /> //获得mehod 对象<br /> //方法1 获得可访问的所有方法mehod<br /> Method[] method1s = son.getMethods();<br /> //方法2 获得可访问某一方法mehod<br /> Method method2 = son.getMethod("setName");<br /> //方法3 获得声明的所有方法mehod<br /> Method[] method2s = son.getDeclaredMethods();<br /> //方法4 获得声明的某一mehod<br /> Method method3 = son.getDeclaredMethod("setName");<br /> <br />
// 获得字段<br /> // 方法1 获得可访问所有的字段<br /> for (Field f :son.getFields()){<br /> System.out.println("getField is " + f.getName());<br /> }
// 方法2 通过名字可访问的获得某一字段<br /> son.getField("name");<br /> <br /> <br /> // 方法3 获得声明所有的字段<br /> for (Field f :son.getDeclaredFields()){<br /> System.out.println("getDeclaredField is " + f.getName());<br /> }<br /> // 方法4 获得声明某一的字段<br /> son.getDeclaredField("name");
// Field field = son.getDeclaredField(“name”);
// field.setAccessible(true);
// field.set(sonObject,”ccc”);
// System.out.println(“name is” + field.get(sonObject));
} catch (Exception e) {<br /> e.printStackTrace();<br /> }<br /> }<br /> <br />}
2 class类
1.forName方法
输入需要加载的类的全路径名,得到类的Class对象
2.newInstance方法
3.isInstance(native方法)
用于判断入参是否为当前Class对象(子类)的实现类
4.getName、getTypeName、getCanonicalName、getSimpleName
public static void main(String[] args) {
System.out.println(TestClass.class.getTypeName());
System.out.println(TestClass.class.getCanonicalName());
System.out.println(TestClass.class.getSimpleName());
System.out.println(TestClass.class.getName());
System.out.println(“———————————————————————————-“);
System.out.println(TestClass[].class.getTypeName());
System.out.println(TestClass[].class.getCanonicalName());
System.out.println(TestClass[].class.getSimpleName());
System.out.println(TestClass[].class.getName());
}
public static abstract class TestClass<T extends TestInfo, String> extends TestInfo implements Aware, Comparable<Integer> {<br /> public abstract void test();<br /> }
输出结果
com.hikvision.test.abc.TestInfo$TestClass
com.hikvision.test.abc.TestInfo.TestClass
TestClass
com.hikvision.test.abc.TestInfo$TestClass
———————————————————————————-
com.hikvision.test.abc.TestInfo$TestClass[]
com.hikvision.test.abc.TestInfo.TestClass[]
TestClass[]
[Lcom.hikvision.test.abc.TestInfo$TestClass;
5.getClassLoader
获取当前类的类加载器
6.getTypeParameters
获取泛型类中的泛型参数数组。
7.getSuperclass和getGenericSuperclass
都是获取父类信息,但是后者会带上泛型参数
8.getInterfaces和getGenericInterfaces
获取当前Class对象实现的接口数组,但是后者会带上接口的泛型参数
public static void main(String[] args) {
System.out.println(TestClass.class.getInterfaces()[1]);
}
public static abstract class TestClass<T extends TestInfo,String> extends TestInfo implements Aware,BeanFactory {<br /> public abstract void test();<br /> }<br />输出结果 interface org.springframework.beans.factory.BeanFactory java.lang.Comparable<java.lang.Integer><br />9.isAssignableFrom(native方法)<br />这个方法比较反人类,括号里的入参表示的是当前Class对象的父类或者是同一个对象时才成立。<br />//这样返回的是false<br />System.out.println(TestClass.class.isAssignableFrom(TestInfo.class));<br />10.isInterface(native方法)<br />判断是否为接口<br />11.isArray(native方法)<br />是否为数组<br />12.isPrimitive(native方法)<br />用于判断这个Class对象是否为基本类型,如int,byte,char等<br />13.isAnnotation<br />判断这个Class对象是否为注解<br />14.getComponentType<br />如果当前Class对象是数组,获取数组中的元素类型<br />15.getModifiers<br />获取类前面的修饰词对应的枚举值<br />16.getDeclaringClass<br />获取方法或属性的归属类,或者获取当前Class对象继承于哪个类<br />17.getSimpleName<br />Class对象的类名<br />18.getClasses、getDeclaredClasses<br />(1)获取Class对象中public修饰的内部类 (2)获取Class对象中的内部类,继承成员是不包含在内的<br />19.getFields、getField、getDeclaredFields<br />(1)获取public修饰的属性域 (2)根据输入的属性名查找对应的属性域 (3)获取Class对象中的属性域<br />20.getMethods、getMethod、getDeclaredMethods<br />(1)获取public修饰的方法 (2)根据输入的方法名和入参类型,查找对应的方法 (3)获取Class对象中的方法<br />21.getConstructors、getConstructor、getDeclaredConstructors<br />(1)获取public修饰的构造函数 (2)根据输入的方法名和入参类型,查找对应的构造函数 (3)获取Class对象中的构造函数<br />22 isAnonymousClass()isInterfaceisLocalClass isMemberClassisSynthetic <br />是否为匿名、接口、局部内部类、内部、镶嵌类<br />23 getPackage<br />24
AnnotatedType[] | getAnnotatedInterfaces() 返回“AnnotatedType”对象的数组,这些对象表示使用类型指定此“Class”对象所表示的实体的上接口。 |
AnnotatedType | getAnnotatedSuperclass() Returns an AnnotatedType object that represents the use of a type to specify the superclass of the entity represented by this Class object. |
A | getAnnotation(Class annotationClass) Returns this element’s annotation for the specified type if such an annotation is present, else null. |
Annotation[] | getAnnotations() Returns annotations that are present on this element. |
A[] | getAnnotationsByType(Class annotationClass) Returns annotations that are associated with this element. |
Class[] | getClasses() Returns an array containing Class objects representing all the public classes and interfaces that are members of the class represented by this Class object. |
Class | getComponentType() Returns the Class representing the component type of an array. |
Constructor | getConstructor(Class… parameterTypes) Returns a Constructor object that reflects the specified public constructor of the class represented by this Class object. |
3 Method 类
4 Filed类
5.反射的缺点
反射被广泛地用于那些需要在运行时检测或修改程序行为的程序中。这是一个相对高级的特性,只有那些语言基础非常扎实的开发者才应该使用它。如果能把这句警示时刻放在心里,那么反射机制就会成为一项强大的技术,可以让应用程序做一些几乎不可能做到的事情。
反射的缺点:
- 反射包括了一些动态类型,所以JVM无法对这些代码进行优化。因此,反射操作的效率要比那些非反射操作低得多。我们应该避免在经常被执行的代码或对性能要求很高的程序中使用反射。
- 使用反射技术要求程序必须在一个没有安全限制的环境中运行。如果一个程序必须在有安全限制的环境中运行,如Applet,那么这就是个问题了。
- 由于反射允许代码执行一些在正常情况下不被允许的操作(比如访问私有的属性和方法),所以使用反射可能会导致意料之外的副作用:代码有功能上的错误,降低可移植性。反射代码破坏了抽象性,因此当平台发生改变的时候,代码的行为就有可能也随着变化。
-
6 提升反射效率
尽量不要getMethods()后再遍历筛选,而直接用getMethod(methodName)来根据方法名获取方法。
- 需要多次动态创建一个类的实例的时候,有缓存的写法会比没有缓存要快很多。void createInstance(String className){
cachedClass = cache.get(className);
if (cachedClass == null) {
// Class.forName耗时
cachedClass = Class.forName(className);
cache.set(className, cachedClass);
}
return cachedClass.newInstance();
} - 使用高性能的反射库,比自己写缓存效果好,如joor,或者apache的commons相关工具类。
-
7 反射修改final static 常量 会变化吗 ?
8 哪里用到反射
JDBC中,利用反射动态加载了数据库驱动程序。
- Web服务器中利用反射调用了Sevlet的服务方法。
- Eclispe等开发工具利用反射动态刨析对象的类型与结构,动态提示对象的属性和方法。
- 很多框架都用到反射机制,注入属性,调用方法,如Spring。
- jdk动态代理
-
9 如何提升反射效率
使用缓存保存 。Class.forName这个方法比较耗时,它实际上调用了一个本地方法,通过这个方法来要求JVM查找并加载指定的类。所以我们在项目中使用的时候,可以把Class.forName返回的Class对象缓存起来,下一次使用的时候直接从缓存里面获取,这样就极大的提高了获取Class的效率。同理,在我们获取Constructor、Method等对象的时候也可以缓存起来使用,避免每次使用时再来耗费时间创建。
- 不要用getMethods()后再遍历筛选,如果知道方面的名字的情况下,尽量使用直接根据方法名的情况下获取方法getMethos(methodsName);
- 使用当前高性能的反射库如 ReflectASM
10 Class.forName和ClassLoader的区别
在java中Class.forName()和ClassLoader都可以对类进行加载。ClassLoader就是遵循双亲委派模型最终调用启动类加载器的类加载器,实现的功能是“通过一个类的全限定名来获取描述此类的二进制字节流”,获取到二进制流后放到JVM中。Class.forName()方法实际上也是调用的CLassLoader来实现的。
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
最后调用的方法是forName0这个方法,在这个forName0方法中的第二个参数被默认设置为了true,这个参数代表是否对加载的类进行初始化,设置为true时会类进行初始化,代表会执行类中的静态代码块,以及对静态变量的赋值等操作。
也可以调用Class.forName(String name, boolean initialize,ClassLoader loader)方法来手动选择在加载类的时候是否要对类进行初始化。Class.forName(String name, boolean initialize,ClassLoader loader)的源码如下:
/ @param name fully qualified name of the desired class
@param initialize if {@code true} the class will be initialized.
See Section 12.4 of The Java Language Specification.
@param loader class loader from which the class must be loaded
@return class object representing the desired class
@exception LinkageError if the linkage fails
@exception ExceptionInInitializerError if the initialization provoked
by this method fails
@exception ClassNotFoundException if the class cannot be located by
the specified class loader
@see java.lang.Class#forName(String)
@see java.lang.ClassLoader
@since 1.2
/
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
caller = Reflection.getCallerClass();
if (sun.misc.VM.isSystemDomainLoader(loader)) {
ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
return forName0(name, initialize, loader, caller);
}11 反射底层原理