Java 反射复习

目录

一.基本了解

1.作用

2.类的加载过程

3.类的加载器

4.类加载器的实例(通过jcbc.properties)

5.获取Class的实例方式(4种)

6. Class实例可以是那些结构

7. 通过反射创建运行时类的对象

8.测试 反射的动态性

9.获取运行类的完整结构

10.获取运行时类带泛型的父类

11.获取运行时类带泛型的父类的泛型

12.获取运行时类父类实现的接口

13.获取运行时类所在的包

14.获取运行时类声明的注解

二 获取运行时类的指定结构

1.获取运行时类的指定属性 

2.获取运行时类的指定方法

3.获取运行时类的指定构造器

三 静态代理和动态代理

1.静态代理

2.动态代理


一.基本了解

1.作用

像Java 在运行时结构不可变的语言 有了反射体现了动态的特性
​运行时获取任何类的内部信息,并能直接操作任意对象的内部属性及方法

进行动态代理

java.lang.reflect包下

框架 = 反射+注解+设计模式

2.类的加载过程

      类的加载  java.exe 指令执行过后将类的class文件读入内存
               并为之创建一个java.lang.Class对象 由类加载器完成此过程
      类的链接 将类的二进制数据合并到JRE中
      类的初始化  JVM负责对类进行初始化

程序经过javac.exe命令之后会生成多个或一个字节码文件,然后使用java.exe命令对某个字节码文件进行解释运行,相当于将某个字节码文件加载 到内存中。加载到内存中的类叫运行时类,此运行时类就作为Class的实例。

注:之前通过类造对象,类本身也是Class的对象

3.类的加载器

类的加载器
   Bootstrap引导类加载器 负责Java核心库
   Extension扩展类加载器 负责jre/lib/etx目录下的jar包
   System系统类加载器 负责java.class.path 的类与jar包装入工作,最常用的加载器
    @Test
    public void test6() {

        ClassLoader classLoader = T1.class.getClassLoader();
//        自定义类 系统类加载器
        System.out.println(classLoader);//sun.misc.Launcher$AppClassLoader@18b4aac2
        ClassLoader parent = classLoader.getParent();
//        系统类加载器getParent() 扩展类加载器
        System.out.println(parent);//sun.misc.Launcher$ExtClassLoader@28a418fc
        ClassLoader parent1 = parent.getParent();
//      扩展类加载器getParent();   null不代表没有 其上层是引导类加载器只不过获取不到
        System.out.println(parent1);//null
    }

4.类加载器的实例(通过jcbc.properties)
 

    //    实例1
    @Test
    public void ex1() throws Exception {
//        配置properties文件
        Properties properties = new Properties();
//        方式一          路径为当前module下
        FileInputStream fis = new FileInputStream("src//reflect//jdbc.properties");
        properties.load(fis);
        String pwd = properties.getProperty("pwd");
        System.out.println(pwd);
        fis.close();
//        方式二 用类加载器  文件路径为module下面的src下
        ClassLoader classLoader = Main.class.getClassLoader();
        InputStream resourceAsStream = classLoader.getResourceAsStream("reflect//jdbc.properties");
        properties.load(resourceAsStream);
        System.out.println(properties.getProperty("pwd"));

    }



5.获取Class的实例方式(4种)

    @Test
    public void test2() throws ClassNotFoundException {
//        1.调用运行时类的属性 .class
        Class<T1> clazz = T1.class;
//        2.通过运行时类的对象
        T1 t1 = new T1();
        Class clazz2 = t1.getClass();
//        3.(常用)调用Class的静态方法 Class.forName("reflect.T1") 全类名 抛异常 ClassNotFoundException
        Class<?> clazz3 = Class.forName("reflect.T1");
//       加载到内存中的运行时类,会缓存一定时间 在此时间之内 这三种方式 获取的是同一个运行时类
        System.out.println(clazz == clazz2);//true
        System.out.println(clazz == clazz3);//true
//        4.使用类的加载器 Main.class.getClassLoader(); Main此类的类名
        ClassLoader classLoader = Main.class.getClassLoader();
        Class clazz4 = classLoader.loadClass("reflect.T1");

    }

6. Class实例可以是那些结构

接口数组,基本数据类型,包括void都可以

    @Test
    public void test5() {
        Class b = int.class;
        Class a = int[].class;
        Class c = void.class;
        Class d = Class.class;
    }

7. 通过反射创建运行时类的对象

  @Test
    public void test8() throws Exception {
//        创建class的实例
        Class<T1> clazz = T1.class;
//        返回的是object 这里强转为T1
//        newInstance(); 创建对应的运行时类对象 
//        这里底层也是new出来的 调用空参的构造器(权限至少大于private)
        T1 t1 = (T1) clazz.newInstance();
    }
