Java-14反射

Java-14反射

一、Java反射机制概述

  • Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。
  • 加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个 类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可 以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看 到类的结构,所以,我们形象的称之为:反射。
1.反射提供的功能
 	   在运行时判断任意一个对象所属的类
*      在运行时构造任意一个类的对象
*      在运行时判断任意一个类所具有的成员变量和方法
*      在运行时获取泛型信息
*      在运行时调用任意一个对象的成员变量和方法
*      在运行时处理注解
*      生成动态代理

二、理解Class类并获取Class实例

public final Class getClass()

1.Class类的常用方法
方法名功能
static Class forName(String name)返回指定类名 name 的 Class 对象
Object newInstance()调用缺省构造函数,返回该Class对象的一个实例
getName()返回此Class对象所表示的实体(类、接口、数组类、基本类型 或void)名称
Class getSuperClass()返回当前Class对象的父类的Class对象
Class [] getInterfaces()获取当前Class对象的接口
ClassLoader getClassLoader()返回该类的类加载器
Class getSuperclass()返回表示此Class所表示的实体的超类的Class
Constructor[] getConstructors()返回一个包含某些Constructor对象的数组
Field[] getDeclaredFields()返回Field对象的一个数组
Method getMethod(String name,Class … paramTypes返回一个Method对象,此对象的形参类型为paramType
public void test2() throws Exception{
    Class clazz = Person.class;
    //1.通过反射,创建Person类的对象
    Constructor constructor = clazz.getConstructor(String.class, int.class);

    Object obj = constructor.newInstance("Tom", 12);

    Person p = (Person) obj;
    System.out.println(obj.toString());
    //2.通过反射,调用对象指定的属性、方法
    //调用属性
    Field age = clazz.getDeclaredField("age");
    age.set(p,10);
    System.out.println(p);

    //调用方法
    Method show = clazz.getDeclaredMethod("show");
    show.invoke(p);

    //通过反射,可以调用Person类的私有结构的。比如:私有的构造器、方法、属性
    Constructor cons1 = clazz.getDeclaredConstructor(String.class);
    cons1.setAccessible(true);
    Person p1 = (Person)cons1.newInstance("Jerry");
    System.out.println(p1);

    //调用私有属性
    Field name = clazz.getDeclaredField("name");
    name.setAccessible(true);
    name.set(p1,"Tom");
    System.out.println(p1);


    //调用私有的方法
    Method showNation = clazz.getDeclaredMethod("showNation", String.class);
    showNation.setAccessible(true);
    showNation.invoke(p1,"中国");
}

三、类的加载与ClassLoader的理解

image-20210417211715143

  • 加载:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时 数据结构,然后生成一个代表这个类的java.lang.Class对象,作为方法区中类数据的访问 入口(即引用地址)。所有需要访问和使用类数据只能通过这个Class对象。这个加载的 过程需要类加载器参与。
  • 链接:将Java类的二进制代码合并到JVM的运行状态之中的过程。
    • 验证:确保加载的类信息符合JVM规范,例如:以cafe开头,没有安全方面的问题
    • 准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存 都将在方法区中进行分配。
    • 解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
  • 初始化:
    • 执行类构造器()方法的过程。类构造器()方法是由编译期自动收集类中 所有类变量的赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信 息的,不是构造该类对象的构造器)。
    • 当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类 的初始化。
    • 虚拟机会保证一个类的()方法在多线程环境中被正确加锁和同步。

image-20210417211847442

//1.获取一个系统类加载器
	ClassLoader classloader = ClassLoader.getSystemClassLoader();
  	System.out.println(classloader);
//2.获取系统类加载器的父类加载器,即扩展类加载器
	classloader = classloader.getParent();
	System.out.println(classloader);
3.获取扩展类加载器的父类加载器,即引导类加载器
	classloader = classloader.getParent();
	System.out.println(classloader);
//4.测试当前类由哪个类加载器进行加载
	classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader();
	System.out.println(classloader);

//5.测试JDK提供的Object类由哪个类加载器加载
	classloader = Class.forName("java.lang.Object").getClassLoader();
	System.out.println(classloader);
