java 反射调用方法_java的反射机制,以及通过反射获取方法,变量等操作

我们应用会用到反射这个知识点,肯定是想要在运行时得到类的信息,根据类的那些信息去做一些特定的操作。那么,首先无疑就是得到类的信息,在JDK中提供了Class对象来保存类的信息。所以,反射的第一步就是得到Class对象。在JDK中提供了两种方式得到Class对象。第一种,如果编写代码的时候,就知道Class的名字,可以直接用如下方式得到Class对象:

	//第一种,如果编写代码的时候,就知道Class的名字,可以直接用如下方式得到Class对象:
	Class exampleObjectClass = ExampleObject.class;
	
	//第二种,如果在编写代码的时候,不知道类的名字,但是在运行时的时候,可以得到一个类名的字符串,可以用如下的方式获取Class对象:
	//注意,此方法需要有2个条件,第一,forName中的字符串必须是全限定名,第二,
	//这个Class类必须在classpath的路径下面,因为该方法会抛出ClassNotFoundException的异常。
	Class exampleObjectClass2 = Class.forName("com.team.frame.fanshe.ExampleObject");


下面介绍通过反射可以获取那些信息:

1. 得到类的名字

	/**
	 * 得到类的名字
         * 类的名字有两种方式得到,一种是getName(),一种是getSimpleName()。
         * 第一种得到的是全限定名,第二种得到的是这个类的名字,不带包名。看下面的例子:Class对象,已经通过上面的代码得到了。
	 */
	String fullClassName = exampleObjectClass.getName();
	String simpleClassName = exampleObjectClass.getSimpleName();
	System.out.println(fullClassName);
	System.out.println(simpleClassName);

2. 得到类的包名、父类和实现的接口

    //得到包信息
    Package aPackage = exampleObjectClass.getPackage();
    System.out.println(aPackage);

    //得到父类
    Class superClass = exampleObjectClass.getSuperclass();
    System.out.println(superClass.getSimpleName());
    
    //判断父类是否是抽象类
    boolean abstract1 = Modifier.isAbstract(superClass.getModifiers());
    
    //我们还可以得到父类实现的接口
    Class[] interfaces = superClass.getInterfaces();
    System.out.println("父类的接口" + interfaces[0]);

3. 利用Java反射可以得到一个类的构造器,并根据构造器,在运行时动态的创建一个对象

    Constructor[] constructors = exampleObjectClass.getConstructors();
    for(Constructor cos:constructors){
    	 System.out.println(cos.toString());
    }
    //如果,事先知道要访问的构造方法的参数类型,可以利用如下方法获取指定的构造方法,例子如下:
    Constructor constructor = exampleObjectClass.getConstructor(String.class);
    System.out.println(constructor);
    
    //此外,如果我们不知道构造器的参数,只能得到所有的构造器对象,那么可以用如下方式得到每一个构造器对想的参数:
    Constructor[] constructors2 = exampleObjectClass.getConstructors();
    for(Constructor cos2:constructors2){
    	Class[] parameterTypes = cos2.getParameterTypes();
    	for(Class cla:parameterTypes){
    		System.out.println("参数类型"+cla.toString());
    	}
    }
    //根据构造器创建一个对象
    //这个创建对象的方式有2个条件,第一是通过有参构造器创建的,第二,构造器对象必须通过传入参数信息的getConstructor得到。
    //第一个条件,对于无参构造方法就可以创建的对象,不需要得到构造器对象,直接Class对象调用newInstance()方法就直接创建对象。
    //第二个条件,构造器对象必须通过exampleObjectClass.getConstructor(String.class);这种形式得到。如果通过getConstructors得到构造器数组
    //,然后调用指定的构造器对象去创建对象在JDK1.8是会错的。但是JDK1.6是正常的
    Constructor constructor2 = exampleObjectClass.getConstructor(int.class,Integer.class);
    Object newInstance = constructor2.newInstance(1,100);
    System.out.println(newInstance.toString());

4. 利用Java反射可以在运行时得到一个类的变量信息

    /**
     * 变量
     * 利用Java反射可以在运行时得到一个类的变量信息,并且可以根据上面讲的方式,创建一个对象,设置他的变量值。首先,通过如下方法,得到所有public的变量:
     */
    Field[] fields = exampleObjectClass.getFields();
    for(Field fi:fields){
    	System.out.println("变量为"+fi.toString());
    }
    //和构造器一样的得到方式一样,我们可以指定一个参数名,然后得到指定的变量:
    Field field = exampleObjectClass.getField("age");
    System.out.println(field.toString());
    
    //更改变量的值
    Constructor constructor1 = exampleObjectClass.getConstructor(String.class);
    ExampleObject newInstance2 = (ExampleObject)constructor1.newInstance("heihei");
    System.out.println("原来的age"+newInstance2.getAge());
    field.set(newInstance2, 10);
    System.out.println("修改后age"+newInstance2.getAge());

5. Java反射给我们除了给我们提供类的变量信息之外,当然也给我们提供了方法的信息

    /**
     * 方法
     * Java反射给我们除了给我们提供类的变量信息之外,当然也给我们提供了方法的信息,
     * 反射可以让我们得到方法名,方法的参数,方法的返回类型,以及调用方法等功能。
     */
    Method[] methods = exampleObjectClass.getMethods();
    for(Method me:methods){
    	System.out.println("method="+me.getName());
    }
    //根据参数获得具体方法
    Method method = exampleObjectClass.getMethod("setAge", int.class);
    System.out.println(method.getName());
    //获取方法的参数类型
    Class<?>[] parameterTypes = method.getParameterTypes();
    for(Class clz:parameterTypes){
    	System.out.println("参数名"+clz.getName());
    	System.out.println("类型"+clz.getTypeParameters());
    }
    //获得方法返回类型的
    Class<?> returnType = method.getReturnType();
    //此外,Java反射支持通过invoke调用得到的方法。例子如下:
    //nvoke第一个参数是这个对象,第二个参数是变长数组,传入该方法的参数。和Field对象同样,对于静态方法同样,可以传入null,调用静态方法。
    method.invoke(exampleObjectClass.newInstance(), 1);

