Java反射机制

1.Java反射机制概述

反射机制允许程序在执行期间借助于Reflection API取得任何类的内部信息,并且能够操作任意对象的内部属性及方法

  • 反射机制的功能:
    1. 在运行时判断任意一个对象所属的类
    2. 在运行时构造任意一个类的对象
    3. 在运行时判断任意一个类所具有的成员变量和方法
    4. 在运行时获取泛型信息
    5. 在运行时调用任意一个对象的成员变量和方法
    6. 在运行时处理注解
    7. 生成动态代理

2 理解Class类并获取Class的实例

package javabasis.chapter15;

import java.lang.reflect.Field;

public class Demo1 {
    public static void main(String[] args) throws Exception{
           
        String str="javabasis.chapter15.Person";
        Class clazz=Class.forName(str);
        System.out.println(clazz);
        Object obj=clazz.newInstance();
        Field field=clazz.getField("name");
        System.out.println(field);
        field.set(obj,"Mike");
        Object name=field.get(obj);
        System.out.println(name);
       

    }
}
class javabasis.chapter15.Person
public java.lang.String javabasis.chapter15.Person.name
Mike
  • 获取Class类的实例的方法
    1. 已知具体的类,通过类的class属性获取,最为可靠安全
    2. 已知某个类的实例,调用实例的getClass方法获取
    3. 已知一个类的全类名,且该类在类路径下,通过Class的静态方法forName获取
package javabasis.chapter15;

public class Demo2 {
    public static void main(String[] args) throws ClassNotFoundException {
        //1.已知具体的类
        Class clazz1=String.class;
        System.out.println(clazz1);

        //2.已知某个类的实例
        Class clazz2="hello".getClass();
        System.out.println(clazz2);

        //3.已知一个类的全类名
        Class clazz3=Class.forName("java.lang.String");
        System.out.println(clazz3);

    }
    
}
class java.lang.String
class java.lang.String
class java.lang.String
  • 可以有Class对象的类型
    1. class
    2. interface
    3. 数组
    4. 枚举
    5. 注解
    6. 基本数据类型
    7. void
package javabasis.chapter15;

import java.lang.annotation.ElementType;

