JAVA编程不能不知道的反射用法总结

目录
  • 下面对Java反射的基础知识进行说明和总结:
  • 总结

下面对Java反射的基础知识进行说明和总结:

首先定义一个MyBase类,其中有私有字段,也有公有字段。同时也有公有方法和私有方法。MyBase类示例如下:

package com.hwdev.demo;
/**
 * 基类示例
 * @author wangming
 */
public class MyBase {
    //公有字段
    public int version  = 1;
    //私有字段
    private String date = "2021-05-18" ;
    //公有方法
    public void say2(String msg){
	System.out.println("Hello " + msg);
    }
    //私有方法
    private String getData(){
        return this.date;
    }
}//加入Java开发交流君样:756584822一起吹水聊天

这里再定义一个Hello类,它继承自MyBase类,通过继承主要用于验证一下反射对于父类、子类的反射用法。

package com.hwdev.demo;
/**
 *
 * @author wangming
 */
public class Hello extends MyBase {
    public String author = "JackWang" ;
    public int version  = 1;
    private String company = "kzcloud" ;
    public void say(String msg){
	     System.out.println("Hello " + msg);
    }
    public void setAuthor(String author){
	    this.author = author;
    }
    public String getAuthor(){
        return this.author;
    }
    private int getVersion(){
        return this.version;
    }
}

关于Java反射,功能强大的就是可以通过字符串配置来动态从系统中调用方法或者修改其中某个对象的字段值,而Class.forName方法即可以通过传入类全路径字符串名称来获取对应的Class对象,非常的方便。另外通过getField方法和GetMethod方法可以获取指定字段和方法,并动态调用。

package com.hwdev.demo;
import java.lang.reflect.*;
import java.util.Arrays;
/**
 * 反射第一种用法 Class.forName
 * @author wangming
 */