//    获取指定类的对象

    public Object getInstance(String classpath) throws Exception {

        Class clazz = Class.forName(classpath);
        return clazz.newInstance();
    }

8.测试 反射的动态性

    @Test
    public void ex2() throws Exception {
        String classPath = " ";
        int num = new Random().nextInt(3);//0,1,2
        switch (num) {
//            要有空参构造器
            case 0:
                classPath = "java.util.Date";
                break;
            case 2:
                classPath = "java.lang.Object";
                break;
            case 1:
//                注意路径是.不是/
                classPath = "reflect.Main";
                break;
        }
        Object obj = getInstance(classPath);
        System.out.println(obj);

    }

9.获取运行类的完整结构

 @Test
    public void test10() {
//        getFields() 获取当前运行时类及其父类声明为public访问权限的属性
//        getDeclaredFields(); 获取当前运行时类的所有属性
        Class clazz = T1.class;
        Field[] df = clazz.getDeclaredFields();
        for (Field f :
                df) {
//            1.权限修饰符 2代表public
            int modifiers = f.getModifiers();
//            toString() 返回String类型的权限修饰符
            System.out.print(Modifier.toString(modifiers) + "\t");
//            2.数据类型
            Class type = f.getType();
            System.out.print(type.getName() + "\t");
//            3.变量名
            String fName = f.getName();
            System.out.print(fName + "\t");
            System.out.println();
//            private	java.lang.String	name
//            private	int	age

        }
        System.out.println("!!!!!!!!!!!!!!!!");
//    获取方法的内部结构
        Method[] methods = clazz.getDeclaredMethods();
        for (Method m:
             methods) {
//          获取注解
            Annotation[] annotations = m.getAnnotations();
            for (Annotation a:
                 annotations) {
                System.out.println(a);
            }
//            获取方法权限
            System.out.print(Modifier.toString(m.getModifiers())+" ");
//            获取返回值类型
            System.out.print(m.getReturnType().getName()+"  ");
//            获取方法名
            System.out.print(m.getName());
//            获取形参列表
            System.out.print("(");
            Class<?>[] parameterTypes = m.getParameterTypes();
            int i =0;
            if (!(parameterTypes==null || parameterTypes.length==0)){
                for (Class p:
                     parameterTypes) {

                    System.out.print(p.getName()+"  args"+i+"  ");
                    i++;
                }
            }
            System.out.print(") ");
//            抛出的异常
            Class<?>[] exceptionTypes = m.getExceptionTypes();
            if (!(exceptionTypes == null || exceptionTypes.length==0)) {
                System.out.print("throws ");
                for (int j = 0; j < exceptionTypes.length; j++) {
                    System.out.print(exceptionTypes[i].getName()+" ");
                }
            }

            System.out.println();
        }
//        public java.lang.String  toString()
//        public java.lang.String  getName()
//        public void  setName(java.lang.String  args0  )
//        public void  show()
//        public int  getAge() throws java.lang.InstantiationException
//        public void  setAge(int  args0  )
//        private void  say()
    }

10.获取运行时类带泛型的父类

@Test
    public void test11(){
        Class clazz = Main.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        System.out.println(genericSuperclass);
    }

11.获取运行时类带泛型的父类的泛型

  @Test
    public void test12(){
        Class clazz = Main.class;
        Type genericSuperclass = clazz.getGenericSuperclass();
        ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
        Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
        System.out.println(actualTypeArguments[0].getTypeName());
    }

12.获取运行时类父类实现的接口

@Test
    public void test13(){
        Class clazz = Main.class;
//        clazz.getSuperclass()获取运行时类的父类  获取父类的接口getInterfaces()
        Class[] interfaces = clazz.getSuperclass().getInterfaces();
        for (Class c :
             interfaces) {
            System.out.println(c);
        }
    }

13.获取运行时类所在的包

  @Test
    public void test14(){
        Class clazz = Main.class;
        Package aPackage = clazz.getPackage();
        System.out.println(aPackage);
    }

14.获取运行时类声明的注解

 @Test
    public void test15(){
        Class clazz = Main.class;
        Annotation[] annotations = clazz.getAnnotations();
        for (Annotation a:
             annotations) {
            System.out.println(a);
        }
    }

二 获取运行时类的指定结构

1.获取运行时类的指定属性 

 @Test
    public  void test20() throws Exception {
        Class clazz = T1.class;
//        创建运行时类的对象
        T1 t =(T1) clazz.newInstance();
//        获取指定的属性 clazz.getField() 获取到的时声明为public的
//        getDeclaredField("age"); 可以获取private但需要setAccessible(true);
        Field age = clazz.getDeclaredField("age");
//        设置age是可访问的
        age.setAccessible(true);
//        给获取的属性赋值  set(Object obj 运行时类的对象, Object value 设置的值)
        age.set(t,12);
        System.out.println(t);
    }

