Java基础之—反射(高级用法)

#一、项目中最常见用法 (读取配置文件)

package com.todoming.reflect;
import java.io.FileReader;
import java.lang.reflect.Method;
import java.util.Properties;
public class ReadProperties {
    //获取配置文件属性
    public static String getValue() throws Exception{
        //获取配置文件的对象
        Properties properties=new Properties();
        //获取输入流
        FileReader reader=new FileReader("app.properties");
        //将流加载到配置文件对象中 
        properties.load(reader);
        reader.close();
        return properties.getProperty("message");
    }
    public static void main(String[] args) throws Exception{
        Class cla = Class.forName(getValue());
        Method method = cla.getDeclaredMethod("showMessage",String.class);
        Object object = cla.newInstance();
        //调用配置文件中类的方法
        method.invoke(object,"hahaha");
    }
}

#二 获取泛型的返回类型
先看段代码:

package com.todoming.reflect;
import java.util.ArrayList;
import java.util.List;
public class Generic {
    public static void main(String[] args) throws Exception {
        List<Integer> list = new ArrayList<>();
        list.add(10);
        //通过反射调用 list的add方法
        list.getClass().getMethod("add",Object.class).invoke(list,"hahah");
        System.out.println(list.toString());
    }
}

这里定义了一个只能存入int类型的List 在通过反射调用add方法时缺可以插入一个string类型的值。
这个要从泛型的原理说起:Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。所以java的泛型是一种伪泛型。反射是在运行状态中获取的,所以通过反射调用的时候我们声明的类型已经被擦除了。这个有时候会导致类型转换失败的问题。

可以通过反射的方式获取返回泛型方法的返回类型。
在University类中添加如下方法

public List<String> getList(String name){
        List<String> list = new ArrayList<>();
        list.add(name);
        return list;
    }

获取返回类型

package com.todoming.reflect;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
public class GetGenericReturn {
    public static void main(String[] args) throws Exception{
        Class cla = Class.forName("com.todoming.reflect.University");
        //这里University类中getList方法
        Method method = cla.getMethod("getList",String.class);
        //获取方法的返回类型对象
        Type returnType = method.getGenericReturnType();
        //判断该type对象能不能转型为ParameterizedType
        if (returnType instanceof ParameterizedType){
            ParameterizedType parameterizedType = (ParameterizedType)returnType;
            //调用getActualTypeArguments得到参数化类型的数组
            Type[] types = parameterizedType.getActualTypeArguments();
            for (Type type:types){
                //转型为Class对象
                Class returnTy = (Class)type;
                System.out.println(returnTy);
            }
        }
    }
}

使用上比较灵活些 不局限与以上这一种写法。关于java泛型的类型擦除有时间研究下。
#三、操作数组
Java反射可以对数组进行操作,包括创建一个数组,访问数组中的值,以及得到一个数组的Class对象。

 //创建一个int类型的数组,长度为3
 int[] arr = (int[])Array.newInstance(int.class,10);
 //通过反射的形式,给数组赋值
 for (int i = 0 ;i < arr .length;i++){
       arr .set(arr ,i,i + 2);
 }
//通过反射的形式,得到数组中的值
for (int i = 0 ; i < arr .length;i++){
      System.out.println(Array.get(arr ,i));
}

除以上基本操作外还有些奇怪的用法。

Class clz = Class.forName("[I");
System.out.println(clz.getTypeName());

输出:int[]
forName中的字符串,[表示是数组,I表示是int,float就是F,double就是D 。

Class stringClz = Class.forName("[Ljava.lang.String;");

上面这种用法是获取一个普通对象数组的用法
[表示是数组,L的右边是类名,类型的右边是一个;。
有法基本完了下次看看反射的原理。

猜你喜欢

转载自blog.csdn.net/weixin_43545983/article/details/84073280