前言:
我们在程序开发的过程中,有时会碰到这样一种情况:A程序员和B程序员共同开发某一项功能,因为是并行开发,有可能A程序员需要用到B程序员所写的类,但是B程序员并没有完成,这种情况下,A程序员的代码是不能通过编译的,有没有办法解决呢?
还有一种情况,当我们想去查看java对象的属性、方法、构造方法,有没有更方便简洁的办法呐?
这个时候我们引用了 java反射机制。
反射机制:
是指在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个属性和方法;这种动态获取调用对象的方法的功能成为java语言的反射机制。
JAVA反射(放射)机制:“程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言”。从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是动态语言。换句话说,就是java程序可以加载一个运行时才得知名称的class,并能对其进行操作。----java反射机制(百度百科)
1)在运行时,可以判断任意一个对象所属的类;
2)在运行时,构造任何一个类的对象;
3)在运行时,判断任意一个对象所具有的成员变量和方法;
4)在运行时,调用任意一个对象的方法;
5)生成动态代理
java反射提供的类:
java.lang.Class;
java.lang.reflect.Constructor;
java.lang.reflect.Field;
java.lang.reflect.Method;
java.lang.reflect.Modifier;
使用:
一)获得类的Class实例
所有类都是Class的类类型
以Person(一个普通的类)类为例:
class RefleDemo {
public static void main(String [] args) {
//方式1)直接调用该类的class方法
Class c1=Person.class;
//方式2)调用对象的getClass()方法
Person person=new Person();
Class c2=person.getClass();
//方式3)通过该类的路径获得
Class c3=Class.forName("该类的全路径");
Person person = (Person) c3.newInstance();(运行时,构建任何一个类的对象)
}
}
二)操作类的Class实例
反射:运行时的类信息---java编程思想。
通过获取到的类的实例,我们可以获取到该类的成员类型,方法,构造函数信息,Class类也java.lang.reflect类库一起对反射的概念进行了支持;
1)获取类的方法
/**
* 获取Class实例的方法
* getDeclaredMethods():仅获得该类的所有的方法(包括重写),不获取Object父类的方法
* getMethods():获得该类以及Object父类的public类型方法(包括重写)
*/
private void getClassMethods() {
Class c1 = Person.class;
Method[] methods = c1.getDeclaredMethods();
Method[] methods = c1.getMethods();
for (Method method : methods) {
Log.i("info", method.getName());
}
}
2)获取类的构造器
/**
* 获得Class实例的构造函数
* getDeclaredConstructors()
* getConstructors()
*/
private void getConstructors() {
Class c1 = Person.class;
//Constructor[] constructors = c1.getDeclaredConstructors();
Constructor[] constructors = c1.getConstructors();
for (Constructor constructor : constructors) {
Log.i("info", constructor.getName());
}
}
3)获取类的成员
/**
* 获得Class实例的成员
* getFields():获得该类的public类型的
* getDeclaredFields():获得该类所有的成员
*/
private void getFields() {
Class c1 = Person.class;
Field[] fields = c1.getFields();
// Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
Log.i("info", field.getName());
}
}
三)方法反射
已知Person类中有一个方法refleMethod(),我们可以通过java方法反射的机制获取到该方法。
public class Person {
public void refleMethod(String args) {
System.out.print(args);
}
}
/**
* java方法反射
*/
private void getRefleMethod() {
//获得Class实例
Person person = new Person();
Class c1 =person.getClass();
try {
//获得对应的方法 getMethod 参数1:对应的方法名称,参数2:对应方法的参数类型 (没有参数类型 则空)
//Method method = c1.getMethod("refleMethod", new Class[]{String.class});
Method method = c1.getMethod("refleMethod", String.class);
//操作对应的方法 invoke 参数1:是该方法所在的类的对象,参数2:赋值 (没有参数则空)
//Object object = method.invoke(person, new Object[]{"this is a test!"});
Object object = method.invoke(person, "this is a test!");
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
4)java泛型的扩展:测试泛型
/**
* 测试泛型的本质 (生命周期只存在编译期间,运行期间去泛型化)
*/
private void testFX() {
ArrayList array1 = new ArrayList();
ArrayList
Log.i("info", "array1与array2相等吗:" + (array1.getClass() == array2.getClass()));//true
/**
* 反射操作都是编译之后的操作(变成字节码之后),是运行时期的操作。
* 从上面的结果可以看出编译之后集合的泛型是去泛型化的
*/
try {
Method method = array2.getClass().getMethod("add", Object.class);
method.invoke(array2, 100);
Log.i("info", "array2:" + array2.size());//长度为1
/**
* 我们通过方法反射的机制,测试了把类型为int的值加入到了ArrayList
* 这种操作是在编译期间不允许的,
* 之所以有这种限制,就是减少操作数据的错误
* 在运行期间可以实现,这说明了java的泛型在运行期间是去泛型化的
*/
} catch (Exception e) {
e.printStackTrace();
}
}
推荐视频:慕课网 https://www.imooc.com/video/3725