Java反射机制
反射的内容:
1、Class类的使用;
2、动态加载类;
3、方法的反射;
4、获取成员变量属性;
5、通过反射了解集合泛型的本质。
一:class类的使用
在Java中,万事万物皆对象,类也是对象,任何一个类都是java.lang.Class类的实例对象,这个对象我们称为该类的类类型。
注:静态成员(静态成员属于类)与普通数据类型(但有对应的包装类弥补)不是对象
(1)反射机制获取类有三种方法:
注:功能性的类尽量使用动态加载,并对新添的类实现功能性接口(标准),这样就不用重新编译
①forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装(最建议)
注:这种方法不仅表示了类的类类型,还代表了动态加载类区分编译、运行编译时刻加载类是静态加载类,运行时刻加载类是动态加载类
②类名.class
③对象.getClass()
以Person类为例:
public void test1() throws Exception {
// 方式一
Class clazz1 = Class.forName("reflect.Person");
// 方式二
Class clazz2 = Person.class;
// 方式三
Person p1 = new Person();
Class clazz3 = p1.getClass();
}
(2)通过Class类获取类的一些信息
1. getName()类的名称(全名,全限定名)
2 getSimpleName()类的的简单名称(不带包名)
3. getModifiers(); 类的的修饰符
4.创建对象
无参数构造创建对象
newInstance()
5. 获取指定参数的构造器对象,并可以使用Constructor对象创建一个实例
Constructor<T> getConstructor(Class<?>... parameterTypes)
例:
private static void test2() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
// 获取类的名称
String name = clazz1.getName();
System.out.println(name); // reflect.Person
// 获取类的简单名称
System.out.println(clazz1.getSimpleName()); // Person
// 获取类的修饰符
int modifiers = clazz1.getModifiers();
System.out.println(modifiers);
// 构建对象(默认调用无参数构造.)
Object ins = clazz1.newInstance();
Person p = (Person) ins;
System.out.println(p);
// 获取指定参数的构造函数
Constructor<?> con = clazz1.getConstructor(String.class, int.class);
// 使用Constructor创建对象.
Object p1 = con.newInstance("jack", 28);
System.out.println(((Person) p1).getName());
}
在JDK中,主要由以下类来实现Java反射机制,这些类(除了第一个)都位于java.lang.reflect包中:
Class类:代表一个类,位于java.lang包下。
Field类:代表类的成员变量(成员变量也称为类的属性)。
Method类:代表类的方法。
Constructor类:代表类的构造方法。
Array类:提供了动态创建数组,以及访问数组的元素的静态方法
二:动态加载类
1.区分动态加载和静态加载
静态加载类,是编译时刻加载;
动态加载类,是运行时刻加载
2、new创建对象:是静态加载类,在编译时刻就需要加载所有的【可能使用
到的类】。有一个类有问题(如不存在),都不能通过编译,会报错。通
过动态加载类可以解决该问题。
3、Class.forName():动态加载类,当用到一个类时,才进行加载。
三:方法的反射:
①要获取一个方法就是获取类的信息,获取类的信息首先要获取类的类类型
②获取方法 由名称和参数列表来决定,getMethod获取的是public方法,getDelcaredMethod获取自己声明的方法
(1)通过Class类获取类型中的方法的信息
1.获取公共方法包括继承的父类的方法
getMethods(); 返回一个数组,元素类型是Method
2.获取指定参数的公共方法
getMethod("setName", String.class);
3.获得所有的方法,包括私有
Method[] getDeclaredMethods();
4.获得指定参数的方法,包括私有
Method getDeclaredMethod(String name, Class<?>... parameterTypes)
例:
/**
* 获取公有方法.
* @throws Exception
* */
private static void test3() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
// 1.获取非私用方法(包括父类继承的方法)
Method[] methods = clazz1.getMethods();
System.out.println(methods.length);
for (Method m : methods) {
// System.out.println(m.getName());
if ("eat".equals(m.getName())) {
m.invoke(clazz1.newInstance(), null);
}
}
}
/**
* 获取指定方法签名的方法
* @throws Exception
* */
private static void test4() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
// 获取指定名称的函数
Method method1 = clazz1.getMethod("eat", null);
method1.invoke(new Person(), null);
}
/**
* 获取指定方法名且有参数的方法
* @throws Exception
* */
private static void test5() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
Method method = clazz1.getMethod("eat", String.class);
method.invoke(new Person(), "包子");
}
/**
* 获取指定方法名,参数列表为空的方法.
* @throws Exception
* */
private static void test4() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
// 获取指定名称的函数
Method method1 = clazz1.getMethod("eat", null);
method1.invoke(new Person(), null);
}
(2)反射方法
/**
* 反射静态方法
* @throws Exception
* */
private static void test7() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
Method method = clazz1.getMethod("play", null);
method.invoke(null, null);
}
/**
* 访问私有方法 暴力反射
* @throws Exception
* */
private static void test6() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
Method method = clazz1.getDeclaredMethod("movie", String.class);
method.setAccessible(true);
method.invoke(new Person(), "张艺谋");
}
四:通过Class类获取类型中的属性的信息
1.获取公有属性
Field[] getFields()
2.获取指定参数的公共属性
Field getField(String name)
3.获取所有的属性
Field[] getDeclaredFields()
4.获取指定参数的属性,包括私有
Field getDeclaredField(String name)
例:
/**
* 获取公有的属性
* */
private static void test8() throws Exception {
Class clazz1 =Class.forName("reflect.Person");
Field[] fields = clazz1.getFields();
Person p = new Person();
System.out.println(fields.length);
for (Field f : fields) {
System.out.println(f.getName());
if ("name".equals(f.getName())) {
System.out.println(f.getType().getName());
f.set(p, "jack");
}
}
System.out.println(p.getName());
}
/**
* 获取私有的属性
* @throws Exception
* */
private static void test9() throws Exception {
Class clazz1 = Class.forName("reflect.Person");
Field field = clazz1.getDeclaredField("age");
System.out.println(field.getName());
field.setAccessible(true);
Person p = new Person();
field.set(p, 100);
System.out.println(p.getAge());
}
五:通过反射了解集合泛型的本质
--java中集合的泛型是防止错误输入的;
--只在编译阶段有效,绕过编译就无效了,我们可以通过方法的反射来操作,绕过编译
例:
ArrayList list1=new ArrayList();
ArrayList<String> list2=new ArrayList<String>();
Class c1=list1.getClass();
Class c2=list2.getClass();
System.out.print(c1==c2); //true
Method m=c2.getMethod("add",Object.class);
m.invoke(list2,20);//向list2集合中添加一个int 型的值;绕过编译,这时就不能直接foreach list2集合,会报类型转换错误
------录制视频的老师say:如果想成为大牛,就一定会用到反射机制,编写一些工具,就比如用于javaweb开发的三大框架......hahahahaha~~~,目前只希望能看懂大牛们的代码=。=