//*6.关于类加载器的一个主要方法:getResourceAsStream(String str):获取类路径下的指定文件的输入流
	InputStream in = null;
	in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties");
	System.out.println(in);

四、创建运行时类的对象

//1.根据全类名获取对应的Class对象
        String name = “atguigu.java.Person";
        Class clazz = null;
        clazz = Class.forName(name);
//2.调用指定参数结构的构造器,生成Constructor的实例
        Constructor con = clazz.getConstructor(String.class,Integer.class);
//3.通过Constructor的实例创建对应类的对象,并初始化类属性
        Person p2 = (Person) con.newInstance("Peter",20);
        System.out.println(p2);

五、获取运行时类的完整结构

方法功能
public Class[] getInterfaces()确定此对象所表示的类或接口实现的接口。
public Class getSuperclass()返回表示此 Class 所表示的实体(类、接口、基本类型)的父类的 Class。
public Constructor[] getConstructors()返回此 Class 对象所表示的类的所有public构造方法。
public Constructor[] getDeclaredConstructors()返回此 Class 对象表示的类声明的所有构造方法。
public Method[] getDeclaredMethods()返回此Class对象所表示的类或接口的全部方法
public Method[] getMethods()返回此Class对象所表示的类或接口的public的方法
public Field[] getFields()返回此Class对象所表示的类或接口的public的Field。
public Field[] getDeclaredFields()返回此Class对象所表示的类或接口的全部Field。
get Annotation(Class annotationClass)注解
getDeclaredAnnotations()注解

Constructor类中:

  • 取得修饰符: public int getModifiers();
  • 取得方法名称: public String getName();
  • 取得参数的类型:public Class[] getParameterTypes();

Method类中:

  • public Class getReturnType()取得全部的返回值
  • public Class[] getParameterTypes()取得全部的参数
  • public int getModifiers()取得修饰符
  • public Class[] getExceptionTypes()取得异常信息

Field方法中:

  • public int getModifiers() 以整数形式返回此Field的修饰符
  • public Class getType() 得到Field的属性类型
  • public String getName() 返回Field的名称。

六、调用运行时类的指定结构

1.调用指定方法
1.1 步骤
  1. 通过Class类的getMethod(String name,Class…parameterTypes)方法取得 一个Method对象,并设置此方法操作时所需要的参数类型。
  2. 之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中 传递要设置的obj对象的参数信息。
    • 1.Object 对应原方法的返回值,若原方法无返回值,此时返回null
    • 2.若原方法若为静态方法,此时形参Object obj可为null
    • 3.若原方法形参列表为空,则Object[] args为null
    • 4.若原方法声明为private,则需要在调用此invoke()方法前,显式调用 方法对象的setAccessible(true)方法,将可访问private的方法。
2.调用指定属性
  • public Field getField(String name) 返回此Class对象表示的类或接口的指定的 public的Field。 
  • public Field getDeclaredField(String name)返回此Class对象表示的类或接口的 指定的Field。
3.setAccessible
  • Method和Field、Constructor对象都有setAccessible()方法。
  • setAccessible启动和禁用访问安全检查的开关。
  • 参数值为true则指示反射的对象在使用时应该取消Java语言访问检查。
    • 提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被 调用,那么请设置为true。
    • 使得原本无法访问的私有成员也可以访问
  • 参数值为false则指示反射的对象应该实施Java语言访问检查

七、反射的应用:动态代理

1.原理

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

    public Object invoke(Object theProxy, Method method, Object[] params)
            throws Throwable{
        try{
            Object retval = method.invoke(targetObj, params);
// Print out the result
            System.out.println(retval);
            return retval;
        }catch (Exception exc){}
    }

2.创建被代理的类以及接口

3.通过Proxy的静态方法

    newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) 创建
    一个Subject接口代理
    RealSubject target = new RealSubject();
    // Create a proxy to wrap the original implementation
    DebugProxy proxy = new DebugProxy(target);
    // Get a reference to the proxy through the Subject interface
    Subject sub = (Subject) Proxy.newProxyInstance(
            Subject.class.getClassLoader(),new Class[] { Subject.class }, proxy);

4.通过 Subject代理调用RealSubject实现类的方法

