一、Class
1.Class是一个类。是对象照镜子后可以得到的信息:数据成员名、方法和构造器、某个类到底实现了哪些接口2.对于每个类而言,JRE为其保留一个不变的Class类型的对象。一个Class对象包含了特定某个类的有关信息
3.Class对象只能由系统建立
4.一个类在JVM中只有一个Class实例。每个类的实例都会记得自己是由哪个Class实例所生产
5.获取Class对象的方式
- Class clazz = null;
- //1.通过类名.class获取
- clazz = Person.class;
-
- //2.通过对象的getClass()方法获取
- Person person = new Person();
- clazz = person.getClass();
-
- //3.通过全类名获取
- clazz = Class.forName("com.ithings.enumtest.Person");
- //利用Class对象的newInstance方法来创建一个对象
- Objectobj = clazz.newInstance();
二、ClassLoader
类装载器是用来把类(class)装载进 JVM 的。JVM 规范定义了两种类型的类装载器:
启动类装载器(bootstrap)和用户自定义装载器(user-defined class loader)。
JVM在运行时会产生3个类加载器组成的初始化加载器层次结构 ,
如下图所示
- //1.获取系统类加载器 -- System ClassLoader
- ClassLoader classLoader = ClassLoader.getSystemClassLoader();
- //2.获取系统类加载器的父加载器扩展类加载器 -- Extension ClassLoader
- classLoader = classLoader.getParent();
- //3.获取扩展类加载器的父加载器系统类加载器 -- Bootstap ClassLoader(获取不到,为空)
- classLoader = classLoader.getParent();
- //4.测试当前类由哪个加载器加载 -- System ClassLoader
- classLoader = Class.forName("com.ithings.enumtest.PersonClass").getClassLoader();
- //5.测试JDK提供的Object对象由哪个加载器加载 -- Bootstap ClassLoader(获取不到,为空)
- classLoader = Class.forName("java.lang.Object").getClassLoader();
- //6.应用实例 -- 获取资源文件的输入流
- InputStream in = this.getClass().getClassLoader().getResourceAsStream("config.properties");
三、Method对象
(一)获取
- Class clazz = Class.forName("com.ithings.enumtest.Person");
- //1.获取所有方法,不包含private方法
- Method[] methods = clazz.getMethods();
- //2.获取所有方法,包括private方法,且之获取当前类声明的方法
- methods = clazz.getDeclaredMethods();
- //3.获取指定的方法
- Method method = clazz.getMethod("setName", String.class);
- method = clazz.getMethod("getName");
- //4.执行方法 obj:执行哪个对象的方法,args:执行方法时需要传入的参数
- Object obj = clazz.newInstance();
- method.invoke(obj, "TT");
(二)操作
- //5.工具方法 -- invoke
- public void testClassMethod() throws Exception{
- //1.全类名
- String className = "com.ithings.enumtest.Person";
- //2.方法名:可能是父类方法,可能是私有方法
- String methodName = "setName";
- //3.参数列表
- Object[] args = {"AA"};
- invokeMethod(className, methodName, args);
- }
- //方法
- public Object invokeMethod(String className, String methodName, Object ... args) throws Exception{
- //1.根据全类名,获取Class对象
- Class clazz = Class.forName(className);
- //2.从给定的参数中,获取参数类型列表
- Class[] parameterTypes = new Class[args.length];
- for(int i=0; i<args.length;i++){
- parameterTypes[i] = args[i].getClass();
- }
- //3.若当前类中无该方法,需要循环去父类中查找
- Method method = null;
- for(; clazz != Object.class; clazz = clazz.getSuperclass()){
- try{
- method = clazz.getDeclaredMethod(className, parameterTypes);
- break;
- }catch(Exception ex){
- }
- }
- //4.method可能是私有的,设置可访问私有方法
- method.setAccessible(true);
- //5.method方法
- //5.1 创建类的对象
- Object obj = clazz.newInstance();
- //5.2 调用方法
- Object result = method.invoke(obj, args);
- return result;
- }
四、Field对象
(一)获取
- //1.全类名
- String className = "com.ithings.enumtest.Person";
- Class clazz = Class.forName(className);
- //1.获取Field的数组
- Field[] fields = clazz.getDeclaredFields();
- //2.获取指定的Field
- Field field = clazz.getDeclaredField("name");
- Person person = new Person("TT",3);
- //3.1 获取指定对象的Field的值
- Object val = field.get(person);
- //3.2 设置指定对象的Field
- field.set(person, "TT");
- //4. 若字段是私有的,则需要设置setAccessible
- field.setAccessible(true);
(二)操作
- public void testClassField() throws Exception{
- //1.全类名
- String className = "com.ithings.enumtest.Person";
- //2.方法名:可能是父类方法,可能是私有方法
- String fieldName = "";
- //3.属性值
- Object value = "TT";
- setField(className, fieldName, value);
- }
- //方法
- public void setField(String className, String fieldName, Object value) throws Exception{
- //1.根据全类名,获取Class对象
- Class clazz = Class.forName(className);
- //2.若当前类中无该属性,需要循环去父类中查找
- Field field = null;
- for(; clazz != Object.class; clazz = clazz.getSuperclass()){
- try{
- field = clazz.getDeclaredField(fieldName);
- break;
- }catch(Exception ex){
- }
- }
- //3.field,设置可访问私有方法
- field.setAccessible(true);
- //4.设置field的值
- //5.1 创建类的对象
- Object obj = clazz.newInstance();
- //5.2 调用方法
- field.set(obj, value);
- }
五、动态代理
1.定义一个接口及实现类。定义一个被代理的对象,使用final修饰
2.类加载器通常是和被代理对象使用相同的类加载器
3.Proxy.newInstance()的返回值是一个被代理对象实现的接口的类型
4.InvocationHandler通常使用匿名内部类的方式
5.InvocationHandler的invoke()方法中的第一个参数Object类型的proxy指的是正在被返回的那个代理对象,一般不使用
- public void proxyMethod(){
- final IDoService doService = new DoServiceImpl();
- IDoService proxy = (IDoService)Proxy.newProxyInstance(doService.getClass().getClassLoader(),
- new Class[]{IDoService.class}, new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- //方法执行前打印
- System.out.println("start with " + method.getName());
- //调用被代理的类的方法
- Object result = method.invoke(doService, args);
- //方法执行后打印
- System.out.println("end ");
- return null;
- }
- });
- proxy.run("TT");
- proxy.walk("WH");
- }