在java中,能否在一个有泛型定义的类中,获取传入的泛型类型呢?

code__fan 2016-09-19 12:25:54
我现在遇到一个问题,就是想在定义了泛型的类中,构建一个泛型类的数组。但是在泛型类中,是不可以直接new泛型数组的(尽管可以通过先构建一个Object数组然后在强转成泛型数组)。所以我想通过在泛型类中,获取从创建对象的地方传来的泛型的class对象,然后通过
Array.newInstance(Class<?> componentType, int length)
这个方法,来动态创建数组。比较简单的办法,是直接在构建对象的时候,传入泛型类的class对象,作为构造参数。但明明我在构造对象的时候,就已经传入了泛型代替AnyType了,却又重复地再传了一次参数,觉得没有必要 。所以我想有没有办法可以直接在定义泛型的类中获取传来的泛型类型。目前我能获得具体的泛型的类型,但还是没想到有什么好的办法可以在定义了泛型的类中,获得传来的泛型类型(尽管那个AnyType本身可以获得。。)求大神给个解决办法。
public class MyQueue<AnyType> {

/**
* 队列数组容量
*/
private int capacity;
/**
* 封装的数组
*/
private AnyType[] data;

//其他属性略过

// 创建
public MyQueue(Class<AnyType> type,int capacity) {
this.capacity = capacity;
//法一:通过强转数组
//data = (AnyType[]) new Object[capacity];//这样做可以实现需求,但底层毕竟是Object[]类型,
//我想要真正的传入的泛型类型的数组

//法二:通过传入AnyType的clazz对象
// data = getArray(type,capacity);

//法三:通过获取传来的泛型类来构建数组,可以少传一个参数。(待解决!!!!)
Class<AnyType> clazz = getGenType();//此处返回的只是AnyType类的class,
//并不是我所要的泛型类的class,不知该如何获得
data = getArray(clazz,capacity);//由于构建的只是AnyType的数组,因此,添加Integer元素会抛异常Exception in
// thread "main" java.lang.ArrayStoreException: java.lang.Integer
clear();
}
@SuppressWarnings("unchecked")
private <E> E[] getArray(Class<E> e,int capacity){
return (E[]) Array.newInstance(e, capacity);

}
//获取传入的泛型类
private Class<AnyType> getGenType(){
Type[] types = getClass().getTypeParameters();
Class<AnyType> clazz = (Class<AnyType>) types[0].getClass();
System.out.println(Arrays.toString(types));
return clazz;
}
//其他方法省略
}

测试类:
public class TestQueue {

public static void main(String[] args) {
MyQueue<Integer> qu = new MyQueue<>(Integer.class,4);
qu.enqueue(4);
qu.enqueue(6);
qu.enqueue(7);
qu.enqueue(9);

qu.traverse();
}
}


------------------------------------------------------------------------------
除此之外,还有几个小疑问:
1,在类中获得泛型的具体类型有什么应用吗?比如我在上面那个测试类上获得传入的Integer这个泛型类,但感觉没什么意义啊。。因为我本来就可以直接知道。。
2.在定义泛型的类中,泛型为什么不能直接用来new数组?而通过强转就可以。。(好神奇

...全文
1571 8 打赏 收藏 转发到动态 举报
写回复
用AI写文章
8 条回复
切换为时间正序
请发表友善的回复…
发表回复
JamesGan96 2016-09-19
  • 打赏
  • 举报
回复
Class = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; 泛型的应用多用于,从几个类中抽取出来的公共方法中!这些方法唯一的不同就是对象的类型!比如basedao,baseaction这些类! 简单类型基本不会用,一般是对象的类型!
code__fan 2016-09-19
  • 打赏
  • 举报
回复
@newmoons @soton_dolphin @lkx_founder 麻烦帮我看一看吧
bree06 2016-09-19
  • 打赏
  • 举报
回复
java.util.*下基本都是使用泛型, 内部也是使用Object[]或者Object Node定 义的. 比如ArrayList<E>中数据是这么定义 的transient Object[] elementData; 而PriorityQueue<E>中数据是这么定义 的transient Object[] queue; 泛型的类型要在运行的时候才知道, 在这之前jvm是不知道需要创建什么类型的数组,也没办法知道创建何种实例, 所以没有办法直接使用new E() 或者new E[n]; 实际构建Object数组只是向上转型而已, 内存中的实际类型依然是泛型指定的明确类型.
public class MyQueue<E> {
    private int capacity;
    private Object[] datas;
    private int size;

    public MyQueue() {
        this(10);
    }

    public MyQueue(int capacity) {
        if (capacity > 0) {
            this.capacity = capacity;
        } else {
            this.capacity = 10;
        }
        datas = new Object[this.capacity];
    }
    private E element(int index) {
        return (E) datas[index];
    }
    public void add(E e) {
        // TODO 逻辑部分省略
        datas[size++] = e;
    }

    public E popFirst() {
        if (size == 0) return null;
        E e = element(0);
        System.arraycopy(datas, 1, datas, 0, size - 1);
        datas[size - 1] = null;
        size--;
        return e;
    }

    public E popLast() {
        if (size == 0) return null;
        E e = element(size - 1);
        datas[size - 1] = null;
        size--;
        return e;
    }

    public int size() {
        return size;
    }

    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(datas, size));
    }

    public static void main(String[] args) {
        MyQueue<Integer> queue = new MyQueue<>();
        queue.add(3);
        queue.add(5);
        queue.add(9);
        System.out.println("queue size: " + queue.size());
        System.out.println(queue);
        Integer first = queue.popFirst();
        System.out.println("first data: " + first);
        System.out.println(queue);
        Integer last = queue.popLast();
        System.out.println("last data: " + last);
        System.out.println(queue);
        System.out.println("queue size: " + queue.size());
    }
}
当然,为了通用性, 最好实现java.util.Queue<E>
NewMoons 2016-09-19
  • 打赏
  • 举报
