IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> JAVA之反射知识点整理 -> 正文阅读

[Java知识库]JAVA之反射知识点整理

概念

将类的各个组成部分封装成其他对象,这就是反射机制


好处

  1. 在程序运行过程中操作这些对象
  2. 可以解耦,提高程序的可扩展性

反射机制的含义及其功能

含义:

反射是被视为动态语言的关键,反射机制能够让程序在执行期间借助Reflection API获取任何类的内部信息,并能直接操作任意对象的内部属性和方法

功能:

在运行时判断任意一个对象所属的类

在运行时构造任意一个类的对象

在运行时判断任意一个类所具有的成员变量和方法

在运行时调用一个对象的成员变量和方法

生成动态代理


处理流程图

在这里插入图片描述


反射相关API

java.lang.Class : 代表一个类

java.lang.reflect.Method: 代表类的方法

java.lang.reflect.Field: 代表类的成员变量

java.lang.reflect.Constuctor: 代表类的构造方法


Class类

反射可以得到的信息: 某个类的属性,方法和构造器,某个类到底实现了哪些接口.
对于每个类而言,JRE都为其保留一个不变的Class对象,
一个Class对象包含了特定某个类的相关信息

Class本身也是一个类

Class对象只能由系统建立对象

一个类在JVM中只会有一个实例

一个Class对象对应的是一个加载到JVM中的一个.class文件(每个类在编译后会生成一个.class文件)

每个类的实例都会记得自己是由哪个Class实例生成的

通过Class可以完整得到一个类中的完整结构


获取class对象的方式

1.class.forName(“全类名”): 将字节码文件加载进内存,返回class对象

多用于配置文件,将类名定义在配置文件中。 读取文件,加载类
全类名: 包名.类名
会抛出ClassNotFoundException的异常

2.类名.class: 通过类名的属性class获取
多用于参数传递

3.对象.getClass(): getClass()方法在Object类中定义

多用于对象的获取字节码的方式


注意

同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪种方式获取的class对象都是同一个


演示

package test;

public class main1 {
    public static void main(String[] args) throws Exception {
        //1.类全名
       Class cls1= Class.forName("test.main1");
        System.out.println(cls1);
        //类名.class
        Class cls2=main1.class;
        System.out.println(cls2);
        //对象.getClass()
        main1 m=new main1();
        Class cls3=m.getClass();
        System.out.println(cls3);
              //比较这三个对象
        System.out.println(cls1==cls2);
        System.out.println(cls1==cls3);
        System.out.println(cls2==cls2);
    }
    
}

在这里插入图片描述


获取一个类的父类和接口

package reflect;

public class main {
    public static void main(String[] args) throws Exception {
    Class cl1=Class.forName("reflect.stu");//获取指定类的Class实例
        System.out.println(cl1.getName());
    Class cl2=cl1.getSuperclass();//获取父类
        System.out.println(cl2.getName());
        //获取当前类的所有接口
        Class[] interfaces=cl1.getInterfaces();
        for(Class c:interfaces)
            System.out.println(c.getName());
    }
}

在这里插入图片描述


获取一个类的构造方法

         //获取当前类的共有构造方法
        Constructor[] con=cl1.getConstructors();
        for(Constructor c:con)
        {
            //getModifiers():  获取构造方法修饰符  返回1代表public 返回2代表private
            //getName(): 获取方法名称
            System.out.println("修饰符:"+c.getModifiers()+"  构造方法:"+c.getName());

            //获取构造函数的参数,参数有几个数组里面元素就有几个
            Class[] paramClass=c.getParameterTypes();
           for(Class c1:paramClass)
           {
               System.out.println("构造方法: "+c.getName()+ "  参数类型: "+c1.getName());
           }
        }


        System.out.println("--------------------------------------------------------");

        //获取当前类的所有构造方法,包括共有和私有构造方法
        Constructor[] con1=cl1.getDeclaredConstructors();
        for(Constructor c:con1)
        {
            //getModifiers():  获取构造方法修饰符  返回1代表public 返回2代表private
            System.out.println("修饰符: "+c.getModifiers()+"  构造方法:"+c.getName());

            Class[] paramClass=c.getParameterTypes();
            for(Class c1:paramClass)
            {
                System.out.println("构造方法: "+c.getName()+ "  参数类型: "+c1.getName());
            }
        }

在这里插入图片描述


