Java中的反射机制基本运用

news/2024/5/19 6:39:39 标签: java, reflect, 反射

Java中的反射机制基本运用

看完反射可以了解一下注解
注解annotation:https://blog.csdn.net/Grantr/article/details/119973318

reflect_5">1、什么是反射reflect

反射java的动态机制,它允许将对象的实例化,方案的调用,属性的操作等从编码期确定转移到程序运行期确定。

反射能大大提高代码的灵活度。但同时也带来了更多的系统开销和较慢的运行效率,因此程序不能过度依赖反射



2、反射机制提供的功能

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象(实例化)
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时调用任意一个对象的方法——动态代理


3、反射->获取类对象

在开始之前创建一个实体类,用于测试反射机制

java">package reflect_text;

/**
 * 用于测试反射机制
 *
 * @author Akio
 * @Create 2021/8/14 10:37
 */
public class Person {
    private String name = "刘瑜澄";//设置初始值
    private int age = 22;

    public Person() {//无参构造
    }

    public Person(String name, int age) {//有参构造
        this.name = name;
        this.age = age;
    }

    public void sayHello() {//无参方法
        System.out.println(name + ":使用sayHello方法");
    }

    public void sayGoodBye() {//无参方法
        System.out.println(name + ":使用sayGoodBye方法");
    }

    public void say(String info) {//有参方法
        System.out.println(name + ":" + info);
    }

    public void say(String info, int sum) {//有参方法(重载say方法)
        for (int i = 0; i < sum; i++) {
            System.out.println(name + ":" + info);
        }
    }

