从这节课开始, 我们正式进入java 反射机制的学习
首先,什么是java的反射机制?来看百度百科:
重点:
- 在运行状态中
- 对任意一个实体类
- 对任意一个对象
- 动态获取信息
- 动态调用对象方法
Java有个包,叫java.lang.reflect,这个包下的所有类都是为反射机制服务的,除此之外还有一个非常重要的类:java.lang.Class
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement {
Class类:
- 反射机制的核心类,这个类包含了我们定义的类的所有属性和方法以及类名
- 这个类的构造器是私有的,所以不用想着new了
- 获取Class对象的方法有 类.class,对象.getClass(), Class.forName(String className) 等
接下来来看看代码:
package reflection;
import helloworld.MyArrayList;
import java.lang.reflect.Field;
public class ClassTeach {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
/**
* Class类可以动态获取任意实体类的属性和方法,那么,我们随便挑个类来试试
* 比如之前我们自己写过的MyArrayList
*/
//第一种获取Class对象的方法: 类.class
Class clazz1 = MyArrayList.class;
//第二种获取Class对象的方法: 对象.getClass()
MyArrayList<Object> list = new MyArrayList<>();
Class clazz2 = list.getClass();
//第三种获取Class对象的方法: Class.forName() 参数是全类名,即完整包名+类名
//这个方法可能会抛出ClassNotFoundException,表示要加载的类找不到,这个异常是编译时异常
Class clazz3 = Class.forName("helloworld.MyArrayList");
/**
* 根据百科里的内容,反射机制是可以动态获取一个类的所有属性和方法的
* 我们来试试
* 首先,查API文档,看看有什么方法可以获取属性和方法
*
* public Field getDeclaredField(String name)
* 返回一个Field对象,它反映此表示的类或接口的指定已声明字段类对象。 name参数是一个String ,它指定了所需字段的简单名称。
*
* OK,这里又牵扯出一个新的类 Field,大家可以暂停视频猜猜在哪个包下
* 揭晓答案, 在java.lang.reflect下,看英语我肯定看得懂,怕你们看不懂,还是来看API文档
*
* Filed 提供有关类或接口的单个字段的信息和动态访问。 反射的字段可以是类(静态)字段或实例字段。
* 所谓字段,其实就是属性
*/
//用clazz1来试试获取属性
//MyArrayList里有一个size属性,来获取的看看
//此方法可能报一个异常NoSuchFieldException,表示没有这样的一个属性
Field sizeField = clazz1.getDeclaredField("size");
System.out.println(sizeField.getName()); //size
/**
* 来介绍下Field比较常用的三个方法
* getName() 获取属性名称
* set(Object obj, Object value) 给obj的Field对应的属性赋值value
* get(Object obj) 获取obj的Field对应的属性的值
*/
//前面我们new了一个list对象,现在来试试
//set方法会报一个异常IllegalAccessException,表示非法接触异常,即如果对象是private的你是不能直接接触的
//刚说完可能报异常立马报了,因为size属性是私有的
//如果我们非要给size属性赋值怎么办?
//设置accessible为true即可
sizeField.setAccessible(true);
sizeField.set(list,2);
//不报错了
//现在来看看list的size属性的值
System.out.println(list.size()); //可以看到已经给list的size属性赋值了
//再来用引用获取的看看
//get方法依然会抛异常,而且还是两个 IllegalArgumentException, IllegalAccessException
//一个非法参数,一个非法接触
System.out.println(sizeField.get(list));
//可以看到通过get也可以动态获取
//最后来输出下Class对应的类的名字吧,下节课再来讲动态获取方法
System.out.println(clazz1.getName()); //helloworld.MyArrayList
}
}