第一章 反射的概述

第1节 反射的概念

Java的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法,并且对于任意一个对象,都能够调用它的任意一个方法,这种动态获取信息以及动态调用对象方法的功能称为Java的反射机制.

第2节 反射理解

如果存在反射,那是不是也存在正射?如果存在正射,那么什么是正射呢?
  • 白话正射
在编写代码的时,如果使用到了某一个类,首先需要了解这个类是干什么的,然后使用new关键字实例化对象.接着对这个对象进行操作,这就是正射.

Teacher t = new Teacher();//实例化
t.doWork("语文");//调用方法(操作对象)
  • 白话反射
反射就是我们不知道要创建对象的类是什么,自然也就无法使用new关键字来创建对象,但是我还想创建对象
  • 正射和反射的对比
/*
 * 下面是使用正射和反射实现的
 * 功能相同
 */
public class TestDemo02 {
    public static void main(String[] args) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        //正射
      	Teacher t = new Teacher();
        t.doWork("语文");
				//反射
        Teacher obj = (Teacher) createObject("cn.ukoko.Teacher");
        obj.doWork("数学");

    }

    public static Object createObject(String o) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        Class<?> c = Class.forName(o);
        Object obj = c.newInstance();
        return obj;
    }
}
class Teacher{
    void doWork(String w){
        System.out.println("老师批改"+w+"作业...");
    }
}

第二章 反射常见API

java.lang.Class: 描述类的类
java.lang.reflect.Method: 描述方法的类
java.lang.reflect.Field: 描述属性的类
java.lang.reflect.Constructor: 描述构造器的类

第1节 Class类

Class被称为描述类的类,他也是一个类,从这个类中可以获取一个类的描述信息,比如获取类中属性的信息,方法的信息,构造器的信息等.

1. Class类没有构造方法,他的对象只能由系统创建,不能由程序员创建.
2. 一个类在 JVM 中只会有一个Class实例
3. 一个Class对象对应的是一个加载到JVM中的一个.class文件
4. 每个类的实例都会记得自己是由哪个 Class 实例所生成
5. 通过Class可以完整地得到一个类中的完整结构 
  • Class类的常见方法

方法名

功能说明

static Class forName(String name)

返回指定类名 name 的 Class 对象

Object newInstance()

调用缺省构造函数,返回该Class对象的一个实例

getName()

返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称

Class getSuperClass()

返回当前Class对象的父类的Class对象

Class [] getInterfaces()

获取当前Class对象的接口

ClassLoader getClassLoader()

返回该类的类加载器

Constructor[] getConstructors()

返回所有public修饰的构造方法

Constructor[] getDeclaredConstructors()

返回所有权限修饰的构造方法

Field[] getFields()

返回所有的public修饰的属性,包含父类

Field[] getDeclaredFields()

返回当前类的所有权限的属性(不包括父类)

Method[] getMethods()

返回所有的public修饰的方法(包括父类)

Method[] getDeclaredMethods

返回当前类的所有权限的方法(不包括父类)

Annotation[] getAnnotations()

返回所有注解(包括父类的注解,父类注解使用@Inherited修饰)

Annotation[] getDeclaredAnnotations()

返回当前类的注解

Type getGenericSuperclass()

获取父类的泛型类型

ParameterizedType

ParameterizedType是Type的子类getGenericSuperclass()方法返回的对象是ParameterizedType的实例,所以需要造型(向上强转)

Type[] getActualTypeArguments()

ParameterizedType中提供了getActualTypeArguments方法,返回泛型类型列表

  • 获取Class类对象的常见3种方式
1. 使用 Class.forName 静态方法
  Class<?> clazz = Class.forName("java.lang.String");
  System.out.println(clazz);//class java.lang.String
  
2. 使用类的.class 方法
	Class<String> clazz = String.class;
  System.out.println(clazz);//class java.lang.String
  
3. 使用实例对象的 getClass() 方法
	String s = new String("xxx");
  Class<? extends String> clazz = s.getClass();
  System.out.println(clazz);//class java.lang.String

第2节 Method类

描述方法的方法
  • Method类的常见方法

方法名