通过反射创建一个对象

       Class cl1=Class.forName("reflect.stu");
       //相当于调用Stu类的无参构造方法
       Object obj=cl1.newInstance();
       stu s=(stu)obj;
       System.out.println(s.name+"  "+s.age);

        System.out.println("-----------------------------");
        //指定一个有两个参数,一个为String,一个为int的共有构造函数
        Constructor c=cl1.getConstructor(String.class,int.class);
        stu s2=(stu)c.newInstance("小朋友",19);//实例化对象,相当于调用对应的有参构造函数
        System.out.println(s2.name+"  "+s2.age);

        System.out.println("-----------------------------");
        //通过反射机制,强制调用私有的构造方法
        Constructor c3=cl1.getDeclaredConstructor(int.class);
        //解除私有的封装,下面就可以对这个私有的方法进行强制调用
          c3.setAccessible(true);
        stu s5=(stu)c3.newInstance(100);
       System.out.println(s5.name+"  "+s5.age);

在这里插入图片描述


获取一个类的方法

获取到类的所有共有方法

         Class cl1=stu.class;
         //获取到类的所有共有方法
        Method[] mt=cl1.getMethods();
        for(Method m:mt)
        {
            System.out.println("方法名: "+m.getName());
            System.out.println("返回值类型: "+m.getReturnType());
            System.out.println("修饰符: "+m.getModifiers());

            //获取方法的参数类型,是一个数组,方法有几个参数,数据就有几个
            Class[] pcs=m.getParameterTypes();
            if(pcs!=null&&pcs.length>0)
            {
                for(Class pc:pcs)
                {
                    System.out.println("参数类型: "+pc.getName());
                }
            }
        }

在这里插入图片描述
在这里插入图片描述

获取到类的所有方法,包括共有和私有方法,不包括继承方法

         Class cl1=stu.class;
         //获取到类的所有共有方法
        Method[] mt=cl1.getDeclaredMethods();
        for(Method m:mt)
        {
            System.out.println("方法名: "+m.getName());
            System.out.println("返回值类型: "+m.getReturnType());
            System.out.println("修饰符: "+m.getModifiers());

            //获取方法的参数类型,是一个数组,方法有几个参数,数据就有几个
            Class[] pcs=m.getParameterTypes();
            if(pcs!=null&&pcs.length>0)
            {
                for(Class pc:pcs)
                {
                    System.out.println("参数类型: "+pc.getName());
                }
            }
        }

在这里插入图片描述


获取一个类的属性和包

获取类的所有公有属性,包含父类的公有属性

        stu s = new stu();
        Class c = s.getClass();
        //获取类的所有公有属性,包含父类的公有属性
        Field[] fs = c.getFields();
        for (Field f : fs)
        {
            System.out.println("修饰符: "+f.getModifiers());
            System.out.println("属性的类型: "+f.getType());
            System.out.println("属性的名称: "+f.getName());
        }

在这里插入图片描述

获取类的所有属性,包括私有,但不包括继承至父类的属性

        stu s = new stu();
        Class c = s.getClass();
        //获取类的所有属性
        Field[] fs = c.getDeclaredFields();
        for (Field f : fs)
        {
            System.out.println("修饰符: "+f.getModifiers());
            System.out.println("属性的类型: "+f.getType());
            System.out.println("属性的名称: "+f.getName());
        }

在这里插入图片描述

获取包名

    stu s = new stu();
        Class c = s.getClass();
        //获取类所在包的包名
        Package p=c.getPackage();
        System.out.println(p.getName());

在这里插入图片描述


反射机制调用指定方法

//注意:下面不论是反射调用show还是display方法,都调用obj对象的方法,obj对象实际上就是stu对象
      Class c=Class.forName("reflect.stu");
        Constructor con=c.getConstructor();//获取无参构造
        Object obj=con.newInstance();
      //调用display公有的无参方法,无返回值
        Method m=c.getMethod("display");
        m.invoke(obj);

        System.out.println("--------------------");

        //调用公有的有参有返回值的重载dispaly
        Method m1=c.getMethod("display",String.class);
        String ret=(String) m1.invoke(obj,"大忽悠");
        System.out.println("返回值打印:"+ret);

        System.out.println("--------------------");

        //调用私有无参无返回值的方法
        m=c.getDeclaredMethod("show");
        //解除私有的封装,下面可以强制调用私有的方法
        m.setAccessible(true);
        m.invoke(obj);

        System.out.println("--------------------");

        //调用私有有参有返回值的重载show方法
        m1=c.getDeclaredMethod("show",String.class);
        //解除私有的封装,下面可以强制调用私有的方法
        m1.setAccessible(true);
        ret=(String) m1.invoke(obj,"小朋友");
        System.out.println("返回值打印:"+ret);

在这里插入图片描述


