JavaSE:反射

概述

Reflection(反射):是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法。

加载完类之后,在对内存的方法区中就产生了一个class类型的对象(一个类只有一个class对象),这个对象就包含了完整的类的结构信息。外面可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。


动态语言:

是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是在运行时代码可以根据某些条件改变自身结构。

主要动态语言:Object-C、C#、JavaScript、PHP、Python、Erlang

静态语言:

与动态语言相对的,运行时结构不可变的语言就是静态语言。如:Java、C、C++。

Java不是动态语言,但Java可以称为“准动态语言”。即Java由一定的动态性,外面可以利用反射机制、字节码操作获得类似动态语言的特性。


反射机制提供的功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

关于java.lang.Class类的理解

  1. 类的加载过程:
    1. 程序在经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)
    2. 接着使用java.exe命令对某个字节码文件进行解释运行,像用于将某个字节码文件加载到内存中,此过程就称为类的加载。
    3. 加载到内存中的类,外面就i称为运行时类,就作为Class的一个实例。
    4. 换句话说,Class的实例对应着一个运行时类。
    5. 加载到内存中的运行时类,会缓存一定的时间。在此时间内,我们可以通过不同的方式来获取此运行时类。


类的加载过程:
在这里插入图片描述




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


对比

@Test
public void test1() throws Exception{
    //通过new 的方式创建对象,使用对象调用public 修饰的属性和方法
    Person person = new Person("张三", 21);
    System.out.println(person);
    person.age = 18;
    System.out.println(person);
    person.show();

    System.out.println("******************* 反射 *******************");

    //使用反射
    //1.获取Class类的实例对象
    Class<Person> p = Person.class;
    //2.通过反射获取Person类的构造器
    Constructor<Person> constructor = p.getConstructor(String.class, int.class);
    //3.创建Person类对象
    Person person1 = constructor.newInstance("李四", 22);
    System.out.println(person1);

    //4.获取Person类属性
    Field age = p.getDeclaredField("age");
    age.set(person1,18);
    System.out.println(person1);

    //5.获取Person类的方法
    Method show = p.getDeclaredMethod("show");
    show.invoke(person1);

    //通过反射获取Person类中的私有构造器、私有属性、私有方法
    System.out.println("******************* 反射获取私有结构 *******************");
    Class<Person> p2 = Person.class;
    Constructor<Person> constructor1 = p2.getDeclaredConstructor(String.class);
    constructor1.setAccessible(true);

    Person person2 = constructor1.newInstance("王五");
    System.out.println(person2);
    Field name = p2.getDeclaredField("name");
    name.setAccessible(true);
    name.set(person2,"赵六");
    System.out.println(person2);
    Method getNation = p2.getDeclaredMethod("getNation", String.class);
    getNation.setAccessible(true);
    String str = (String) getNation.invoke(person2, "中国");
    System.out.println(str);

}

运行结果

在这里插入图片描述



Class类的实例化

@Test
public void test2() throws Exception{
    //Class类的实例化
    //方式一
    Class clazz = Person.class;

    //方式二:
    Person p = new Person("Tom", 28);
    Class clazz2 = p.getClass();


    //方式三:使用Class类的 静态方法
    Class clazz3 = Class.forName("Person");

    System.out.println( clazz == clazz2);
    System.out.println(clazz == clazz3);

    //方式四:通过类加载器加载
    ClassLoader loader = p.getClass().getClassLoader();
    Class clazz4 = loader.loadClass("Person");

    System.out.println(clazz == clazz4);

}



使用ClassLoader加载配置文件

    @Test
    public void test3() throws Exception{
        //使用ClassLoader加载配置文件
        Properties pro = new Properties();
        //方式一:此时默认路径在当前Module下
        FileInputStream fis = new FileInputStream("jdbc.properties");
        pro.load(fis);

        //方式二:此时当前默认路径在src下
//        ClassLoader loader = ReflectionTest.class.getClassLoader();
//        InputStream is = loader.getResourceAsStream("jdbc.properties");
//        pro.load(is);



        String username = pro.getProperty("username");
        String password = pro.getProperty("password");
        System.out.println("用户名为:" + username + ",密码为:" + password);
    }



使用反射获取运行时类的完整结构

属性

    //获取运行时类的属性结构及其内部结构
    @Test
    public void test(){
        Class clazz = Person.class;

        //获取所有类及其父类中声明为public的属性
        Field[] fields = clazz.getFields();

        for(Field f:fields){
            System.out.println(f);
        }
        System.out.println("*********************************************************");
        //获取类中的所有属性
        Field[] field = clazz.getDeclaredFields();
        for(Field f:field){
//            System.out.println(f);

            //获取属性的权限修饰符
            int modifier = f.getModifiers();
            System.out.print(Modifier.toString(modifier) + "\t");


            Class<?> type = f.getType();
            System.out.print(type.getName() + "\t");

            String name = f.getName();
            System.out.print(name);

            System.out.println();
        }

    }

