概述:反射是java中最强大的技术之一,很多高级框架都用到了反射技术,面试中也是经常问的点,所以搞懂反射非常重要!
java反射机制指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都可以知道它是什么类的对象,并且能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法功能称为java语言的反射机制.
丢了堆概念,大家可能看的就懵逼了,接下来举个简单的例子让大家来了解什么叫动态的获取和动态的调用。
动态获取类的信息例子:
代码
Class real= user.class;
System.out.println(real.getPackage());
System.out.println(real.getName());
System.out.println(real.getSimpleName());
System.out.println("user类的所有字段属性,包括public private protected");
Field[] fieldds= real.getDeclaredFields();//获取user类中所有的字段
for(Field field : fieldds){
# System.out.println(field);
System.out.println(field.getName());
}
System.out.println("user类的所有公共方法,只有public");
Method[] methods=real.getMethods();
for(Method method: methods){
System.out.println(method.getName());
}
运行结果:
截图没有截完。
从这个例子我们可以看到,我们通过Class这个类型的对象的API就知道了user这个类的属性和方法,这就叫做动态获取类的信息。
同理,接下来我们又看动态调用的例子。
代码:
Class real=user.class;
Method method=real.getMethod("show");#user类里的show方法.
method.invoke(real.newInstance());#newInstance是new一个real类的对象,因为你要调用非static方法的话必须是去对象中访问那个方法。
我们平时编写的文件都是*.java文件,经过jdk里面的javac编译器编译后就变成了一堆*.class文件,然后类加载器会将class文件加载到JYM虚拟机的内存中,此时会自动创建一个Class对象(由始至终只有一个)去存储这个类的相关信息(构造器,成员变量,方法等等)。我们可以利用这个Class对象去动态的创建对象和动态的调用对象的方法。
#通过class.forname()来获取Class对象
Class nice=Class.forName("com.example.questions.bean.user");
#通过类名来获取对象, 前提是该类必须能在当前项目中找到
Class real= user.class;
#通过对象的.getClass方法来获取
Class notgoodway=user1.getClass();
静态编译:在编译时确定类型,绑定对象,即通过。
动态编译:运行时确定类型,绑定对象。动态编译最大限度发挥了java的灵活性,体现了多态的应用,有以降低类之间的藕合性。
反射机制的优点:可以实现动态创建对象和编译,体现出很大的灵活性(特别是在J2EE的开发中它的灵活性就表现的十分明显)。通过反射机制我们可以获得类的各种内容,进行了反编译。对于JAVA这种先编译再运行的语言来说,反射机制可以使代码更加灵活,更加容易实现面向对象。
反射机制的缺点:对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它 满足我们的要求。这类操作总是慢于只直接执行相同的操作。
待更
1.获取类名
Class aClass = MyObject.class;
String className = aClass.getName();
2.获取类权限修饰符
#使用Class对象可以获取一个类的修饰符.类的修饰符即关键字"public","private", "static"等. 如下:
Class aClass = MyObject.class;
int modifiers = aClass.getModifiers();
3.获取包信息
使用Class对象可以获取包信息,如下:
Class aClass = MyObject.class;
Package package = aClass.getPackage();
String packageName = package.getname();
4.获取父类
Class aClass = MyObject.class;
Class superclass = aClass.getSuperclass();
5.获取实现的接口
Class aClass = MyObject.class;
Class[] interfaces = aClass.getInterfaces();
注意:只有给定类声明实现的接口才会返回。例如,如果类A的父类B实现了一个接口C,但类A并没有声明它也实现了C,那么C不会被返回到数组中。即使类A实际上实现了接口C,因为它的父类B实现了C。
6.获取构造函数
Class aClass = MyObject.class;
Constructor[] constructors = aClass.getConstructors();
7.获取方法
Class aClass = MyObject.class;
Method[] methods = aClass.getMethods();
8.获取属性
Class aClass = MyObject.class;
Field[] fields = aClass.getFields();
9.获取类的注解
Class aClass = MyObject.class;
Annotation[] annotations = aClass.getAnnotations();
10.使用Method对象调用方法
Method method = MyObject.class.getMethod("doSomething", String.class);
Object returnValue = method.invoke(null, "parameter-value1");
空参数是你想要调用该方法的对象。如果该方法是静态的,使用null,而不是一个对象实例。在这个例子中,如果doSomething(String.class)不是静态的,你需要提供有效的MyObject实例而不是null作为参数;
Method.invoke(Object target, Object …parameters)方法接受可变长度的参数,但是你在调用时必须为每一个参数提供一个准确的参量。在这个例子中,方法以字符串作为参数的,所以必须提供一个字符串。
11.获取方法的参数和返回值类型
Method method = ... //获取 method – 如上
Class[] parameterTypes = method.getParameterTypes();
Method method = ... // obtain method - see above
Class returnType = method.getReturnType();
后续遇到什么API再补上