反射机制调用指定属性

            Class c=Class.forName("reflect.stu");
            //反射创建一个对象
            stu s=(stu)c.newInstance();//默认调用无参构造
            //获取名称为name的属性
        Field f=c.getField("name");
        //将对象s的name属性设置为大忽悠
        f.set(s,"大忽悠");
        //获取对象s的name属性值
        String name=(String) f.get(s);
        System.out.println("name属性值: "+name);

      System.out.println("-----------------");

      //获取私有属性
      f=c.getDeclaredField("age");
      //解除私有的封装,下面就可以强制的调用这个属性
      f.setAccessible(true);
      //设置私有属性
      f.set(s,18);
      System.out.println("私有属性age值: "+f.get(s));

在这里插入图片描述


JAVA动态代理

在这里插入图片描述

其实动态代理很好理解,就是有些情况下我们不能直接对目标类进行一个访问,这个时候就需要中间商,也就是代理对象,我们通过Proxy里的newProxyInstance,指定目标对象的父类接口,它就会根据这个接口里的抽象方法,隐含的在底层实现一个代理类,这个时候肯定有人会问,那实现了代理类,里面重写的方法咋办?,,其实代理类并没有重写接口里的那些方法,是直接通过反射对目标对象里的方法进行的调用,在此基础之上,还可以添加一些额外的非业务逻辑代码,例如日志信息、验证啊啥的,下面是我话的一张草图,希望有助于大家理解。

在这里插入图片描述

举例:

一个java项目,有100个类,每个类有10个方法,一共1000个方法
现在要求在每个方法执行前后加上两句话

testDemo接口 :

package reflect;

public interface testDemo {
    void test1();
    void test2();
}

test实现testDemo接口:

package reflect;

public class test implements testDemo{
    @Override
    public void test1()
    {
        System.out.println("test1方法执行中...");
    }

    @Override
    public void test2() {
        System.out.println("test2方法执行中....");
    }
}

proxyDemo实现代理类接口:

package reflect;

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


public class proxyDemo implements InvocationHandler {
    //被代理的对象
    Object obj;
    proxyDemo( Object obj)
    {
        this.obj=obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(method.getName()+"开始执行");
        //执行指定代理对象的指定方法
        Object ret=method.invoke(obj,args);//不管代理对象的方法有无返回值都接收一下,然后返回
        System.out.println(method.getName()+"执行完毕");
        return ret;
    }
}

主函数:

package reflect;

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

public class main {
    public static void main(String[] args) throws Exception
    {
          test t=new test();
        InvocationHandler handler=new proxyDemo(t);
/*
第一个参数: 代理对象的类加载器
第二个参数: 被代理对象的接口
第三个参数: 代理对象
返回值: 成功被代理后的对象,返回的是Object,需要根据情况进行类型转换
* */
        testDemo t1=(testDemo) Proxy.newProxyInstance(handler.getClass().getClassLoader(), t.getClass().getInterfaces(),handler);
            t1.test1();
        System.out.println("----------------------");
            t1.test2();
    }
}

在这里插入图片描述

注意

如果一个对象想要通过Proxy.newProxyInstance方式被代理,那么这个对象的类一定要有相应的接口,就像本例中的testDemo接口和test实现接口的类一样


案例

写一个框架,可以帮助我们创建任意类的对象,并且执行其中任意的方法

实现:

  1. 配置文件
  2. 反射

步骤:

  1. 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
  2. 在程序中加载读取配置文件
  3. 使用反射技术来加载类文件进内存
  4. 创建对象
  5. 执行方法

代码:

main:

package reflect;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Properties;

public class main {
    public static void main(String[] args) throws Exception
    {
      //1.加载配置文件
        //1.1创建Properties对象
        Properties pro=new Properties();
        //1.2加载配置文件,转换为一个集合
        //1.2.1获取class目录下的配置文件
        ClassLoader classLoader=main.class.getClassLoader();
        InputStream is=classLoader.getResourceAsStream("pro.properties");
        pro.load(is);

        //2.获取配置文件中定义的数据
        String className=pro.getProperty("className");
        String methodName=pro.getProperty("methodName");

        //3.加载该类进内存
        Class cls=Class.forName(className);
        //4.创建对象
        Object obj=cls.newInstance();
        //5.获取方法对象
        Method method=cls.getMethod(methodName);
       //6.执行方法
        method.invoke(obj);
    }
}

stu类:

package reflect;

public class stu
{
    String name;
        public void show()
        {
            System.out.println("学生的姓名:"+name);
        }
}

pro.properties配置文件:

className=reflect.stu
methodName=show

在这里插入图片描述

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-04 19:22:40  更:2021-07-04 19:23:18 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/17 18:44:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码