方法

    @Test
    public void test2(){
        //获取运行时类的方法的内部结构
        Class clazz = Person.class;

        //获取所有类及其父类中声明为public的方法
//        Method[] methods = clazz.getMethods();
//        for (Method method:methods){
//            System.out.println(method);
//        }

        //获取当前类的说有方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method:methods){
            //获取权限修饰符
            int modifiers = method.getModifiers();
            System.out.print(Modifier.toString(modifiers) + "\t");

            //获取返回值类型
            Class<?> type = method.getReturnType();
            System.out.print(type.getName() + "\t");

            //获取方法名
            String name = method.getName();
            System.out.print(name+ "\t");


            //获取参数列表
            System.out.print("(");
            Class<?>[] parameterTypes = method.getParameterTypes();
            if (parameterTypes.length > 0){
                for (int i = 0; i < parameterTypes.length; i++) {
                    if (i == parameterTypes.length - 1){
                        System.out.print(parameterTypes[i].getName() + "\targs_" + i);
                        break;
                    }
                    System.out.print(parameterTypes[i].getName() + "\targs_" + i + ",");
                }
            }


            System.out.print(")");

            //获取异常
            Class<?>[] exceptionTypes = method.getExceptionTypes();
            if (exceptionTypes.length > 0){
                System.out.print("\tthrows\t");
                for (int i = 0; i < exceptionTypes.length; i++) {
                    if (i == exceptionTypes.length - 1){
                        System.out.print(exceptionTypes[i].getName());
                        break;
                    }
                    System.out.print(exceptionTypes[i].getName() + ",");

                }
            }
            System.out.println("{}");
        }

    }

构造器同上。



获取带泛型的父类以及其泛型

@Test
public void test3(){
    Class clazz = Person.class;
    //获取当前类的带泛型的父类
    Type type = clazz.getGenericSuperclass();
    //强转为ParameterizedType类
    ParameterizedType paramType = (ParameterizedType) type;
    //获取当前类的带泛型的父类的泛型
    Type[] args = paramType.getActualTypeArguments();
    for(Type arg:args){
        System.out.println(arg.getTypeName());
    }
}



获取运行时类的接口、所在包、注解

@Test
public void test4(){
    //获取运行时类的接口、所在包、注解
    Class clazz = Person.class;

    Class[] interfaces = clazz.getInterfaces();
    for (Class interfacess:interfaces){
        System.out.println(interfacess);
    }

    Package aPackage = clazz.getPackage();
    System.out.println(aPackage);

    Annotation[] annotations = clazz.getAnnotations();
    for (Annotation anno:annotations){
        System.out.println(anno);
    }
}



动态代理

代理设计模式的原理:

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

静态代理:特征是代理类和目标类对象的类都是在编译期间确定下来的,不利于程序的扩展。同时,每个代理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。最好可以通过一个代理类完成全部的代理功能。

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

动态代理相比静态代理的优点:

​ 抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中处理,这样,我们可以更灵活和统一的处理众多的方法。



动态代理代码示例:

//动态代理测试
public class ProxyTest {
    public static void main(String[] args) {
        ANTAClothFactory a = new ANTAClothFactory();
        clothFactory instance = (clothFactory) ProxyFactory.getInstance(a);
        instance.productCloth();
        String name = instance.getName("ANTA");
        System.out.println(name);
    }

}


interface clothFactory{

    void productCloth();

    String getName(String name);

}

class ANTAClothFactory implements clothFactory{

    @Override
    public void productCloth() {
        System.out.println("ANTA生产了一批衣服");
    }

    @Override
    public String getName(String name) {
        return name;
    }
}

//根据加载到内存中的被代理类,动态创建一个代理类以及其对象
//当通过代理类的对象调用方法时,如何动态的去调用被代理类中的同名方法。
class ProxyFactory{

    //调用此方法,返回一个代理类对象
    public static Object getInstance(Object obj){//obj-->被代理类
        MyInvocationHandler handler = new MyInvocationHandler();
        handler.bind(obj);
        ClassLoader loader = obj.getClass().getClassLoader();
        return Proxy.newProxyInstance(loader, 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 {
        //method即为代理类对象调用方法,此方法也就作为了被代理类对象要调用的方法
        //obj被代理类对象
        System.out.println("动态代理");
        return method.invoke(obj,args);
    }
}

运行结果

在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值