2.获取运行时类的指定方法

 @Test
    public  void test21() throws Exception {
        Class clazz = T1.class;
//        创建运行时类的对象
        T1 t =(T1) clazz.newInstance();
//        获取指定的方法 参数1方法名  参数二 形参列表
        Method say = clazz.getDeclaredMethod("say", String.class);
//        设置age是可访问的
        say.setAccessible(true);
//        调用获取的方法  invoke(Object obj 运行时类的对象, Object value 设置的值)
//        invoke的返回值 即对应方法的返回值
        say.invoke(t,"para");
        System.out.println("!!!!!!");
//        调用静态方法    private static  void st()
        Method st = clazz.getDeclaredMethod("st");
        st.setAccessible(true);
//        方法没有返回值 填null也行 因为是静态的 所以newInstance();这一步时已经获取到方法了
        Object invoke = st.invoke(null);
        System.out.println(invoke);//null


    }

3.获取运行时类的指定构造器

 @Test
    public void test23() throws Exception {
        Class clazz = T1.class;

//        注意 int 和 Integer不一样
        Constructor dc = clazz.getDeclaredConstructor(String.class,int.class);
        dc.setAccessible(true);
//        用此构造器创建运行类的对象
        T1 t = (T1) dc.newInstance("luck", 22);
        System.out.println(t);
    }

三 静态代理和动态代理

1.静态代理

特点

被代理类和代理类在编译期间就确定下来了

代理类和被代理类要实现相同的接口

步骤1.创建普通的接口

interface ClothFactory{
    void produceCloth();
}

步骤2.创建被代理类

class NikeClothFactory implements ClothFactory{

    @Override
    public void produceCloth() {
        System.out.println("生产的Nike");
    }
}

步骤3.创建代理类

class ProxyCloth implements ClothFactory{
    private ClothFactory clothFactory;
//    初始话的时候拿被代理的对象进行初始化
    public ProxyCloth(ClothFactory clothFactory){
        this.clothFactory = clothFactory;
    }

    @Override
    public void produceCloth() {
        System.out.println("代理对象启动");
        clothFactory.produceCloth();
        System.out.println("代理结束");
    }
}

步骤4.测试

       

public class StaticProxyTest {
    public static void main(String[] args) {
//        1.声明被代理对象
        NikeClothFactory ncf = new NikeClothFactory();
//        2.声明代理类对象
        ProxyCloth pc = new ProxyCloth(ncf);
        pc.produceCloth();
//        代理对象启动
//        生产的Nike
//        代理结束

    }
}

2.动态代理

步骤1.创建普通的接口

interface  Human{
    String getBelief();
    void say(String hello);
}

步骤2.创建被代理类

//被代理类
class  SuperMan implements Human{

    @Override
    public String getBelief() {
        return "No fair in the word!";
    }

    @Override
    public void say(String hello) {
        System.out.println("I am SuperMan"+hello);

    }
}

步骤3.创建动态代理类(Proxy.newProxyInstance()这个方法需要步骤4)

//代理类
class ProxyFac {
    public  static Object getInstance(Object o) throws Exception {
        MyInvocationHandler h = new MyInvocationHandler();
//        将被代理类对象传进去
        h.bind(o);
//        o 被代理类的对象 借用此方法返回一个代理对象
//        public static Object newProxyInstance
//        (被代理类加载器, 被代理类实现的接口,InvocationHandler h)
//        调用方法生成一个代理类对象
       return Proxy.newProxyInstance(o.getClass().getClassLoader(),
                o.getClass().getInterfaces(),h);
    }
}

步骤4.创建一个类实现 InvocationHandler接口 (动态调用被代理类中的同名方法实现)

class MyInvocationHandler implements InvocationHandler{

    private  Object o;//method.invoke(o, args);赋值时 
//    需要使用被代理类的对象赋值 所以要把该对象传进来
    public void bind(Object o){
        this.o = o;
    }
    @Override
    //    当我们通过代理类的对象,调用方法A时,就会自动的调用如下方法
    // 将被代理类要执行的方法功能就声明在invoke方法中
    public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable {
//        invoke(Object proxy, 要调用的方法, 参数) 
    //    其方法的返回值即被代理类方法的返回值
        //        method即为代理类对象调用的方法 此
//        invoke(对象, 参数)
        Object invoke = method.invoke(o, args);
        return invoke;
    }
}

步骤5.测试

public class ProxyTest {
    public static void main(String[] args) throws Exception {
        SuperMan sm = new SuperMan();
//        为什么时是human 如果superMan的话,代理无意义
        Human hm =(Human) ProxyFac.getInstance(sm);
        System.out.println(hm.getBelief());
//         hm.say("好麻烦") 
//    此时就会进入我们重写的invoke method=say args="好麻烦"
        hm.say("好麻烦");
    }
}
输出结果
No fair in the word!
I am SuperMan好麻烦

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值