Object数组到泛型数组转换的伪解决方案

闲来无事,想要用目前的Java技术模拟一个对象数据库。最初只是停留在很简单的构想,单用户的,本地的,仅仅是为了实现一些纯对象化的数据库操作:

 

public interface DataBase
{
    public <T> T[] select(Filter<T> filter);
    public <T> void insert(T t);
    public int update(Filter<T> filter, Updater<T> handler);
    public <T> int delete(T t);
}

 

 

其中,FilterUpdater分别是两个接口,处理查询子句和更新子句。

 

public interface Filter<T>
{
	public boolean where(T obj);
}

public interface Updater<T>
{
	public void set(T obj);
}

 

 

这么设计的目的是以一种对象化的方式处理数据,把数据库的操作和业务流程无缝的结合在一起。我说过,这只是我的一个练习,因此请仅把它看成是练习就好。数据库的对象容器用了一个泛型的List,里面可以包含任何对象。

 

然而在select方法的时候,碰到了一些问题。因为它要返回的是T[]类型结果,而由于T是泛型,在ListtoArray时,仅能生成Object[]类型的数组,与需求有差异。

 

//...

@SuppressWarnings("unchecked")
public <T> T[] select(Filter<T> filter)
{
    Collection<T> c= new ArrayList<T>();
    for (Object obj : pool) {
        try {
            T t = (T) obj;
            if (filter.where(t)) c.add(t);
        } catch (Exception ex) {
            continue;
        }
    }
    // 到现在都OK
    return c.toArray(); // 不OK,返回类型为Object[],与结果不符
    return (T[]) c.toArray(); // 不OK,仍返回 Object[],ClassCastException
    return c.toArray(new T[0]); // 不OK,编译错误。
}

//...

 

首先要解释一下为什么return c.toArray(new T[0]); 不能通过编译。因为据Java官方所说,为了向旧版本兼容,Java的泛型只是存在于编译期,其目的是编译期的源代码正确性校验,变成了.class之后所有泛型内容全部被抛弃。所以,new T[0]这种写法在运行期是不可能有意义的,因为没有T的具体定义。

 

@SuppressWarnings("unchecked")的原因是T t = (T) obj;语句。没有想到更好的办法做泛型的类型比较,用这种方法最直接。不过可能会产生ClassCastException,所以一旦发生转换错误,只是简单地继续处理下一个元素。若有其它解决方案也请能不吝赐教,这里谢过。

 

现在,回到问题上来:怎么实现这个泛型的数组转换呢?

 

我这里有一个伪解决方案。就是从结果集合中取一个值出来,然后创建这个值类型的数组,见下:

 

@SuppressWarnings("unchecked")
public <T> T[] select(Filter<T> filter)
{
    Collection<T> c;
//...
    Iterator<T> it = c.iterator();
    if (it.hasNext()) {
        T[] tt = (T[]) Array.newInstance(it.next().getClass(), c.size());
        return c.toArray(tt);
    } else return null;
}

 

 

说这是个伪解决方案的原因是集合中的值并不就等于是T,有可能是T的子类。若集合中所有元素都是一个类别倒还好说,怕只怕有些元素又是子类的子类(孙类)。那么假设碰巧集合中第一个拿到的就是孙类,那么tt实际是孙类的数组,这样对于包含子类对象的集合执行toArray操作的时候就会出现ArrayStoreException

 

好了,在暂时不考虑这个“伪”字的情况下,这里举个使用的例子:

 

public static void main(String[] args)
{
    DataBase db = new DataBaseImpl();
    db.insert("Hello, ");
    db.insert(" this ");
    db.insert(new Integer(3));
    db.insert("world!");

    String[] ss = (db.select(new Filter<String>() {

        @Override
        public boolean where(String obj)
        {
            return (obj.trim().length() > 4);
        }

    }));

    for (String s : ss)
        System.out.println(s);
}

 

======== 补充========

春节休假在家,偶尔看了一下论坛。结合下面的评论并思考了一下,目前采用通过传入的Filter获得泛型类的方法:

 

import java.lang.reflect.*;
import java.util.*;

public class Container {
    private Collection<Object> container = new ArrayList<Object>();

    public void add(Object obj) {
        container.add(obj);
    }

    @SuppressWarnings("unchecked")
    public <T> T[] select(Filter<T> filter)
    {
        Class clazz;
        Type[] types = filter.getClass().getGenericInterfaces();
        if (types != null && types.length > 0) {
            clazz = ((Class) ((ParameterizedType) types[0])
                    .getActualTypeArguments()[0]);
        } else return null;
        Collection<T> c = new ArrayList<T>();
        for (Object o : container) {
            if (clazz.isInstance(o) && filter.where((T) o))
                c.add((T) o);
        }
        T[] tt = (T[]) Array.newInstance(clazz, c.size());
        return c.toArray(tt);
    }

    public static void main(String[] args) {
        Container c = new Container();
        c.add("Hello");
        c.add("world");
        c.add("I");
        c.add("love");
        c.add("you");
        c.add(new Integer(4));
        c.add("ever");

        String[] list = c.select(new Filter<String>() {
            public boolean where(String s) {
                return (s.length() > 3);
            }
        });
        for (String s : list)
            System.out.println(s);
    }
}

interface Filter<T> {
	boolean where(T t);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值