6. Java给我们提供了在运行时获取类的注解信息,可以得到类注解,方法注解,参数注解,变量注解

    /**
     * 注解
     * Java给我们提供了在运行时获取类的注解信息,可以得到类注解,方法注解,参数注解,变量注解。
     * 与上面获取方式一样,Java提供了2种获取方式,一种是获取全部的注解,返回一个数组,第二种是指定得到指定的注解。
     * 我们以一个类注解为例,讲解以下这两种获取方式。
     */
    //获取类上的注解
    Class clz = AnnotationObject.class;
    Annotation[] annotations = clz.getAnnotations();
    Annotation annotation = clz.getAnnotation(AnnotationObject.class);
    //根据注解进行后续处理
    for(Annotation ano:annotations){
    	if(ano instanceof MyAnnotationFanshe){
    		MyAnnotationFanshe annoFanshe=(MyAnnotationFanshe)ano;
    		System.out.println(annoFanshe.name());
    		System.out.println(annoFanshe.value());
    	}
    }
    //获取参数上的注解
    Method method2 = clz.getMethod("doOtherThing",String.class);
    Class[] params = method2.getParameterTypes();
    Annotation[][] annotationInParam = method2.getParameterAnnotations();
    int i = 0;
    for (Annotation[] annos: annotationInParam){
        Class para = params[i++];
        for (Annotation anno : annotations){
            if(annotation instanceof MyAnnotationFanshe){
            	MyAnnotationFanshe myAnnotation = (MyAnnotationFanshe) annotation;
                System.out.println("param: " + para.getName());
                System.out.println("name : " + myAnnotation.name());
                System.out.println("value :" + myAnnotation.value());
            }

        }
    }

7. 获取泛型

    /**
     * 泛型
     * 因为Java泛型是通过擦除来实现的,很难直接得到泛型具体的参数化类型的信息,
     * 但是我们可以通过一种间接的形式利用反射得到泛型信息。比如下面这个类:
     * 如果一个方法返回一个泛型类,我们可以通过method对象去调用getGenericReturnType来得到这个泛型类具体的参数化类型是什么。
     */
    
    Class generObject = GenericObject.class;
    //反射得到返回类型为泛型类的方法
    Method method3 = generObject.getMethod("getLists");
    //调用getGenericReturnType得到方法返回类型中的参数化类型
    Type genericType = method3.getGenericReturnType();
    //判断该type对象能不能向下转型为ParameterizedType
    if(genericType instanceof ParameterizedType){
    	//转型成功,调用getActualTypeArguments得到参数化类型的数组,因为有的泛型类,不只只有一个参数化类型如Map<K,V>
        ParameterizedType parameterizedType = ((ParameterizedType) genericType);
        //取出数组中的每一个的值,转型为Class对象输出
        Type[] types = parameterizedType.getActualTypeArguments();
        for (Type type : types){
            Class actualClz = ((Class) type);
            System.out.println("参数化类型为 : " + actualClz);
        }
    }
    //因为方法的参数为泛型类型的可能不止一个,所以通过getGenericParameterTypes得到是一个数组,
    //我们需要确定每一个元素,是否是具有参数化类型。后续的步骤与上面类似,就不多说了。
    //如果连方法参数都不带泛型类,那么只剩下最后一种情况,通过变量类型,即用Field类。例子如下:
    Field field1 = generObject.getField("lists");
    Type type = field1.getGenericType();
    if (type instanceof ParameterizedType){
        ParameterizedType parameterizedType = ((ParameterizedType) type);
        Type [] types = parameterizedType.getActualTypeArguments();
        for (Type type1 : types) {
            System.out.println("参数化类型 : " + ((Class) type1).getTypeName());
        }
    }

8. Java反射可以对数组进行操作

    /**
     * 数组
	 * Java反射可以对数组进行操作,包括创建一个数组,访问数组中的值,以及得到一个数组的Class对象。
	 * 下面,先说简单的,创建数组以及访问数组中的值:在反射中使用Array这个类,是reflect包下面的。
     */
    //创建一个int类型的数组,长度为3
    int[] intArray = (int[])Array.newInstance(int.class, 3);
    //通过反射形式给数组赋值
    for(int a=0;a<intArray.length;a++){
    	Array.set(intArray, a, a+2);
    }
    //通过反射形式获取数组中的值
    for(int b=0;b<intArray.length;b++){
    	Array.get(intArray, b);
    }
    //上述就是创建数组,访问数组中的值利用反射方式
    //对于得到一个数组的Class对象,简单的可以用int[].class,或者利用Class.forName的形式得到,写法比较奇怪
    Class clz2 = Class.forName("[I");
    System.out.println(clz2.getTypeName());
    //这个forName中的字符串,[表示是数组,I表示是int,float就是F,double就是D等等,如果要得到一个普通对象的数组
    Class stringClz = Class.forName("[Ljava.lang.String;");
    //[表示是数组,L的右边是类名,类型的右边是一个;;
    //这种方式获取数组的Class对象实在是太繁琐了。
    //在得到数组的Class对象之后,就可以调用他的一些独特的方法,比如调用getComponentType来得到数组成员的类型信息,如int数组就
    //是成员类型就是int。
    System.out.println(clz2.getComponentType().getTypeName());
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值