public class Demo3 {
    public static void main(String[] args) {
        Class c1=Object.class;//类
        Class c2=Comparable.class;//接口
        Class c3=String [].class;//数组
        Class c4=int [][].class;//数组
        Class c5=ElementType.class;//注解
        Class c6=Override.class;//注解
        Class c7=int.class;//基本类型
        Class c8=void.class;//void类型
        Class c9=Class.class;//接口
        System.out.println(c1);
        System.out.println(c2);
        System.out.println(c3);
        System.out.println(c4);
        System.out.println(c5);
        System.out.println(c6);
        System.out.println(c7);
        System.out.println(c8);
        System.out.println(c9);
      
    }
    
}
class java.lang.Object
interface java.lang.Comparable
class [Ljava.lang.String;
class [[I
class java.lang.annotation.ElementType
interface java.lang.Override
int
void
class java.lang.Class

3. 类的加载

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

什么时候会发生类初始化

  • 虚拟机启动会先初始化main方法所在的类
  • new一个类的对象
  • 调用类的静态成员和静态方法 final常量除外
  • 使用了Java反射
  • 如果初始化一个类时其父类还没有被初始化。会先初始化父类

什么时候不会发生类的初始化

  • 通过子类访问父类的静态变量,不会导致子类初始化
  • 定义对象数组不会出发类的初始化
  • 引用常量不会出发初始化

类加载器的作用

  • 将class文件字节码内容读入内存,并将这些静态数据转化成方法区的运行时数据结构,然后在堆中生成一个代表这个类的java.lang.Class对象

4.创建运行时类的对象

创建类的对象: 使用Class对象的newInstance()方法

  • 类必须有一个无参构造器,没有无参构造器时需要明确类找的构造器,并传入相应的参数
  • 类的构造器的访问权限要够
package javabasis.chapter15;

public class Person {
    public String name;
    public int age;
    public Person(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
    public String toString()
    {
        return "name:"+name+"age: "+age;
    }
   
}
package javabasis.chapter15;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;

public class Demo1 {
    public static void main(String[] args) throws Exception{
           
        String str="javabasis.chapter15.Person";
        Class clazz=Class.forName(str);
     
        //Object obj=clazz.newInstance();//有无参构造器时可直接使用newInstance方法
       Constructor con=clazz.getConstructor(String.class,int.class);///没有无参构造器

       Person p=(Person)con.newInstance("Mike",20);
       System.out.println(p);
       
     
    }
}

5.调用运行时类的指定结构

通过反射调用类中的方法,由Method完成

  • 通过Class类的getMethod(…)方法取得一个Method对象
  • 之后使用Object invoke(Object obj,Object []args)进行调用
package javabasis.chapter15;

public class Person {
    public String name;
    public int age;
    public Person(String name,int age)
    {
        this.name=name;
        this.age=age;
    }
    public String toString()
    {
        return "name:"+name+"age: "+age;
    }
    public void say(String name,int age)
    {
        System.out.println("name: "+name+" age: "+age);
    }
     public void sayHello()
    {
        System.out.println("hello");
    }
    public Person()
    {

    }
   
}
package javabasis.chapter15;


import java.lang.reflect.Method;

public class Demo1 {
    public static void main(String[] args) throws Exception{
           
        String str="javabasis.chapter15.Person";
        Class clazz=Class.forName(str);//获取Person的Class实例
        Object obj=clazz.newInstance();//创建对象
        Method method=clazz.getMethod("say",String.class,int.class);
        //"say"是类里面的方法名  String.class,int.classs是say方法里面的参数类类型
        method.invoke(obj, "Mike",12);
        //obj是创建的对象  "Mike",12是需要传入的参数
        //如果是静态方法,obj可为null
        //如果方法没有参数,String.class,int.class  "Mike",12可没有
        Method method2=clazz.getMethod("sayHello");
       method2.invoke(obj);
    }
}
name: Mike age: 12

6. 动态代理

代理模式的思想是:使用一个代理对象将对象包装起来,然后使用该代理取代原来的对象,任何对原始对象的操作都要通过代理,代理对象决定是否以及何时将方法调用到原始对象上

动态代理是指客户通过代理类来调用其他对象的方法,并且是在程序运行时根据需要创建目标类的代理对象

动态代理步骤

  1. 创建一个实现接口 Invocationhandler类
  2. 创建被代理的类以及接口
  3. 通过调用Proxy的静态方法
  4. 通过Subject代理调用RealSubject的方法
package javabasis.chapter15;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDemo {
   
public static void main(String[] args) {
   Subject1 target=new RealSubject();
    MyInvocationHandler handler=new MyInvocationHandler();
    handler.setTarget(target);
    Subject1 sub=(Subject1)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
    sub.say("Tom11", 11);
}
      
}


interface Subject1{
    public void say(String name,int age);
}
class RealSubject implements Subject1{

    @Override
    public void say(String name, int age) {
      System.out.println("name:"+name+" age: "+age);

    }    
}

//创建一个实现接口InvocationHandler的类,必须实现invoke()方法
class MyInvocationHandler implements InvocationHandler{
    Object target;
    public void setTarget(Object target)
    {
        this.target=target;//传入被代理的目标对象
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(target);
        System.out.println("方法名:"+method.getName());
        Object result=method.invoke(target, args);
        return result;
    }
    
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-maRNWjeP-1616568406608)(Java反射机制.assets/image-20210324143156598.png)]

7. 动态代理与AOP

面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

AOP可以若干个代码段中的重复内容提取出来

package javabasis.chapter15.proxytest;

public interface Dog {
    void info();
    void run();
    void show(String name,int age);
}
package javabasis.chapter15.proxytest;

public class HuntingDog implements Dog {


    @Override
    public void info() {
     System.out.println("我是一只猎奇");
    }

    @Override
    public void run() {
       System.out.println("我跑得很快");
    }

    @Override
    public void show(String name, int age) {
     
       System.out.println("name :"+name+" age:"+age);
    }
    
}
package javabasis.chapter15.proxytest;

public class DogUtil {
    public void method1()
    {
        System.out.println("模拟通用方法1");

    }
    public void method2()
    {
        System.out.println("模拟通用方法2");

    }

}
package javabasis.chapter15.proxytest;
import java.lang.reflect.Proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {

    // 需要被代理的对象
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
         DogUtil du=new DogUtil();
         //执行DogUtil中的方法1
         du.method1();
         //以target作为主调来执行method方法
         System.out.println("方法名:"+method.getName());
         System.out.println("参数:");
          if(args!=null)
         {
             for(Object arg:args)
             System.out.println(arg);
         }
         Object result=null;
         if("show".equals(method.getName()))
          result=method.invoke(target, args);
         //执行DogUtil中的方法2
         du.method2();
      return result;
       
    }
   
}
    

在这里插入图片描述

package javabasis.chapter15.proxytest;
import java.lang.reflect.Proxy;


public class MyProxyFactory {
    public static Object getProxy(Object target)
    {
        MyInvocationHandler handler=new MyInvocationHandler();
        handler.setTarget(target);
       return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
     
    }
}
package javabasis.chapter15.proxytest;

public class TestProxy {
    public static void main(String[] args) {
        Dog target=new HuntingDog();
        Dog dog=(Dog)MyProxyFactory.getProxy(target);
        dog.info();
        dog.run();
        dog.show("Tom", 11);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodePanda@GPF

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值