String info = sub.say(“Peter", 24);
System.out.println(info);
2.步骤

1.创建一个实现接口InvocationHandler的类,它必须实现invoke方 法,以完成代理的具体操作。

public Object invoke(Object theProxy, Method method, Object[] params) 
throws Throwable{
try{
Object retval = method.invoke(targetObj, params);
// Print out the result
System.out.println(retval);
return retval;
}catch (Exception exc){}
}
package 反射07反射的应用0动态代理;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 动态代理的举例
 * 不要自己写下来 知道这个过程就行 理解动态代理就可以
 */

interface Human{
    String getBelief();

    void eat(String food);


}
//被代理类
class SuperMan implements Human{
    @Override
    public String getBelief() {
        return "I believe I can fly!";
    }


    @Override
    public void eat(String food) {
        System.out.println("我喜欢吃" + food);
    }
}

class HumanUtil{
    void method1(){
        System.out.println("==========通用方法一==========");

    }
    void method2(){
        System.out.println("==========通用方法二==========");

    }
}
/*
    要想实现动态代理,需要解决的问题?
        问题一:如何根据加载到内存中的被代理类,动态的创建一个代理类及其对象
        问题二:当通过代理类的对象调用方法时,如何动态的区调用被代理类中的同名方法
 */

class ProxyFactory{
    //调用此方法,返回一个代理类的对象,解决问题一
    public static Object getProxyInstance(Object obj){ //obj:被代理类的对象
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),handler);
    }
}

class MyInvocationHandler implements InvocationHandler{

    private Object obj;//赋值时,也需要使用被代理类对象进行赋值
    public void bind(Object obj){
        this.obj = obj;
    }
    //当我们通过代理类的对象,调用方法A时,就会自动的调用如下的方法:invoke()
    //将被代理类要执行的方法A的功能酒声明在invoke()中
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        HumanUtil util = new HumanUtil();
        util.method1();

        //method:即为代理类对象调用的方法,此方法也就作为了被代理类对象要调用的方法
        //obj:被代理类的对象
        Object returnValue = method.invoke(obj, args);
        //上述方法的返回值就作为当前类中的invoke()的返回值
        util.method2();

        return returnValue;
    }
}
public class ProxyTest {
    public static void main(String[] args) {
        SuperMan superMan = new SuperMan();
        //proxyInstance:代理类的对象
        Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
        //当通过代理类对象调用方法时,会自动的调用被代理类中同名的方法
        String belief = proxyInstance.getBelief();
        System.out.println(belief);
        proxyInstance.eat("四川麻辣烫");

        System.out.println("***********动态的体现************");
        NikeClothFactory nikeClothFactory = new NikeClothFactory();
        ClothFactory proxyClothFactory = (ClothFactory) ProxyFactory.getProxyInstance(nikeClothFactory);
        proxyClothFactory.produceCloth();


    }
}

package 反射07反射的应用0动态代理;

/**
 * 静态代理举例
 *
 * 特点:代理类和被代理类在编译期间,酒确定下来了
 */
interface ClothFactory{
    void produceCloth();
}

class ProxyClothFactory implements ClothFactory{
    private ClothFactory factory;//用被代理类对象进行实例化
    public ProxyClothFactory(ClothFactory factory){
        this.factory = factory;
    }
    @Override
    public void produceCloth() {
        System.out.println("代理工厂做一些准备工作");
        factory.produceCloth();
        System.out.println("代理工厂做一些后续的收尾工作");
    }
}

//被代理类
class  NikeClothFactory implements ClothFactory{
    @Override
    public void produceCloth() {
        System.out.println("Nike工厂生产一批运动服");
    }
}
public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被代理类的对象

        ClothFactory nike = new NikeClothFactory();
        //创建代理类的对象
        ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
        proxyClothFactory.produceCloth();
    }
}

    @Override
    public void produceCloth() {
        System.out.println("Nike工厂生产一批运动服");
    }
}
public class StaticProxyTest {
    public static void main(String[] args) {
        //创建被代理类的对象

        ClothFactory nike = new NikeClothFactory();
        //创建代理类的对象
        ClothFactory proxyClothFactory = new ProxyClothFactory(nike);
        proxyClothFactory.produceCloth();
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值