public class ReflectDemo01 {
     public static void Test() {
        try
        {
            //通过字符串全路径类名查找Class
            Class helloC = Class.forName("com.hwdev.demo.Hello");
            //获取所有公有的字段数组,私有的无法获取
            Field [] fields = helloC.getFields();
            //打印字段数组内容//加入Java开发交流君样:756584822一起吹水聊天
            System.out.println(Arrays.toString(fields));
            //[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version]
            //实例化
            Object obj = helloC.newInstance();
            //获取特定字段,比遍历Field[]效率更高
            Field f = helloC.getField("author");
            if (f != null){
                //关闭安全检查,提高效率
                f.setAccessible(true);
                //获取字段author内容
                String author = (String)f.get(obj);
                System.out.println("author=" + author);
                //author=JackWang
            }
            //获取所有公有的方法数组,私有的无法获取
            Method [] methods = helloC.getMethods();
            //打印方法数组内容,子类等方法也可以获取到
            System.out.println(Arrays.toString(methods));
            //本类所有方法
            Method [] methods2 = helloC.getDeclaredMethods();
            //打印方法数组内容
            System.out.println(Arrays.toString(methods2));
            //获取特定方法,第二个参数String.class为say方法的参数类型
            //say(java.lang.String)
            Method m = helloC.getDeclaredMethod("say",String.class);
            if (m != null){
                //关闭安全检查,提高效率
                m.setAccessible(true);
                //获取字段author内容
                Object returnValue = m.invoke(obj, new Object[]{"Java"});
                //Hello Java
                if (returnValue!=null){
                    System.out.println("returnValue =" + returnValue);
                }
            }//加入Java开发交流君样:756584822一起吹水聊天
        }catch(ClassNotFoundException | SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

这里需要注意:xxx.getMethods()方法默认情况下,会返回本类、父类、父接口的公有方法,而xxx.getDeclaredMethods()返回本类的 所有方法,包括私有的方法。同理,反射API中其他getXXX和getDeclaredXXX的用法类似。

package com.hwdev;
import com.hwdev.demo.ReflectDemo01;
/**
 *
 * @author wangming
 */
public class Main {
    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        //反射第一种用法 Class.forName
        ReflectDemo01.Test();
    }
}

执行程序,输出的结果如下:

[public java.lang.String com.hwdev.demo.Hello.author, public int com.hwdev.demo.Hello.version, public int com.hwdev.demo.MyBase.version] author=JackWang [public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), public void com.hwdev.demo.MyBase.say2(java.lang.String), public final void java.lang.Object.wait() throws java.lang.InterruptedException, public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException, public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException, public boolean java.lang.Object.equals(java.lang.Object), public java.lang.String java.lang.Object.toString(), public native int java.lang.Object.hashCode(), public final native java.lang.Class java.lang.Object.getClass(), public final native void java.lang.Object.notify(), public final native void java.lang.Object.notifyAll()] [public void com.hwdev.demo.Hello.say(java.lang.String), public void com.hwdev.demo.Hello.setAuthor(java.lang.String), public java.lang.String com.hwdev.demo.Hello.getAuthor(), private int com.hwdev.demo.Hello.getVersion()] Hello Java

从输出结果上来看,Field [] fields = helloC.getFields();不但可以获取Hello类的公有字段,还可以获取到父类MyBase的公有字段:com.hwdev.demo.MyBase.version

而Method [] methods2 = helloC.getDeclaredMethods();则可以获取本类,即Hello类所有的方法,包括公有的方法和私有的方法。因此,Java反射可以访问类的私有字段和方法,从而暴露内部的信息,这也是Java反射有安全问题的原因。

由于Java方法支持重载,因此同名的方法可以存在多个,即参数不同,因此在用反射调用方法时,需要指定方法的参数类型,这样就可以明确调到的具体是哪个方法签名,如`Method m = helloC.getDeclaredMethod("say",String.class); `调用的是`public void com.hwdev.demo.Hello.say(java.lang.String) `。

除了可以用Class.forName来进行反射外,还可以通过如下方式来获取反射对象:

Hello hello = new Hello();
Class helloC = hello.getClass();
Field [] fields = helloC.getFields();
//
Class helloC = Hello.class;
Field [] fields = helloC.getFields();

下面介绍一下如何用Java反射修改私有字段和调用私有方法的示例:

package com.hwdev.demo;
import java.lang.reflect.*;
/**
 * 反射访问私有字段和方法
 * @author wangming
 */
public class ReflectDemo02 {
   //加入Java开发交流君样:756584822一起吹水聊天
     public static void Test() {
        try
        {
            //通过已有类查找Class
            Class helloC = Hello.class;
            //实例化
            Object obj = helloC.newInstance();
            //获取特定私有字段
            Field f = helloC.getDeclaredField("company");
            if (f != null){
                //私有必须开启
                f.setAccessible(true);
                //设置私有字段值
                f.set(obj, "newKZ");
                //获取字段author内容
                String fv = (String)f.get(obj);
                System.out.println("company=" + fv);
                //company=newKZ
            }
            //获取私有方法
            Method m = helloC.getDeclaredMethod("getVersion", null);
            if (m != null){
                //私有必须开启
                m.setAccessible(true);
                Object returnValue = m.invoke(obj, null);
                if (returnValue!=null){
                    //returnValue =1
                    System.out.println("returnValue =" + returnValue);
                }
            }
        }catch(SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

另外,Java反射可以获取注解信息,这个对于ORM框架来讲,用的非常多。

package com.hwdev.demo;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * 注解示例
 * @author wangming
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface ORMAnnotation {
    public String FieldName();
    public String FieldType();
}

其中,@Retention(RetentionPolicy.RUNTIME)表示注解可以在运行时通过反射访问。@Target(ElementType.FIELD) 表示这个注解只能用在字段上面。同理,可以把FIELD改为Type或者Method等。

package com.hwdev.demo;
import java.lang.annotation.Annotation;
import java.lang.reflect.*;
/**
 * 反射或者字段注解
 * @author wangming
 *///加入Java开发交流君样:756584822一起吹水聊天
public class ReflectDemo03 {
     public static void Test() {
        try
        {
            Class helloC = Class.forName("com.hwdev.demo.HelloAnnotation");
            Field[] fields = helloC.getDeclaredFields();
            for(Field f : fields){
                 //关闭安全检查,提高效率
                f.setAccessible(true);
                Annotation ann = f.getAnnotation(ORMAnnotation.class);
                if(ann instanceof ORMAnnotation){
                    ORMAnnotation ormAnn = (ORMAnnotation) ann;
                    System.out.println("FieldName=" + ormAnn.FieldName());
                    System.out.println("FieldType=" + ormAnn.FieldType());
                }
            }
        }catch(ClassNotFoundException | SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

执行此示例,则输出如下:

FieldName=f_author FieldType=varchar(50) FieldName=f_ver FieldType=int

再次,介绍一下如何用反射获取方法参数个数和类型,其中包含泛型的信息获取:

package com.hwdev.demo;
import java.util.ArrayList;
import java.util.List;
/**
 * 泛型示例
 * @author wangming
 */
public class GenericCls {
   protected List<String> myList = new ArrayList();
   public GenericCls(int size){
       for(int i = 0;i<size;i++){
           myList.add("item"+i);
       }
   }
   public  List<String> getList(){
      return this.myList;
   }
   public String getList(int idx){
      return this.myList.get(idx);
   }
}
package com.hwdev.demo;
import java.lang.reflect.*;
/**
 * 反射获取方法参数
 * @author wangming
 */
public class ReflectDemo05 {
     public static void Test() {
        try
        {
        //加入Java开发交流君样:756584822一起吹水聊天
            Class helloC = Class.forName("com.hwdev.demo.GenericCls");
            //构造函数调用
            Object obj = helloC.getConstructor(int.class).newInstance(3);
            Method method = helloC.getMethod("getList", int.class);
            Class<?> returnType = method.getReturnType();
            System.out.println("ReturnType = " + returnType.getName());
            Parameter[] params = method.getParameters();
            for(Parameter p : params){
                System.out.println("ParameterizedType = " + p.getParameterizedType());
                System.out.println("getModifiers = " + p.getModifiers());
                System.out.println("getName = " + p.getName());
                System.out.println("getType = " + p.getType());
            }
           //调用方法
           Object ret =  method.invoke(obj, new Object[]{2});
           System.out.println("ret = " + ret.toString());
            Method method2 = helloC.getMethod("getList", null);
            Type greturnType = method2.getGenericReturnType();
            System.out.println("getGenericReturnType = " + returnType.getName());
            if(greturnType instanceof ParameterizedType){
                ParameterizedType type = (ParameterizedType) greturnType;
                System.out.println("type = " + type.getTypeName());
                Type[] typeArguments = type.getActualTypeArguments();
                for(Type typeArgument : typeArguments){
                    Class typeArgClass = (Class) typeArgument;
                    System.out.println("typeArgClass = " + typeArgClass);
                }
            }
        }catch(ClassNotFoundException | SecurityException ex){
            ex.printStackTrace();
        }
        catch(Exception ex){
            ex.printStackTrace();
        }
    }
}

执行此示例,则输出如下:

R`eturnType = java.lang.String ParameterizedType = int getModifiers = 0 getName = arg0 getType = int ret = item2 getGenericReturnType = java.lang.String type = java.util.List<java.lang.String> typeArgClass = class java.lang.String

总结

本篇文章就到这里了,希望能给你带来帮助,也希望您能够多多关注我们的更多内容!

(0)

相关推荐

  • Java开发反射机制的实战经验总结

    目录 前言 一.创建Class的三种方式 二.反射获取类的所有属性和属性类型 三.反射动态修改类属性的注解值 四.反射获取类的方法及调用方式 总结 前言 我在实际项目当中有经常用到反射机制,故而将学会的反射用法做一些汇总笔记,当做以后复盘所用. 存在这样一个类: package com.example.demo; import com.alibaba.fastjson.annotation.JSONField; public class User { private String name; @

  • 详解Java编程中的反射在Android开发中的应用

    反射定义 "反射"(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为. 为何需要反射 反射带来的好处包括: 在运行时检测对象的类型. 动态构造某个类的对象. 检测类的属性和方法. 任意调用对象的方法. 修改构造函数.方法.属性的可见性. 反射方法Method getDeclaredMethod方法 声明如下: public Method getDeclaredMethod(String name, Class<?>... parameterTypes)

  • 实例讲解Java编程中数组反射的使用方法

    什么是反射 "反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为."这个概念常常会和内省(Introspection)混淆,以下是这两个术语在Wikipedia中的解释: 内省用于在运行时检测某个对象的类型和其包含的属性: 反射用于在运行时检测和修改某个对象的结构及其行为. 从它们的定义可以看出,内省是反射的一个子集.有些语言支持内省,但并不支持反射,如C++. 内省示例:instanceof 运算符用于检测某个对象是否属于特定的类. if (obj inst

  • Java编程反射机制用法入门与实例总结

    本文实例讲述了Java编程反射机制用法.分享给大家供大家参考,具体如下: 前言:反射:动态获取类 (字节码文件 如本篇中的Person.class),并对其成员进行运行.反射在Android应用层的开发中可能遇到会稍微少一点,但对于想打通底层的小伙伴来说,必须要熟练掌握运用. 实体类 Person.java package com.sunwenou.reflect;// 包名 public class Person { private String name; private int age;

  • Java的枚举,注解和反射(二)

    目录 反射 什么是反射? 反射的用途 反射的具体作用 反射的主要API Class类 总结 反射 什么是反射? 反射是指在程序运行期间,可以通过Reflection Api提供方法可以获取任何类的内部的信息,并能直接操作任意类的方法和属性.反射被视为动态语言的关键. //在反射之前可以做的事情 @Test public void Test1() { //创建Person类的对象 Person person = new Person("name", 78); //通过对象调用其内部的方法

  • JAVA编程不能不知道的反射用法总结

    目录 下面对Java反射的基础知识进行说明和总结: 总结 下面对Java反射的基础知识进行说明和总结: 首先定义一个MyBase类,其中有私有字段,也有公有字段.同时也有公有方法和私有方法.MyBase类示例如下: package com.hwdev.demo; /** * 基类示例 * @author wangming */ public class MyBase { //公有字段 public int version = 1; //私有字段 private String date = "20

  • Java编程中的vector类用法学习笔记

    java.util.vector提供了向量类(vector)以实现类似动态数组的功能.在Java语言中没有指针的概念,但如果正确灵活地使用指针又确实可以大大提高程序的质量.比如在c,c++中所谓的"动态数组"一般都由指针来实现.为了弥补这个缺点,Java提供了丰富的类库来方便编程者使用,vector类便是其中之一.事实上,灵活使用数组也可以完成向量类的功能,但向量类中提供大量的方法大大方便了用户的使用. 创建了一个向量类的对象后,可以往其中随意插入不同类的对象,即不需顾及类型也不需预先

  • 详解Java编程中super关键字的用法

    通过用static来定义方法或成员,为我们编程提供了某种便利,从某种程度上可以说它类似于C语言中的全局函数和全局变量.但是,并不是说有了这种便利,你便可以随处使用,如果那样的话,你便需要认真考虑一下自己是否在用面向对象的思想编程,自己的程序是否是面向对象的. 好了,现在开始讨论this&super这两个关键字的意义和用法.在Java中,this通常指当前对象,super则指父类的.当你想要引用当前对象的某种东西,比如当前对象的某个方法,或当前对象的某个成员,你便可以利用this来实现这个目的,当

  • 关于Java中你所不知道的Integer详解

    前言 本文主要给大家介绍了关于Java中Integer的相关内容,分享出来供大家参考学习,下面话不多说了,来一起看看详细的介绍吧. 实参形参 前些天看到朋友圈分享了一片文章<Java函数的传参机制--你真的了解吗?> 有些触发,之前也研究过Java的Integer,所以写下本文,希望对你有所帮助. 交换 首先来看一个示例. 请用Java完成swap函数,交换两个整数类型的值. public static void test() throws Exception { Integer a = 1,

  • Go语言中你所不知道的位操作用法

    前言 因为之前一直忽略的就是所有语言中关于位操作,觉得用处并不多,可能用到也非常简单的用法,但是其实一直忽略的是它们的用处还是非常大的,下面先回顾一下位操作符的基础 位操作符 与操作:& 1 & 1 = 1 1 & 0 = 0 0 & 1 = 0 0 & 0 = 0 或操作:! 1 | 1 = 1 1 | 0 = 1 0 | 1 = 1 0 & 0 = 0 异或:^ 1 ^ 1 = 0 1 ^ 0 = 1 0 ^ 1 = 1 0 ^ 0 = 0 左移:<

  • 基于switch你可能不知道的一些用法

    One:int i = 0; switch (i) {     case 0:         Console.WriteLine("0");     case 1:         Console.WriteLine("1");         break; } //在这里,想让i==0的时候执行//Console.WriteLine("0"),然后"fall through"到下层执行Case 1.//但是在C#中是不允许

  • Java编程接口回调一般用法代码解析

    接口回调是指:可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法.实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调. Java接口回调一般用法:实现接口实际上和继承抽象类类似,只不过继承是在类的层面上操作,接口是在方法和常量集合的层面上操作,接口比抽象类更抽象.更简洁.可以把实现接口看成继承特定的一个或多个方法以及一些常量,关于接口的具体规则这里不赘述. 为什么要使用接口和抽

  • Java编程BigDecimal用法实例分享

    Java中提供了大数字(超过16位有效位)的操作类,即 java.math.BinInteger 类和 java.math.BigDecimal 类,用于高精度计算. 其中 BigInteger 类是针对大整数的处理类,而 BigDecimal 类则是针对大小数的处理类. BigDecimal 类的实现用到了 BigInteger类,不同的是 BigDecimal 加入了小数的概念. float和Double只能用来做科学计算或者是工程计算;在商业计算中,对数字精度要求较高,必须使用 BigIn

  • java编程scanner类用法示例

    在Eclipse中编写程序时,如果我们的变量是需要手动输入的时候,我们就可以用到scanner类了. Scanner类,这是一个用于扫描输入文本的新的实用程序.由于任何数据都必须通过同一模式的捕获组检索或通过使用一个索引来检索文本的各个部分.于是可以结合使用正则表达式和从输入流中检索特定类型数据项的方法.这样,除了能使用正则表达式之外,Scanner类还可以任意地对字符串和基本类型(如int和double)的数据进行分析.借助于Scanner,可以针对任何要处理的文本内容编写自定义的语法分析器.

随机推荐