回复
个人的理解,泛型的目的主要是提高代码的可靠性,避免强制转换,在编译期就将错误清除。
NewMoons 2016-09-19
  • 打赏
  • 举报
回复
转载: Java语言引入泛型的好处是安全简单。泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,提高代码的重用率。 1,类型安全。 泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的程度上验证类型假设。没有泛型,这些假设就只存在于程序员的头脑中(或者如果幸运的话,还存在于代码注释中)。 2,消除强制类型转换。 泛型的一个附带好处是,消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。 3,潜在的性能收益。 泛型为较大的优化带来可能。在泛型的初始实现中,编译器将强制类型转换(没有泛型的话,程序员会指定这些强制类型转换)插入生成的字节码中。但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来可能。由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改。所有工作都在编译器中完成,编译器生成类似于没有泛型(和强制类型转换)时所写的代码,只是更能确保类型安全而已。
code__fan 2016-09-19
  • 打赏
  • 举报
回复
引用 5 楼 bree06的回复:
java.util.*下基本都是使用泛型, 内部也是使用Object[]或者Object Node定 义的. 比如ArrayList<E>中数据是这么定义 的transient Object[] elementData; 而PriorityQueue<E>中数据是这么定义 的transient Object[] queue; 泛型的类型要在运行的时候才知道, 在这之前jvm是不知道需要创建什么类型的数组,也没办法知道创建何种实例, 所以没有办法直接使用new E() 或者new E[n]; 实际构建Object数组只是向上转型而已, 内存中的实际类型依然是泛型指定的明确类型.
public class MyQueue<E> {
    private int capacity;
    private Object[] datas;
    private int size;

    public MyQueue() {
        this(10);
    }

    public MyQueue(int capacity) {
        if (capacity > 0) {
            this.capacity = capacity;
        } else {
            this.capacity = 10;
        }
        datas = new Object[this.capacity];
    }
    private E element(int index) {
        return (E) datas[index];
    }
    public void add(E e) {
        // TODO 逻辑部分省略
        datas[size++] = e;
    }

    public E popFirst() {
        if (size == 0) return null;
        E e = element(0);
        System.arraycopy(datas, 1, datas, 0, size - 1);
        datas[size - 1] = null;
        size--;
        return e;
    }

    public E popLast() {
        if (size == 0) return null;
        E e = element(size - 1);
        datas[size - 1] = null;
        size--;
        return e;
    }

    public int size() {
        return size;
    }

    @Override
    public String toString() {
        return Arrays.toString(Arrays.copyOf(datas, size));
    }

    public static void main(String[] args) {
        MyQueue<Integer> queue = new MyQueue<>();
        queue.add(3);
        queue.add(5);
        queue.add(9);
        System.out.println("queue size: " + queue.size());
        System.out.println(queue);
        Integer first = queue.popFirst();
        System.out.println("first data: " + first);
        System.out.println(queue);
        Integer last = queue.popLast();
        System.out.println("last data: " + last);
        System.out.println(queue);
        System.out.println("queue size: " + queue.size());
    }
}
当然,为了通用性, 最好实现java.util.Queue<E>
谢谢回复,我知道您底层是用Object数组来接收的,这其实跟我上面的第一种方式一样。但我就是想通过接收泛型传入的类型,然后来动态地new数组。其实第二种方式可以new但毕竟是通过传参进来的。。貌似是没法在MyQueue中获得传入的泛型的类型呢。。
code__fan 2016-09-19
  • 打赏
  • 举报
回复
引用 4 楼 NewMoons的回复:
个人的理解,泛型的目的主要是提高代码的可靠性,避免强制转换,在编译期就将错误清除。
谢谢回复。我把我的问题说得具体点吧,请问您知道怎么在MyQueue这个类中,获得从测试类中传来的Integer类型吗?现在用那个getGenType方法还只能获得获得AnyType这个类本身。。
code__fan 2016-09-19
  • 打赏
  • 举报
回复
引用 2 楼 努力也坎坷的回复:
Class = (Class<T>) ((ParameterizedType) getClass() .getGenericSuperclass()).getActualTypeArguments()[0]; 泛型的应用多用于,从几个类中抽取出来的公共方法中!这些方法唯一的不同就是对象的类型!比如basedao,baseaction这些类! 简单类型基本不会用,一般是对象的类型!
谢谢回复,这个方法我试过了,可以获得父类中定义的泛型的类型。我的问题,说得具体点,就是现在我想在MyQueue这个类中,获得从测试类中传来的Integer类型。现在用那个getGenType方法还只能获得获得AnyType这个类本身。。

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