功能说明

int getModifiers()

权限修饰符

String getName()

方法名

Class<?>[] getParameterTypes()

方法的参数列表类型

Class<?>[] getReturnType()

返回值类型

Object invoke(Object obj, Object… args)

方法调用

第3节 Field类

描述属性的类
  • Field类的常见方法

方法名

功能说明

Object get(Object obj)

获取指定属性值

int getModifiers()

获取属性的权限修饰符

String getName()

获取属性的名称

void set(Object obj, Object value)

给指定对象的指定属性对象赋值

  • AccessibleObject的常见方法

方法名

功能说明

setAccessible(boolean flag)

设置权限,比如给私有属性赋值需要开启权限,否则不能赋值

第4节 Constructor

描述构造器的类
  • Constructor类的常见方法

方法名

功能说明

int getModifiers()

获取构造方法的权限修饰符

String getName()

获取构造方法的名称

Class<?>[] getParameterTypes()

方法的参数列表类型

T newInstance(Object… initargs)

构造方法

第5节 其他类和方法

  • ClassLoader类加载器
类加载器的功能:把类(class)装载进内存中
JVM在运行时会产生3个类加载器
1. 引导类加载器:用C++编写的,是JVM自带的类加载器,负责加载Java平台核心类库
2. 扩展类加载器:负责jre/lib/ext目录下的jar包或 –D java.ext.dirs 指定目录下的jar包装入工作库
3. 系统类加载器:负责java –classpath 或 –D java.class.path所指的目录下的类与jar包装入工作
  • 类加载的过程

反射看这一篇文章就够了_面试

 

  • 类加载器的获取
Class类中提供了获取类加载器的方法,所以要获取一个类的类加载器首先就是获取这个类的Class实例,然后调用类加载器方法获取类加载器
  • 类加载器中的重要方法
ClassLoader cl = TestDemo.class.getClassLoader();
//可以获取一个文件的输入流
InputStream in = cl.getResourceAsStream("db.properties");

第三章 动态代理

  • 代理模式的定义
代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用

1. 目标代理对象(源对象)
2. 代理对象
  • 静态代理的实现
  • 公共接口
public interface Boss {
    /*
        签字
     */
    void sign();
}
  • IT老板
/*
    目标代理类
*/
public class ItBoss implements Boss {
    @Override
    public void sign() {
        System.out.println("IT老板签字...");
    }
}
  • IT秘书
/*
  代理类
*/
public class Secretary implements Boss {

    /*
        目标代理对象
     */
    private Boss boss;

    public Secretary(Boss boss) {
        this.boss = boss;
    }

    @Override
    public void sign() {
        /*
            代理对象方法,调用目标代理对象方法
         */
        boss.sign();
    }
}
  • 静态代理的局限
静态代理设计,每一个代理类只能代理一个接口,如果在项目中需要对多个接口生成代理,这样程序开发中就会产生过多代理不易维护.
  • 动态代理的实现
  • JDK动态代理
JDK自带的动态代理类java.lang.reflect.Proxy实现动态代理
优点: 简单、方便
缺点: 只能代理接口,不能代理类
  • CGLIB动态代理
开源,功能强大高性能的代码生成库
优点: 可以代理类

目标代理类

public class ITBoss {
	//签名
	void sign() {
		System.out.println("IT老板签名...");
	}
}

测试

```java
 public class TestDemo01 {
 public static void main(String[] args) {//1.创建Enhancer对象
    Enhancer enhancer = new Enhancer();
    //2.指定被代理对象的Class
    enhancer.setSuperclass(ITBoss.class);
    //3.设置方法的拦截以及回调
    enhancer.setCallback(new MethodInterceptor() {
        /*
         * obj:被代理对象
         * method:原方法
         * args:方法入参
         * methodProxy:代理的方法
         */
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            return methodProxy.invokeSuper(obj, args);
        }
    });
    //创建代理对象
    ITBoss boss = (ITBoss) enhancer.create();
    System.out.println(boss);//指向的是代理对象com.hy.ITBoss$$EnhancerByCGLIB$$3e50753c@7506e922
    boss.sign();
}