Java反射机制

本文参考自
https://www.sczyh30.com/posts/Java/java-reflection-1/
https://www.zhihu.com/question/24304289/answer/147529485

一、 什么是反射(Reflection)

反射是java的一种特性,运行中的程序可以用这个特性获取自身的一些信息,也可以用它来操作类或者对象的属性

官方文档中对反射的解释是:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

简单来说就是我们可以在运行时获得程序或程序集中每一个类型的成员和成员的信息。程序中一般的对象的类型都是在编译期就确定下来的,而 Java 反射机制可以动态地创建对象并调用其属性,这样的对象的类型在编译期是未知的。

当我们使用java IDE(例如eclipse、idea等)时,在类名后面输入“.”时,IDE会自动列出该类的所有属性用于参考,这就是运用了反射机制,IDE类属性提示并没有运行我们的程序,而是用反射将被提示的类动态的加载进了IDE本身的运行环境中去并获取它的属性。

通常我们在代码中使用new objA()创建类objA的实例后,在编译时就已经将该对象加载进JVM中,以供后面的程序调用,但是如果程序运行过程中用户突然指定需要调用某个类,而这个类之前却没有被加载到JVM中,这时候不可能让程序停下来 让程序员中途写段代码new一下,这时候就是反射机制发挥作用的时候,可以在程序运行过程中动态地把类加载进JVM中。
例如项目底层有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类,这时com.java.dbtest.myqlConnection,com.java.dbtest.oracleConnection这两个类我们都要使用,但是我们又不想提前将这两个类都加载进JVM中去,这时候就可以用反射机制动态的加载它们:

Class tc = Class.forName("com.java.dbtest.TestConnection");
//驱动的类名可以由用户给出,也可以从配置文件(如xml文件等)中读取

另一个反射的例子就是web项目中的xml配置文件

<servlet>
      <servlet-name>webSpring</servlet-name>
      <servlet-class>
         org.springframework.web.servlet.DispatcherServlet
      </servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>

   <servlet-mapping>
      <servlet-name>webSpring</servlet-name>
      <url-pattern>/</url-pattern>
   </servlet-mapping>

其中<servlet>标签规定了一个叫webSpring的sevlet,其请求处理类为org.springframework.web.servlet.DispatcherServlet,而<servlet-mapping>标签告诉程序匹配到“/”的url交给名叫webSpring这个servlet来处理。
当web核心程序运行时,根据收到的请求,就会去找xml文件配置中的servlet来处理该请求,而此时就需要动态地将xml文件中规定的servlet请求处理类加载进JVM中去

二、反射的基本运用
1.获取Class对象
  • 使用 Class 类的 forName 静态方法:

    public static Class<?> forName(String className){...}
    
    // 在数据库中加载驱动类
    Class db_class = Class.forName(driver);
    
  • 直接获取一个对象的class

    Class<?> klass = int.class;
    Class<?> classInt = Integer.TYPE;
    
  • 调用对象的getClass方法

    Class<?> obj_class = obj.getClass();
    
2.判断是否是某个类的实例

一般地,我们用 instanceof 关键字来判断是否为某个类的实例。同时我们也可以借助反射中 Class 对象的 isInstance() 方法来判断是否为某个类的实例,它是一个 native 方法:

public native boolean isInstance(Object obj);
  • 示例
    Person pobj = new Person()
    Class<?> pclass = pobj.getClass();
    pobj.instanceof(Person)
    pclass.isInstance(pobj)
    
3.创建实例
  • 使用Class对象的newInstance()方法来创建对应类的实例

    Class<?> s_class = String.class;
    Object str = s_class.newInstance();
    
  • 先通过Class对象获取指定的Constructor对象,再调用Constructor对象的newInstance()方法来创建实例。这种方法可以用指定的构造器构造类的实例。

    //获取String所对应的Class对象
    Class<?> s_class = String.class;
    //获取String类带一个String参数的构造器
    Constructor constructor = s_class.getConstructor(String.class);
    //根据构造器创建实例
    Object obj = constructor.newInstance("23333");
    System.out.println(obj);
    
4.获取方法
  • getDeclaredMethods 方法返回类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法

    public Method[] getDeclaredMethods() throws SecurityException
    
  • getMethods 方法返回某个类的所有公用(public)方法,包括其继承类的公用方法。

    public Method[] getMethods() throws SecurityException
    
  • getMethod 方法返回一个特定的方法,其中第一个参数为方法名称,后面的参数为方法的参数对应Class的对象。

    public Method getMethod(String name, Class<?>... parameterTypes)
    
  • 示例

    public class test1 {
    	public static void test() {
            Class<?> p = Person.class;
            
            //获取Person类中的sleep方法
            Method mtd = p.getMethod("sleep", Time.class, Bed.class, String.class);
        }
    }
    class Person{
    	...
    	public void sleep(Time tim, Bed bd, String context){...}
    }
    
    
    
5.获取类的成员变量信息
  • getFiled:访问公有的成员变量
  • getDeclaredField:所有已声明的成员变量,但不能得到其父类的成员变量

getFileds 和 getDeclaredFields 用法同Method。

6.调用方法

使用反射机制从类中获取了一个方法后,我们就可以用 invoke() 方法来调用这个方法。invoke 方法的原型为:

public Object invoke(Object obj, Object... args)
        throws IllegalAccessException, IllegalArgumentException,
           InvocationTargetException

示例

public class test1 {
		public static void test() {
	        Class<?> p = Person.class;
	        Object pObj = p.newInstance();
	        
	        //获取Person类中的sleep方法
	        Method mtd = p.getMethod("sleep", Time.class, Bed.class, String.class);
			
			//执行获取到的方法
	        mtd.invoke(pObj, time_1, bed_1, "good luck");
	        
	    }
  	}
  class Person{
		...
		public void sleep(Time tim, Bed bd, String context){...}
	}
	
三、 使用反射的注意事项
  • 反射会额外消耗一定的系统资源,如果不需要动态地创建一个对象,那么就不需要用反射。
  • 反射调用方法时可以忽略权限检查,可以利用这个特性来获取到一些类的私有属性和方法,但也可能破坏封装性而导致安全问题。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Go语言(也称为Golang)是由Google开发的一种静态强型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。
Go语言(也称为Golang)是由Google开发的一种静态强型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值