java,关于利用反射自动设置List<T>中T的类型

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了java,关于利用反射自动设置List<T>中T的类型相关的知识,希望对你有一定的参考价值。

用 类名.class 可以得到一个 Class对象
class.newInstance() 可以得到一个实体
现在我想要一个方法
可以根据 Class指定的类型,生成一个 List<T> list 集合
问题是怎么让程序自动指定 这个"T" ?
或者根本没有必要 指定 T ?

泛型可以用"<T>"代表,任意类型的。
解释: “<T>”是泛型的默认值,可以被任意类型所代替,如:
List<String> list = new ArayList<String>();这个就定义了一个String类型的”泛型“集合,那么T的类型就是字符串。
List<T> list = new ArayList<T>();
可以赋值给list:list.add("StringBatch");
可以获取到list的值:list.get(0),结果就是”StringBatch“;
这个时候T的类型也是String。也就是说T是动态的,可以被任意指定类型。
参考技术A 由于return 无法返回“数据类型”这种模糊的对象,所以无法通过“方法”达到你的目的。
但是你可以通过判断已知的数据类型或者采用超类来达到相同的目的。
判断已知数据类型可以使用关键字 instanceof :
if(str instanceof String)
List<String> list = null;

采用超类:
List<Object> list = null;
List<?> list = null; 使用“?”与使用Object达到的结果相同。
如果使用超类的话,在使用集合元素前最好先判断(instanceof)在进行强制类型转换,否则可能会出错。追问

str instanceof String
这种形式倒是很容易,但是我想让方法更"自由一点",不要太死
请问用超类的方法怎么用?可以给个例子吗?

追答

用代码给你例子:
import java.util.*;
public class A
List list = null;
static int b;
int a = 0;
private A() //这虽然是使用了private声明的构造函数
//但是在使用newInstance()方法时调用的是这个构造函数
//如果类中声明了其他构造函数且没有默认构造函数的话,会出错。
//你可以试一下注释掉这个构造函数。
a+=b++;

public A(Object o) //与前一个构造函数作对比。
a-=b++;

List getList(Object o)
List list = new ArrayList();
try
for(int i = 0 ; i < 10 ; i++ )
Object b = o.getClass().newInstance();
list.add(b);

catch (InstantiationException e)
// TODO Auto-generated catch block
e.printStackTrace();
catch (IllegalAccessException e)
// TODO Auto-generated catch block
e.printStackTrace();

return list;

public static void main(String[] args)
A a = new A();
a.list = a.getList(a);
for(Object o:a.list)
System.out.println(((A)o).a);


本回答被提问者采纳
参考技术B 大哥,问题能描述清楚?仔细看看你问的问题是否已经矛盾了? 这里创建的都是对象,不是类型。 参考技术C 要不你试下List<?> list;
看看是不是你要的效果

基于Java+Selenium的WebUI自动化测试框架-----读取Excel文件(POI)

  上一篇我们讲了怎么利用Java的反射机制,将Excel的读取到的数据,赋值给我们构造函数中定义的变量。

  接下来就简单了,我们将实际实现这个读取的简单过程。来看下面一段代码。

private static <T> List<T> transToObject(Class<T> clz,Workbook xssfWorkbook, String sheetName)
            throws InstantiationException, IllegalAccessException,
            InvocationTargetException 
        List<T> list = new ArrayList<T>();
        Sheet xssfSheet = xssfWorkbook.getSheet(sheetName);
        Row firstRow = xssfSheet.getRow(0);
        if(null ==firstRow)
            return list;
        
        List<Object> heads = getRow(firstRow);
        //添加sheetName字段,用于封装至bean中,与bean中的字段相匹配。
        heads.add("sheetName");
        Map<String, Method> headMethod = getSetMethod(clz, heads);
        for (int rowNum = 1; rowNum <= xssfSheet.getLastRowNum(); rowNum++) 
            try 
                Row xssfRow = xssfSheet.getRow(rowNum);
                if (xssfRow == null) 
                    continue;
                
                T t = clz.newInstance();
                List<Object> data = getRow(xssfRow);
                //如果发现表数据的列数小于表头的列数,则自动填充为null,最后一位不动,用于添加sheetName数据
                while(data.size()+1<heads.size())
                    data.add("");
                
                data.add(sheetName);
                setValue(t, data, heads, headMethod);
                list.add(t);
             catch (IllegalArgumentException e) 
                // TODO Auto-generated catch block
                e.printStackTrace();
            
        
        return list;
    

  在这段代码中,我们使用了一个泛型Class<T>来指代我们的构造类,返回的就是一个包含这个构造类的实例集合List<T>。

  另外,xssfWorkbook 是POI中指代一个Excel workbook的变量,sheetName就是我们要读取的sheet名字。

  这里使用了一个小技巧,就是我们的构造函数中,并没有包含sheetName这样一个变量,但是我们实际读取Excel的时候,每个被读取的值都是在一个sheet上的,这样也就必然会有一个sheetName的属性。我们获取第一列的列名之后,可以把“sheetName”这个字段加入List集合中。

  在赋值的时候,我们把参数当中的sheetName赋值给“sheetName”字段,这样,作为一个返回的构造类实例,就包含了变量“sheetName”及具体值sheetName。

  下面,我们再对xssfWorkbook进行再定义,请看下面一段代码:

    public static <T> List<T> readExcel(Class<T> clz, String path,String sheetName) 
        if (null == path || "".equals(path)) 
            return null;
        
        InputStream is;
        Workbook xssfWorkbook;
        try 
            is = new FileInputStream(path);
       //判断Excel的版本。因为Excel版本不一样,文件的后缀名也不一样