    private void privateMethod() {//私有方法
        System.out.println(name + ":这是一个私有方法");
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

以上这个用于测试反射的实体类创建成功后,先学习反射中是如何获取类对象的。
反射的第一步就是要获取操作类的类对象,即一个Class的实例,JVM中每个被加载的类有且只有一个类对象与之对应,获取到这个类对象后我们就可以通过这个类对象来了解该类的一切信息(类名、有哪些方法、属性等等) 以便在程序运行期间通过反射机制进行相关操作

这里介绍三种获取类对象的方式:

  • (包名.)类名.class

    java">Class personClass = reflect_text.Person.class;
    Class intClass = int.class;
    

    这种方式最直接,但是由于是靠硬编码形式写死(编译期间已经确定),因此不够灵活。但是需要注意,基本类型(int\double等)只能通过这种方式获取类对象

  • Class.forName(String className)

    java">Class personClass = Class.forName("reflect_text.Person");
    Class stringClass = Class.forName("java.lang.String");
    

    这种方式较为常用,遵循运行期绑定。

  • 类加载器ClassLoader

    java">Class stringClass = ClassLoader.getSystemClassLoader().loadClass("java.lang.String");
    Class personClass = ClassLoader.getSystemClassLoader().loadClass("reflect_text.Person");
    

在这一节中介绍几个简单的方法:
java">getName()
获取类的完全限定名:包名.类名
getSimpleName()
仅仅获取类名
getMethods()
返回一个Method数组,获取class所表示的类的所有公开方法(包含从超类中继承的方法)

例子:

java">		Scanner scanner = new Scanner(System.in);
		Class cls = Class.forName(scanner.nextLine());//运行期绑定

        String name = cls.getName();//获取类的完全限定名:包名.类名
        System.out.println("完全限定名 = " + name);
        name = cls.getSimpleName();//仅获取类名
        System.out.println("仅类名 = " + name);

        Method[] methods = cls.getMethods();
        for (Method m : methods) {
            System.out.print(m.getName()+"\t");
        }

在这里插入图片描述


4、反射->利用无参构造实例化对象

Class类中提供了一个方法newInstance()来实例化,该方法要求此类必须具有无参构造器,它是通过无参构造器实例化对象的。

java">		Person person = new Person();

        //1获取要实例化的类的类对象
        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入类名:");
        Class cls = Class.forName(scanner.nextLine());

        /*
            通过Class提供的方法newInstance()来实例化
           	该方法要求此类必须具有无参构造器,它是通过无参构造器实例化对象的
         */
        Object obj = cls.newInstance();
        System.out.println("obj = " + obj);

在这里插入图片描述


5、反射->利用有参构造实例化对象

java">getConstructor()
//获取无参构造器,可以利用无参构造器实例化对象,但这个方法对于使用无参构造器实例化对象可有可无

getConstructor(类对象)
//通过类对象获取特定的构造器,该参数列表是根据特定构造器的参数列表类型来决定的,如
		getConstructor(String.class, int.class)
		即为调用Person类中两个参数的有参构造器
		public Person(String name, int age) {//有参构造
    		this.name = name;
    		this.age = age;
		}

举例

java">		//加载类对象
        Class cls = Class.forName("reflect.Person");
        //通过类对象获取特定的构造器
        Constructor c = cls.getConstructor(String.class, int.class);

        Object o = c.newInstance("流年", 21);//实例化
        System.out.println(o);

结果可知初始值已经被修改
在这里插入图片描述


6、反射->调用无参方法

java">getMethod(String MethodName)
获取类对象的MethodName方法,返回值类型为Method
invoke(Object object)
执行object对象的某方法

举例

java">		//一般调用方法的做法-------------------
        Person p = new Person();//实例化对象
        p.sayHello();//调用该对象方法

        //反射机制调用方法-----------------------
        //1、实例化对象
        Class cls = Class.forName("reflect_text.Person");
        Object o = cls.newInstance();

        //2、调用o的sayHello方案
        //2.1通过Class获取Person的sayHello方法
        Method method = cls.getMethod("sayHello");
        //2.2调用o的该方法
        method.invoke(o);//等效于一般方法中的o.sayHello()

可见两种操作均能达到一样的效果
在这里插入图片描述


7、反射->调用有参方法

java">getMethod(String MethodName, 类对象)
获取类对象的MethodName有参方法,并传入对应参数类型的类对象,返回值类型为Method

举例

java">		//一般调用有参方法------------------------
        Person p = new Person();
        p.say("七夕快乐~");
        p.say("七夕快乐~",3);

        //反射机制调用有参方法---------------------
        Class cls = Class.forName("reflect_text.Person");
        Object o = cls.newInstance();

        //调用say(String info)方法
        Method m1 = cls.getMethod("say", String.class);
        m1.invoke(o, "春节快乐~");

        //调用say(String info, int sum)
        Method m2 = cls.getMethod("say", String.class, int.class);
        m2.invoke(o,"春节快乐~",3);

通过结果可以看到,效果都是一样的
在这里插入图片描述


8、反射->访问私有方法

注意:反射访问私有的方法,但是会破坏类的封装性

java">getDeclaredMethod(String MethodName)
可以仅获取此类定义的所有方法,包含私有方法

setAccessible(boolean flag)
开启私有方法的访问权限

举例

java">		//正常情况下,在本类中不可以访问外部的私有方法
		//但在反射机制中可行
		Class cls = Class.forName("reflect_text.Person");
        Object o = cls.newInstance();

        Method method = cls.getDeclaredMethod("privateMethod");
        method.setAccessible(true);//打开访问权限
        method.invoke(o);

在这里插入图片描述


9、反射->类加载路径

加载资源时常用相对路径,之前学习的相对路径./由于运行环境不同,位置并非固定,因此实际开发中使用较少。
接下来介绍,在开发中常用的类加载路径
常用的路径通常为类的加载路径,有两个:
1:类对象.getResource()与当前类所处同一目录

2:类加载器.getResource()类加载路径,类的package定义中根包位置。

java">例如:有一个类:
package reflect_text;
public class WebServer{
     ……
}WebServer类中,当我们使用上述两种方式获取路径时他们的对应位置为:
WebServer.class.getResource()
当前WebServer所在的目录(编译后的class文件所在目录)

WebServer.class.getClassLoader().getResource()
则是在WebServer的包的最上级,即com包的上一级
java">package reflect_text;
public class ReflectDemo {
		File dir = new File(ReflectDemo.class.getResource(".").toURI());
        System.out.println("dir = " + dir);
        //dir = D:\ClassCode\JavaSE_API\out\production\JavaSE_API\reflect

        File dir2 = new File(ReflectDemo.class.getClassLoader().getResource(".").toURI());
        System.out.println("dir2 = " + dir2);
        //dir2 = D:\ClassCode\JavaSE_API\out\production\JavaSE_API
}

在这里插入图片描述


http://www.niftyadmin.cn/n/776403.html

相关文章

Java注解(annotation)简单上手

Java注解(annotation)简单上手 反射reflect&#xff1a;https://blog.csdn.net/Grantr/article/details/119966805 1、什么是注解&#xff1f; 注解就像商场的商品上都贴有自己的标签一样&#xff0c;它提供了关于这个商品的许多额外信息。你可以根据这些信息对其进行附加的…

Idea插件官网下载插件并安装

Idea插件官网下载插件并安装 为了解决Idea中Plugins功能转不出来&#xff0c;如下图 在开始操作之前可以先试试以下方法能不能使Idea成功加载Plugins功能&#xff0c;执行下图操作后&#xff0c;重启试试&#xff0c;一般都能转出来&#xff0c;如果不行&#xff0c;直接去官…

5- sem使用

概述&#xff1a; sem用于常用于资源管理、同步。 头文件&#xff1a;#include <semaphore.h> 接口&#xff1a; 【定义】 sem_t sem_rd; 【初始化】 int sem_init(sem_t *sem,int pshared,unsigned int value); //返回值&#xff1a;正常返回0 【等待信号量】 …

Java之SessionCookie

Java之Session&Cookie 1、会话管理 1.1 什么是会话管理&#xff1f; 将浏览器与Web服务器之间多次交互&#xff08;一次请求与响应&#xff09;当做一个整体来处理&#xff0c;并且将多次交互所产生的数据&#xff08;即状态&#xff09;保存下来。 1.2 为什么使用会话…

多线程编程、进程之经验贴

【多线程编程】 博主的几篇博客比较系统的讲解了多线程的知识点&#xff0c;主要有附了demo&#xff0c;便于理解实操。 链接&#xff1a;https://www.cnblogs.com/wuyepeng/p/9749956.html 【进程、线程调度】 宋宝华大神录得视频&#xff0c;讲解的还是很到位的&#xff0…

springboot项目接入天猫精灵

springboot项目接入天猫精灵 最近工作需要使用到天猫精灵的语音功能&#xff0c;大体是通过呼叫对应的“调用词”实现携带参数&#xff0c;然后调用我项目中的接口&#xff0c;以实现对应的业务。所以在此简单的记录下使用过程 实际上&#xff1a;天猫精灵的官方文档记录的也很…

虚拟文件系统几个好贴

其中最经典的还是内核示例&#xff1a; \kernel\linux\linux-4.4.39-cgel\samples\kobject-example.c \kernel\linux\linux-4.4.39-cgel\samples\kset-example.c 对着内核示例操作一遍&#xff0c;再看下面帖子&#xff0c;应该会有所感悟吧。 https://www.cnblogs.com/hell…

ubuntu系统添加idea快捷到菜单

ubuntu系统添加idea快捷到菜单 参考链接&#xff1a;来源 下载解压idea的压缩包后&#xff0c;我们可以通过bin目录下的idea.sh脚本来启动idea&#xff0c;不是很方便。 如何将其添加到菜单&#xff1f; 进入命令行&#xff0c;调整为root用户。进入/usr/share/applications/…