精华内容
下载资源
问答
  • 利用java反射原理调用方法时,常先需要传入方法参数数组才能取得方法。该方法参数数组采用动态取得的方式比较合适
  • 主要介绍了详解java反射机制(含数组参数)的相关资料,希望通过本文能帮助到大家,让大家理解掌握这部分内容,需要的朋友可以参考下
  • 在自定义mybatis框架的过程中,在使用注解来进行配置sql语句时,就遇到了一些关于获取返回值类型的小问题。比如说方法 publIc User getOne(int id);的返回值类型是User;public List< User > getAll();的...

    最近在学mybatis的时候,自己根据参考资料自定义了一个简单的mybatis框架,期望能够简单实现对数据库操作的增删查改功能。在自定义mybatis框架的过程中,在使用注解来进行配置sql语句时,就遇到了一些关于获取返回值类型的小问题。比如说方法 publIc User getOne(int id);的返回值类型是User;public List< User > getAll();的返回值类型是List< User >,但是我们在进行mybatis框架书的时候,通过注解配置时,我们获取的返回值类型需要获取的是实体类的全限定类名,也即是我们实际上需要获取的是 List< User >中的实体类User即可。在我们实际的应用中,为了便于代码的通用性以及复用性,我们习惯使用泛型,比如public List< T> getAll()和public Map<T,V> getAll();这两个方法,就是使用了泛型,是代码更加通用。那么我们首先来了解一下泛型的原理:
    定义:把类型明确的工作推迟到创建对象或调用方法的时候才去明确的特殊的类型。
    Java泛型设计原则:只要在编译时期没有出现警告,那么运行时期就不会出现ClassCastException异常.
    参数化类型:把类型当作是参数—样传递;<数据类型>只能是引用类型。
    相关术语:
    List< E >中的E称为类型参数变量。
    List< Integer >中的Integer称为实际类型参数。
    整个称为List< E >泛型类型。
    整个List< Integer >称为参数化的类型ParameterizedType。

    不过也就是因为使用了泛型,导致我们在通过反射获取返回值了类型的时候会更加麻烦一些。为了更加方便学习通过反射获取返回值类型以及参数化的实际参数类型,我特意写了几个小案例进行测试讲解。
    1.首先创建用于测试的各个类,在这些类中我们不需要写额外的代码实现,只是用于测试获取返回值类型即可。

    package dao;
    
    import java.util.List;
    
    import entity.User;
    
    /**
     * @author 陌意随影
     TODO :UserDao测试接口
     *2020年7月26日  下午10:58:04
     */
    public interface UserDao {
     
    /**
     * 获取所有用户
     * @return 返回所有用户的集合
     */
    	public List<User> getAll();
    /**
     * 通过指定的id获取一个用户对象
     * @param id: 指定的id
     * @return 返回一个User
     */
    	public User getOne(int id);
    
    }
    
    
    package dao;
    
    import java.util.Map;
    
    /**
     * @author 陌意随影
     TODO :学生dao测试类
     *2020年7月26日  下午11:02:10
     */
    public interface StudentDao<T,V> {
    	/**
    	 * 获取所有对象
    	 * @return 返回一个map
    	 */
    	public Map<T,V> getAll();
    	/**
    	 * 获取一个T对象
    	 * @return 返回T
    	 */
    	public T getT();
    	/**
    	 * 获取一个V对象
    	 * @return 返回V
    	 */
    	public	V getV();
    
    }
    
    
    package entity;
    
    /**
     * @author 陌意随影
     TODO :测试实体类
     *2020年7月26日  下午11:05:27
     */
    public class Cat {
    
    }
    
    
    package entity;
    
    /**
     * @author 陌意随影
     TODO :测试实体类
     *2020年7月26日  下午11:05:10
     */
    public class Dog {
    
    }
    
    
    package entity;
    
    /**
     * @author 陌意随影
     TODO :测试用户类
     *2020年7月26日  下午10:59:22
     */
    public class User {
    
    }
    
    

    然后建立相关的测试类:

    package test;
    
    
    import org.junit.jupiter.api.Test;
    
    class StudentDaoTest {
    
    	@Test
    	void testGetAll() {
    	}
    
    	@Test
    	void testGetT() {
    	}
    
    	@Test
    	void testGetV() {
    	}
    
    }
    
    
    package test;
    
    
    import org.junit.jupiter.api.Test;
    
    class UserDaoTest {
    
    	@Test
    	void testGetAll() {
    		
    	}
    
    	@Test
    	void testGetOne() {
    	}
    
    }
    
    

    这些类的具体目录结构为:
    在这里插入图片描述
    2.建立测试类进行测试
    2.1首先测试UserDao接口

    package test;
    
    
    import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    import org.junit.jupiter.api.Test;
    
    class UserDaoTest {
    
    	@Test
    	void test() throws Exception {
    	 //根据UserDao接口的全限定类名通过反射获取该接口的字节码
    	Class<?> userDaoClass = Class.forName("dao.UserDao");
    	//获取UserDao所有的方法
    	Method[] methods = userDaoClass.getMethods();
    	for(Method method: methods) {
    		//获取方法的名称
    		String methodName = method.getName();
    		//判断是否是UserDao中的getAll()或者getOne(int id)方法,
    		if(methodName.startsWith("get")) {
    			//返回一个Type对象,表示由该方法对象表示的方法的正式返回类型。
    			//比如public List<User> getAll();那么返回的是List<User>
    		  Type genericReturnType = method.getGenericReturnType();
    		  //获取实际返回的参数名
    		  String returnTypeName = genericReturnType.getTypeName();
    		  System.out.println(methodName+"的返回参数是:"+returnTypeName);
    		  //判断是否是参数化类型
    		  if(genericReturnType instanceof ParameterizedType) {
    			  //如果是参数化类型,则强转
    			  ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
    			//获取实际参数类型数组,比如List<User>,则获取的是数组[User],Map<User,String> 则获取的是数组[User,String]
    			  Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    			  for(Type type:actualTypeArguments) {
    				  //强转
    				  Class<?> actualTypeArgument = (Class<?>) type;
    				 //获取实际参数的类名
    				  String name = actualTypeArgument.getName();
    				  System.out.println(methodName+"的返回值类型是参数化类型,其类型为:"+name);
    			  }
    			  
    		  }else {
    			  //不是参数化类型,直接获取返回值类型
    			  Class<?> returnType = method.getReturnType();
                  //获取返回值类型的类名
    			  String name = returnType.getName();
    			  System.out.println(methodName+"的返回值类型不是参数化类型其类型为:"+name);
    			  
    		  }
    		  
    		}
    		
    		
    	}
    	}
    
    
    }
    
    

    从该测试类中我们可以看到,我们首先获取对应的方法后,使用

    //比如public List<User> getAll();那么返回的是List<User>
    Type genericReturnType = method.getGenericReturnType();
    

    来获取方法的正式返回类型,比如public List< User > getAll();那么返回的是List< User >,public Map< String,User> getAll();那么返回的是Map< String,User>;,然后判断是否是参数化类型,在这里多说一句,其实参数化类型就是我们常见的List< User >,Map< String,Integer>等这些 < > 中的参数,我们可以通过是否有< >来判断是不是参数化。当我们知道是参数化类型后,需要进行强转:

     ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
    
    

    2.2下面我们开始对ParameterizedType进行解析:

    public interface ParameterizedType extends Type {
        Type[] getActualTypeArguments();
    
        Type getRawType();
    
        Type getOwnerType();
    }
    

    2.2.1 Type[] getActualTypeArguments​():返回一个Type对象的数组,表示此类型的实际类型参数。
    请注意,在某些情况下,返回的数组为空。 如果此类型表示嵌套在参数化类型中的非参数化类型,则可能会发生这种情况。
    结果:一个 Type对象的数组,表示此类型的实际类型参数。
    2.2.2 Type getRawType​():返回表示此类型的类或接口的 Type对象。
    结果 :表示声明此类型的类或接口的 Type对象 。
    2.2.3Type getOwnerType():返回表示此类型Type成员的类型的Type对象。 例如,如果该类型是O< T >.I < S > ,返回的表示O< T > 。
    如果此类型是顶级类型,则返回null 。
    结果 :表示此类型Type成员的类型的Type对象。 如果此类型是顶级类型,则返回null。
    2.3获取返回类型的实际参数数组:

      Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    
    

    2.4将actualTypeArguments 每个Type强转为Class后获取其方法名,也就是获取参数类型的全限定类名,如Map<User,Integer>中的实际参数数组actualTypeArguments ={User,Integer},其全限定类名对应为{dao.User , java.lang.Integer }。

    2.5如果不是参数化类型的话,可直接获取返回值类型然后获取返回值类型的全限定类名:

     //不是参数化类型,直接获取返回值类型
    			  Class<?> returnType = method.getReturnType();
                  //获取返回值类型的类名
    			  String name = returnType.getName();
    

    2.6测试的结果为:
    在这里插入图片描述
    我们发现 public List< User > getAll();的返回值类型是参数化类型,为List< User >,其全限定类名表示为:java.util.List<entity.User>
    public User getOne(int id);的返回值类型为User ,不是参数化类型,其全限定类名表示为:entity.User。
    由此我们初步懂得了如何获取简单的参数化类型的返回值。那么对于更加复杂的泛型类的如Map<T,V>的实际参数该怎么获取呢?欲知后事如何请看
    Java通过反射获方法的返回值的类型以及参数化的实际类型(下篇)

    该测试的源代码已经上传到我的个人博客,如有需要移步到我的个人博客里并下拉到文章结束底部点击链接下载源码:http://moyisuiying.com/index.php/javastudy/170.html

    展开全文
  • 笔者最近在学习mybatis的框架,在写源码的时候遇到了一些关于通过反射获取返回值类型的实际参数类型的问题,并且已经写有一篇关于简单的返回值类型的获取,诸如public User getOne(int id);获取返回值的类型是User,...

    笔者最近在学习mybatis的框架,在写源码的时候遇到了一些关于通过反射获取返回值类型的实际参数类型的问题,并且已经写有一篇关于简单的返回值类型的获取,诸如public User getOne(int id);获取返回值的类型是User,public List< User > getAll();的返回值类型是List< User >,其参数化类型数组是 {User},也就是参数化类型是<> 里面包含的参数类型,比如public Map<String,Integer> getAll();的返回值是Map<String,Integer>,其参数化类型数组是 {String,Integer},具体可参考笔者之前写的文章:Java通过反射获取方法的返回值的类型以及参数化的实际类型(上篇)
    该文章对一些简单的返回值的参数类型有了比较详细的讲解,那么对于更加负责的参数化类型,比如public Map< T,V > getAll()中,假若在实例化的时候这个T为Dog.java类,V为Cat.java类,那么在获取其返回值参数化数组的实际类型时,其参数化数组为 {Dog,Cat},对应的全限定类名为:{entity.Dog,entity.Cat},比较复杂的该怎么获取呢?下面我们通过几个小例子进行详细讲解。
    1.首先建立用于测试的StudentDao.java接口以及其实现类StudentDaoImpl.java。

    package dao;
    
    import java.util.Map;
    
    /**
     * @author 陌意随影
     TODO :学生dao测试类
     *2020年7月26日  下午11:02:10
     */
    public interface StudentDao<T,V> {
    	/**
    	 * 获取所有对象
    	 * @return 返回一个map
    	 */
    	public Map<T,V> getAll();
    	/**
    	 * 获取一个T对象
    	 * @return 返回T
    	 */
    	public T getT();
    	/**
    	 * 获取一个V对象
    	 * @return 返回V
    	 */
    	public	V getV();
    
    }
    
    

    该接口的实现类StudentDaoImpl.java的源码为:

    package dao;
    
    import java.util.List;
    import java.util.Map;
    
    /**
     * @author 陌意随影
     TODO :学生dao测试类
     *2020年7月26日  下午11:02:10
     */
    public class StudentDaoImpl<T,V>  implements StudentDao<T,V> {
    	/**
    	 * 获取所有对象
    	 * @return 返回一个map
    	 */
    	public Map<T,V> getAll(){
    	return null;
    }
    	/**
    	 * 获取一个T对象
    	 * @return 返回T
    	 */
    	public T getT(){
       return null;
    }
    	/**
    	 * 获取一个V对象
    	 * @return 返回V
    	 */
    	public	V getV(){
    
    return null;
    
    }
    	/**
    	 * @return 返回T的集合
    	 */
    	public List<T> getAllT(){
    return null;
    }
    
    }
    
    

    2.我们参考着上一篇:Java通过反射获取方法的返回值的类型以及参数化的实际类型(上篇)来进行测试看看是否能获取我们想要的结果。首先建立测试文件:

    package test;
    
    import java.lang.reflect.Method;
    import java.lang.reflect.ParameterizedType;
    import java.lang.reflect.Type;
    
    import org.junit.jupiter.api.Test;
    
    import dao.StudentDao;
    import dao.StudentDaoImpl;
    import entity.Cat;
    import entity.Dog;
    
    class StudentDaoTest {
    
    	@Test
    	void test() throws Exception {
    		//父接口充当声明部分
    		StudentDao<Dog, Cat> studentDao  = new StudentDaoImpl();
    		 //根据StudentDao的实例化对象获取字节码对象
    		Class<?> studentDaoClass =studentDao.getClass();
    		//获取UserDao所有的方法
    		Method[] methods = studentDaoClass.getMethods();
    		for(Method method: methods) {
    			//获取方法的名称
    			String methodName = method.getName();
    			//判断是否是studentDao中的get方法,
    			if(methodName.startsWith("get")&& !methodName.startsWith("getClass")) {
    				//返回一个Type对象,表示由该方法对象表示的方法的正式返回类型。
    			  Type genericReturnType = method.getGenericReturnType();
    			  //获取实际返回的参数名
    			  String returnTypeName = genericReturnType.getTypeName();
    			 
    			  System.out.println(methodName+"的返回参数是:"+returnTypeName);
    			  //判断是否是参数化类型
    			  if(genericReturnType instanceof ParameterizedType) {
    				  //如果是参数化类型,则强转
    				  ParameterizedType parameterizedType = (ParameterizedType) genericReturnType;
    				//获取实际参数类型数组,比如List<Dog>,则获取的是数组[Dog],Map<Dog, Cat> 则获取的是数组[Dog, Cat]
    				  Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
    				  System.out.println(methodName+"的返回值类型是参数化类型,其类型为:");
    				  for(Type type:actualTypeArguments) {
    					  //强转
    					  Class<?> actualTypeArgument = (Class<?>) type;
    					 //获取实际参数的类名
    					  String name = actualTypeArgument.getName();
    					  System.out.print("  "+name);
    				  }
    				  System.out.println();
    				  
    			  }else {
    				  //不是参数化类型,直接获取返回值类型
    				  Class<?> returnType = method.getReturnType();
    	              //获取返回值类型的类名
    				  String name = returnType.getName();
    				  System.out.println(methodName+"的返回值类型不是参数化类型其类型为:"+name);
    				  
    			  }
    			  
    			}
    			
    			
    		}
    		}
    	
    	}
    
    
    

    进行JUnit测试,其结果为:

    在这里插入图片描述

    发现能运行打印输出一部分,中途出现异常直接中断运行了。根据JUnit测试的 提示:
    在这里插入图片描述

    在进行对public Map<T,V> getAll();这个参数化方法进行解析的时候,强转遇到异常从而中断程序的运行。下面我们仔细分析看看这个原因是啥:
    2.1首先获取字节码

    Class<?> studentDaoClass =studentDao.getClass();
    

    获取字节码后,我们知道在字节码中方法的返回值类型和代码中的返回值类型是一致的,比如public Map<T,V> getAll();,那么返回值的类型就是Map<T,V>;虽然我们在实例化时:

    StudentDao<Dog, Cat> studentDao  = new StudentDaoImpl<>();
    

    已经使用了实际类型,但是我们获取的字节码对象studentDaoClass 中是没有具体类型的信息的,因为我们获取返回值的类型的时候会获得的是Map<T,V>,然后在

     Class<?> actualTypeArgument = (Class<?>) type;
    

    进行转换的时候,由于Map<T,V>中的T和V是泛型,而泛型是不支持强转的,所以会报错,从而结束程序运行。显然,在上述的情况下我们是无法进行获取到方法的返回值的正确类型的。因此我们要想获取函数中的返回值的具体类型,就必须要修改StudentDaoImpl.java,改为:

    package dao;
    
    import java.util.List;
    import java.util.Map;
    
    import entity.Cat;
    import entity.Dog;
    
    
    /**
     * @author 陌意随影
     TODO :StudentDao接口的实现了
     *2020年7月27日  上午12:35:32
     */
    public class StudentDaoImpl implements StudentDao<Dog,Cat>{
    
    	@Override
    	public Map<Dog, Cat> getAll() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Dog getT() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Cat getV() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public List<Dog> getAllT() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	
    	
    
    }
    
    

    也就是在子类实现的时候就该指定泛型的具体类型,然后
    运行JUnit测试,其结果为:
    在这里插入图片描述

    从结果中我们发现,运行成功,并且打印输出,但是发现如果不是参数化的每个方法的返回值都回打印两次,并且每次的返回值的参数化实际类型都不一样;而参数化的每个方法的返回值都值打印一次,并且打印的结果均正确。其原因是为何呢?
    其实原因是因为,StudentDao是父接口,其实现类StudentDaoImpl继承了StudentDao接口的所有方法,当我们

    //父接口充当声明部分
    		StudentDao<Dog, Cat> studentDao  = new StudentDaoImpl();
    		 //根据StudentDao的实例化对象获取字节码对象
    		Class<?> studentDaoClass =studentDao.getClass();
    

    获取的是StudentDaoImpl的字节码对象,studentDaoClass 中包含了自己定义的方法列表以及父类接口的方法列表。由于父类StudentDao接口中是泛型,public T getT();和public V getV();的返回值对象都是Object,而Map<T,V> getAll();和List getAllT();的返回对象分别是Map,List.
    StudentDaoImpl中

    @Override
    	public Dog getT() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    
    	@Override
    	public Cat getV() {
    		// TODO Auto-generated method stub
    		return null;
    	}
    

    这两个函数的返回值类型分别是Dog和Cat,这时候子类StudentDaoImpl和StudentDao中的方法的返回值不一样,子类的方法无法覆盖父类的方法,所以字节码studentDaoClass 中实际上包含有四个方法 public Object getT();public Dog getT(); 和public Object getV();public Cat getV();
    另外,返回值类型是集合的,不考虑参数化类型,比如public Map<T,V> getAll();的返回值类型是Map; public List getAllT()的返回值类型是List;
    因此,无论是在StudentDao还是在StudentDaoImpl中,public Map< T,V > getAll(),public Map< Dog,Cat > getAll()返回值类型都是Map;public List getAllT();和public List< Dog > getAllT();的返回值类型都是List,这说明子类的public Map< Dog, Cat > getAll() ;和public List< Dog> getAllT() 完全覆盖了父类的方法,因此studentDaoClass只有子类StudentDaoImpl的
    public Map< Dog,Cat> getAll()和public List< Dog> getAllT();方法。
    综上所述,studentDaoClass中实际上是有我们自定义的八个(StudentDao有四个,StudentDaoImpl有四个)方法中的六个方法。分别是:
    public Object getT();public Dog getT(); 和public Object getV();public Cat getV();以及public Map< Dog,Cat> getAll()和public List< Dog> getAllT();这六个方法。因此在我们获取方法的返回值时,打印输出的是上述结果。
    3.本次测试代码已经打包上传到个人博客,有需要的请移步(在文章最后有下载链接):
    http://moyisuiying.com/index.php/javastudy/152.html

    展开全文
  • java 通过反射获取类上注解,方法上注解,注解里的值及方法参数,项目为maven项目。导入时记得选择maven项目
  • java反射提供了很多方法,获取所有的方法,获取所有的参数类型等,但是却没有一个方法能够帮助我们获取方法的参数名列表。 首先: 为什么我们需要获取到方法对应的参数名称? 原因是例如mybatis的mapper接口中...

    假设有方法:     

     String adminTest(String mobile,int age);

    希望获取到参数名称:     [mobile,age]

    java反射提供了很多方法,获取所有的方法,获取所有的参数类型等,但是却没有一个方法能够帮助我们获取方法的参数名列表。

    首先:

      为什么我们需要获取到方法对应的参数名称?    

    原因是例如mybatis的mapper接口中定义了很多参数名称,在xml用占位符来标识,就可以类似通过这种方法来一一对应,

    包括spring的参数解析,这个问题是我在参考别人的手写mybatis,中考虑到的一个问题,故贴出我查阅资料得到的方法,网上的大部分只能获取到类的方法的参数名称列表,对接口的方法参数名称获取较少.

     

    其实也是基于spring中提供的类来实现的:需要jdk1.8及其以上:

    在Java1.8之后,可以通过反射API java.lang.reflect.Executable.getParameters来获取到方法参数的元信息。这要求在使用编译器时加上-parameters参数,它会在生成的.class文件中额外存储参数的元信息,这会增加class文件的大小。
     

    idea默认是开启的:

     

    工具类:

     

     

     

    package com.wm.ruanyan1.util;
    
    import com.wm.ruanyan1.service.AdminService;
    import com.wm.ruanyan1.service.UserService;
    import com.wm.ruanyan1.service.impl.UserServiceImpl;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.core.DefaultParameterNameDiscoverer;
    import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
    import org.springframework.util.Assert;
    
    import java.lang.reflect.Method;
    import java.util.Arrays;
    
    /**
     * @author 半卷流年
     * @date 2020-6-20 10:12
     */
    @Slf4j
    public class ReflectUtil {
    
    
        /**
         * 借助spring 的工具类,注意需要jdk8及其以上
         * 获取方法的参数的名称(不是类型),这个兼容接口(可以没有实现类)  和 普通类的方法参数
         *
         * 例如:    public String test(String name,Long id);
         *
         *     获取到的是:   [name,id]
         *
         *
         * @return
         */
        public static String[] getMethodParamName(Method method){
            Assert.notNull(method,"传入的方法对象为空");
            method.setAccessible(true);
            DefaultParameterNameDiscoverer discoverer = new DefaultParameterNameDiscoverer();
           return discoverer.getParameterNames(method);
        }
    
    
        /**
         * 借助spring 的工具类,注意需要jdk8及其以上
         *      * 获取方法的参数的名称(不是类型),普通类的方法参数,不能获取到接口的方法的参数名称
         *      *
         *      * 例如:    public String test(String name,Long id);
         * @param method
         * @return
         */
        public static String[] getMethodParamNameNoInterface(Method method){
            Assert.notNull(method,"传入的方法对象为空");
            method.setAccessible(true);
            LocalVariableTableParameterNameDiscoverer discoverer = new LocalVariableTableParameterNameDiscoverer();
            return discoverer.getParameterNames(method);
        }
    
    
        public static void main(String[] args) throws Exception{
    
    
            /***   有实现类的接口**/
            Method test = UserService.class.getMethod("userTest", String.class, Long.class, int.class);
            String[] paramName = getMethodParamName(test);
            log.info("userService有实现类的接口方法名称:{},方法的参数名称:{}",test.getName(), Arrays.toString(paramName));
    
            /***没有实现类的接口方法参数名称获取***/
            Method adminTest = AdminService.class.getMethod("adminTest", String.class, int.class);
            String[] methodParamName = getMethodParamName(adminTest);
            log.info("userService有实现类的接口方法名称:{},方法的参数名称:{}",adminTest.getName(), Arrays.toString(methodParamName));
    
            /***获取类的方法参数名称**/
    
            Method userTest = UserServiceImpl.class.getMethod("userTest", String.class, Long.class, int.class);
            String[] name = getMethodParamName(userTest);
            log.info("userService类的方法:{},方法的参数名称:{}",adminTest.getName(), Arrays.toString(name));
    
            System.out.println("----------------------下面为测试只能获取类的方法参数名称,获取不到接口的方法的参数名称---------------------------");
    
            /*****获取接口的方法参数名称******/
            String[] nameNoInterface = getMethodParamNameNoInterface(test);
            log.info("adminService有实现类的接口方法名称:{},方法的参数名称:{}",test.getName(), Arrays.toString(nameNoInterface));
    
            /***获取类的方法参数名称**/
            String[] noInterface = getMethodParamNameNoInterface(userTest);
            log.info("adminService类的方法:{},方法的参数名称:{}",test.getName(), Arrays.toString(noInterface));
    
        }
    
    }
    

     

    编写接口和实现类:

    UserService

    package com.wm.ruanyan1.service;
    
    /**
     * @author 半卷流年
     * @date 2020-6-20 10:19
     */
    public interface UserService {
    
        String userTest(String name,Long id,int count);
    
    
    
    }
    

    实现类:

    UserServiceImpl

    package com.wm.ruanyan1.service.impl;
    
    import com.wm.ruanyan1.service.UserService;
    
    /**
     * @author 半卷流年
     * @date 2020-6-20 10:20
     */
    public class UserServiceImpl implements UserService {
    
        @Override
        public String userTest(String name, Long id, int count) {
            return "success";
        }
    }
    

     

    编写一个没有实现类的接口:

    AdminService

    package com.wm.ruanyan1.service;
    
    /**
     * @author 半卷流年
     * @date 2020-6-20 10:21
     */
    public interface AdminService {
    
        String adminTest(String mobile,int age);
    }
    

     

    测试结果:

     

     

     

    可以看到成功获取到了方法的参数名称列表,是按照顺序的

     

     

     

     

     

     

     

     

     

     

    展开全文
  • java 反射 调用私有方法(有参数私有方法)获取私有属性值
  • Java-使用反射获取类型信息

    千次阅读 2018-09-18 19:30:33
    Java中如何使用反射获取类型信息?Java中如何使用反射获取类型信息?一个简单类的例子分析如何获取不同属性的类型1、普通类型2、数组类型3、带泛型的类型4、复杂的嵌套类型5、多个泛型参数总结 Java中如何使用反射...

    Java中如何使用反射获取类型信息?

    最近写了大量需要根据类属性的类型反射注入值的代码,总结了以下常用的反射技巧:

    一个简单类的例子

    在这个类中,有普通的String类型,有数组类型,有带泛型的List类型,有嵌套List类型,以及有多个泛型参数的简单类,这个类将作为我们后面的内容的基础。我们这一次博客解析如何使用反射获取到不同属性的类型值。

    public class Some{
        private String name;
        private Integer[] numbers;
        private List<String> list;
        private List<List<Double>> matrix;
        private Map<String,Class> map;
        
        //ignore getter and setter
    }
    

    分析如何获取不同属性的类型

    1、普通类型

    普通类型的变量直接field.getType()即可以获取到他们的类型

    public void queryNameType() throws NoSuchFieldException {
        Field field = Some.class.getDeclaredField("name");
        Class<?> type = field.getType();
        assertEquals(type,String.class);
    }
    

    2、数组类型

    数组类型不像其他的类型可以通过isAssignableFrom()函数来进行判断,他需要使用isArray() 来判断该type是否是一个数组类型,然后使用getComponentType() 获取他的元素的类型

    public void queryArrayType() throws NoSuchFieldException {
        Field field = Some.class.getDeclaredField("numbers");
        Class<?> type = field.getType();
        //一般来说,判断是否是某种类型是可以使用isAssignableFrom
        // 判断是否是数组类型比较特殊,要使用isArray()这个函数
        if (type.isArray()){
            //获得数组的类型,使用getComponentType()这个方法
            Class<?> componentType = type.getComponentType();
            assertEquals(componentType,Integer.class);
        }
        else{
            throw new IllegalStateException();
        }
    }
    

    3、带泛型的类型

    带泛型的类型就是类似于List<String>这样的类型,我们现在的任务就是获取到String这个类型。
    ParameterizedType表示参数化的类型,例如Collection这样的类型。我们可以通过getGenericType()方法获得该子类,当你的类型带有参数的时候就会返回ParameterizedType,否则会返回普通的类型(class)
    那么具体是怎么操作的呢?
    以获得List<T>的类型为例子

    public void getListType() throws NoSuchFieldException {
        Field field = Some.class.getDeclaredField("list");
        //如果类似于List<String>这样的类型就是一种GenericType
        //注意这是一种Type类型
        Type type = field.getGenericType();
        if (type instanceof ParameterizedType){
            //泛型参数类型
            ParameterizedType parameterizedType = (ParameterizedType)type;
            Type[] actualTypes = parameterizedType.getActualTypeArguments();
            //因为List<String>获得第一个泛型参数,因为只有一个,我们取第一个
            //如果我们有多个泛型参数,我们可以根据顺序取不同的泛型参数
            assertEquals(actualTypes[0],String.class);
            //如果获得List这个原始类型呢?
            assertEquals(parameterizedType.getRawType(),List.class);
        }else{
            throw new IllegalStateException();
        }
    }
    

    4、复杂的嵌套类型

    假如是List<List<String>> 如何获得最里面的类型呢?
    例子如下

    public void getSubListType() throws NoSuchFieldException {
    		//思考一下,如果我们有一个嵌套List,我们想拿到嵌套在最里面的类型,那么我们可以这么做呢?
    		//其实我们可以使用递归的思想去获得最里面的类型
    		Field field = Some.class.getDeclaredField("matrix");
    		assertEquals(getBaseType(field.getGenericType()),Double.class);
    	}
    
    	public static Type getBaseType(Type genericReturnType){
    		Objects.requireNonNull(genericReturnType);
    		if (genericReturnType instanceof ParameterizedType &&
    				List.class.isAssignableFrom((Class)(((ParameterizedType) genericReturnType).getRawType()))){
    			Type[] actualTypeArguments = ((ParameterizedType)genericReturnType).getActualTypeArguments();
    			Type type = actualTypeArguments[0];
    			return getBaseType(type);
    		}else{
    			return genericReturnType;
    		}
    	}
    
    

    5、多个泛型参数

    与第三个例子相似,只需要使用actualTypes数组按顺序取即可
    例子如下

    public void getMapType() throws NoSuchFieldException {
        Field field = Some.class.getDeclaredField("map");
        Type type = field.getGenericType();
        if (type instanceof ParameterizedType){
            ParameterizedType parameterizedType = (ParameterizedType)type;
            Type[] actualTypes = parameterizedType.getActualTypeArguments();
            assertEquals(actualTypes[0],String.class);
            assertEquals(actualTypes[1],Class.class);
        }else{
            throw new IllegalStateException();
        }
    }
    

    总结

    以上总结了几种常用的使用反射获取属性类型的例子,稍加改造就可以写自己的工具类了。希望对大家有帮助^_^

    展开全文
  • Java反射获取实际泛型类型参数

    千次阅读 2016-03-14 10:53:49
    反射的主要作用是能够在运行时获取一个Class的各个元素的结构,但无法更改这些元素的结构。这些元素就是前面说的成员变量和成员方法,并且对于成员变量,反射可以对其进行设值和取值,对于成员方法,反射可以直接...
  • ParameterizedType是一个接口,这...[java] view plain copy class Dao  {   public Dao(){     }  }  上面的这个类,也就是泛型类,当有子类集成它的时候,子类也许会将其参数化,
  • JAVA通过反射获取方法真实参数

    千次阅读 2020-01-03 09:50:54
    默认情况下,我们是无法获取到方法中参数的名称,通过反射机制也只能获取...因为java文件在编译时,不会将参数名称信息记入class文件中,自然也不能通过反射获取到。 在JDK 8之后,我们可以通过在编译时指定“-para...
  • java通过反射获取到list泛型的类型

    千次阅读 2020-12-27 20:11:33
    Field[] fields = bean.getClass().getDeclaredFields(); for(Field f : fields){ ... // 如果是List类型,得到其Generic的类型 Type genericType = f.getGenericType(); if(genericType == null) continue;
  • 主要介绍了Java如何基于反射机制获取不同的类,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
  • Java反射调用带接口类型参数的方法

    千次阅读 2019-08-15 20:47:23
    Java反射属于java高阶编程的一大法宝,无论是动态代理还是... 言归正传,近日在用反射调用第三方sdk中一个方法时候,发现了这个方法中带有接口类型参数,一时不知如何传递接口参数,具体看下面的一个demo方法...
  • 下面小编就为大家带来一篇利用反射获取Java类中的静态变量名及变量值的简单实例。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
  • java反射获取方法参数名称

    千次阅读 2017-02-22 11:58:41
    java原始的反射是不能获取方法菜蔬的名称的..这里借住了地方jar包 使用maven管理jar org.javassist javassist 3.18.1-GA java示范代码 Class clazz = IExample.class; try { ClassPool...
  • java反射获取方法参数及返回值类型

    千次阅读 2013-09-08 15:38:48
    package test;... import java.lang.reflect.Method; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; import java.util.List; import java.util.Map; ...
  • java8反射获取方法的参数名称 文章目录java8反射获取方法的参数名称1.简要说明2.java类获取方法参数名称测试代码解决方法执行结果3.接口测试代码执行结果解决方法感谢 1.简要说明 演示springboot版本为2.0.3....
  • Java反射--获取类方法的泛型返回或泛型参数 一.测试类 public class Test02 { public void parameterTest(Map<Integer, Dog> map){ } public Map<Integer,Dog> returnTest(){ return new ...
  • 1.通过Java反射机制获取JavaBean对象。 2.通过JavaBean全路径字符串获取JavaBean对象。 3.获取JavaBean注解信息
  • java 反射获取方法返回值类型

    千次阅读 2017-05-17 21:14:00
    //ProceedingJoinPoint pjp //获取方法返回值类型 Object[] args = pjp.getArgs(); Class<?>[] paramsCls = new Class<?>[args.length]; for (int i = ...
  • Java——通过反射获取函数参数名称

    万次阅读 2017-04-30 22:53:28
    通过javassit获取参见 http://blog.csdn.net/viviju1989/article/details/8529453 这篇文章的方法一,实现比较麻烦,就不说了。通过spring的LocalVariableTableParameterNameDiscovererpublic static List<String> ...
  • 记录2018年我遇见的一个大坑!!!!!前言具体介绍出现问题解决 ...将到有@requestMapping的注解的方法通过反射机制获取出来 将获取到的Method放入一个Map&amp;lt;String,Object&amp;gt;中,其中key为re...
  • 需求:通过该方法运行任意类的任意有参数与无参数的方法 public class Test1 {  public static void main(String[] args) {  try { Class c=Class.forName("testRef.Test2"); Method[] methods=c....
  • 之前阿里面试的时候,面试官问我Java通过反射可以获取到一个方法的形参名称吗? 听到这个问题我是懵逼的,之前只知道通过反射可以获取方法名,形参的类型,但是从来没有注意可不可以获取方法形参的名称。在网上查了...
  •  一般来说,通过反射是很难获得参数名的,只能取到参数类型,因为在编译时,参数名有可能是会改变的,需要在编译时加入参数才不会改变。  使用注解是可以实现取类型名(或者叫注解名)的,但是要写注解,并不方便...
  • 先来看一段 Spring MVC 经常用到的定义在方法参数上的注解: @RestController @RequestMapping("/param") public class ParamTestController { @PostMapping("/upload") public void upload(@RequestParam("userId...
  • JAVA反射机制 作者:邱名涛 撰写时间:2019年4月28日 ...这种动态 获取的信息以及动态调用对象的方法的功能就称为java语言的反射机制。 通俗点讲, 通过反射,该类对我们来说是完全透明的,想要获取任何东西...
  • 在8以前的jdk版本的时候,我们利用反射只能获取参数类型,然后参数名字都是利用arg0,arg1,arg2......所以在使用一些反射编程方面上不是很方便,jdk8开始开辟了这项function,但是我们正常情况下使用jvm不会默认...
  • 本质是String[], 在使用反射获取方法的时候需要使用String[].class 调用invoke方法时候需要用Object[] public class A { public void a(String... str) { System.out.println("a"); } //获取反射对象的...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 157,024
精华内容 62,809
关键字:

java反射获取参数类型

java 订阅