if (path.endsWith(".xls")) xssfWorkbook = new HSSFWorkbook(is); else xssfWorkbook = new XSSFWorkbook(is); is.close(); return transToObject(clz, xssfWorkbook, sheetName); catch (Exception e) e.printStackTrace(); throw new RuntimeException("转换excel文件失败:" + e.getMessage());

  这样,我们就完成了一个自定义的构造类----“按需读取”Excel的过程。

  在这个过程中,我们需要注意:构造类中的变量名和Excel文件中记录的列名要保持一致,我们才能正常读取数据。

  扩展一下,假如我要读取Excel和N个sheet上的数据,并且也要“按需读取”。怎么办呢。例如:

Excel有2个Sheet,SheetA和SheetB,这两页上分别写有不同的元素,我想把这些页面元素的内容都读出来,作为一个集合List<T>返回

SheetA------页面元素A1(网页名,名称,寻找方式,等待时间,路径),SheetA------页面元素A2(网页名,名称,寻找方式,等待时间,路径)

SheetB------页面元素B1(网页名,名称,寻找方式,等待时间,路径),SheetB------页面元素B2(网页名,名称,寻找方式,等待时间,路径)

  我们来看下面一段代码:

    public static <T> List<T> readExcel(Class<T> clz, String path) 
        System.out.println(path);
        if (null == path || "".equals(path)) 
            return null;
        
        InputStream is;
        Workbook xssfWorkbook;
        try 
            is = new FileInputStream(path);
            if (path.endsWith(".xls")) 
                xssfWorkbook = new HSSFWorkbook(is);
             else 
                xssfWorkbook = new XSSFWorkbook(is);
            
            is.close();
            int sheetNumber = xssfWorkbook.getNumberOfSheets();
            List<T> allData = new ArrayList<T>();
            for (int i = 0; i < sheetNumber; i++) 
                allData.addAll(transToObject(clz, xssfWorkbook,
                        xssfWorkbook.getSheetName(i)));
            
            return allData;
         catch (Exception e) 
            e.printStackTrace();
            throw new RuntimeException("转换excel文件失败:" + e.getMessage());
        
    

  这里还是比较好处理的,只要直接遍历每个Sheet再存储就好了。

  实际使用例子:

  

    public static void main(String[] args) 
        String excelpath = ".\\case-data\\same4Test.xls";
        List<positionBean> dataList = new ArrayList<positionBean>();
        dataList = excelUtil.readExcel(positionBean.class,excelpath,"Sheet1");
        for(int i = 0; i < dataList.size();i++) 
            String pageName = dataList.get(i).getPageName();
            String path = dataList.get(i).getPath();
            int waitSec = dataList.get(i).getSec();
            String type = dataList.get(i).getType();
            String positionName = dataList.get(i).getPositionName();
            System.out.println(pageName);
            System.out.println(path);
            System.out.println(waitSec);
            System.out.println(type);
            System.out.println(positionName);
        
    

  这样我们就真正完成了使用POI实现“按需读取”

  

以上是关于java,关于利用反射自动设置List<T>中T的类型的主要内容,如果未能解决你的问题,请参考以下文章

利用反射将IDataReader读取到实体类中效率低下的解决办法

利用反射把Datatable转换成List

利用反射和代理简单模拟mybatis实现简单的CRUD

基于Java+Selenium的WebUI自动化测试框架-----读取Excel文件(POI)

jdbc利用java反射实现结果集得到处理:bug:argument type mismatch

利用反射插入数据库与更新数据库