在Java中添加两个泛型(强制转换)

时间:2017-12-17 23:18:50

标签: java generics

我目前正在学习Java中的泛型,来自C ++它有很大的不同。 我想要一个向量加法,在C ++中,它看起来像这样。 (我知道这段代码编写得不好,只是为了一个简单的例子来展示我想要做的事情)

public class Vect0<T extends Number> {

    //Attributs
    private T[] _vec;

    //Constructeur
    public Vect0(T[] vec){
        System.out.println("Construction du _vec !");
        _vec = vec;
    }
    //Getter
    public int get_length() {
        return _vec.length;
    }
    //Methodes
    public void print(){
        System.out.print("[");
        for (int i = 0; i < _vec.length; ++i){
            if (i != _vec.length-1) {
                System.out.print(_vec[i] + ", ");
            }
            else {
                System.out.print(_vec[i]);
            }
        }
        System.out.println("]");
    }
    public T index(int i) {
        return _vec[i];
    }
    public void sum(Vect0<T> other) {
        if (other.get_length() == this.get_length()) {
            for(int i = 0; i < this.get_length(); ++i) {
                Double res = (this.index(i).doubleValue() + other.index(i).doubleValue());
                System.out.print(res);
                T t = (T) res;
                _vec[i] =  t;
            }
        }
    }
}

我正在尝试用Java做同样的事情,但我无法通过添加两个泛型T并将值(一个T)放在第一个向量中。我这样做:

private

所以它会打印一个双精度,但是然后投射不起作用而且我收到错误:

  

线程中的异常&#34; main&#34; java.lang.ArrayStoreException:   在Vect0.sum上的java.lang.Double(Vect0.java:37)at   Main.main(Main.java:12)

我希望你能帮助我解决这个问题。 非常感谢你。

1 个答案:

答案 0 :(得分:1)

看看下面的代码。您的问题的解释在评论中。

public class TestGenerics {

    public static void main(String[] args) {
        Integer[] ints = new Integer[] { 1 };
        Double[] doubles = new Double[] { 1.0 };

        // By not telling the compiler which types you're
        // expecting it will not be able to deduce if
        // the usage of the generic methods are going
        // to be ok or not, because the generics notation is
        // erased and is not available at runtime.
        // The only thing you will receive by doing this
        // is a warning telling you that:
        // "Vect0 is a raw type. 
        // References to generic type Vect0<T> should be parameterized"
        Vect0 rawVect0 = new Vect0(ints);
        Vect0 rawVect1 = new Vect0(doubles);

        // This will throw java.lang.ArrayStoreException 
        // because you're trying, at runtime, to cast
        // a Double object to Integer inside your sum method
        // The compiler doesn't have a clue about that so it 
        // will blow at runtime when you try to use it.
        // If you're only working with Integers, than you should not
        // cast the result to double and should always work with intValues
        rawVect0.sum(rawVect1);

        // In Java, when using generics, you should be 
        // explict about your types using the diamond operator
        Vect0<Integer> vect2 = new Vect0<>(ints);
        Vect0<Double> vect3 = new Vect0<>(doubles);

        // Now that you told the compiler what your types are
        // you will receive a compile time error:
        // "The method sum(Vect0<Integer>) in the type Vect0<Integer> 
        // is not applicable for the arguments (Vect0<Double>)"
        vect2.sum(vect3);
    }
}

如果您阅读了有关ArrayStoreException的内容,它将变得更加清晰:

  

public class ArrayStoreException extends RuntimeException Thrown to   表示已尝试存储错误类型的   将对象转换为对象数组。例如,以下代码   生成一个ArrayStoreException:

 Object x[] = new String[3];
 x[0] = new Integer(0);

每当处理Generic方法时,您应该认为Producer应该使用extends,而Consumer应该使用super - PECS 。这是一件好事。看看这个问题: What is PECS (Producer Extends Consumer Super)?

如果您真的希望能够添加不同类型的Number,那么您的案例的一个解决方案是始终使用一种特定类型(Vect0)在Double对象内部工作。看看下面的代码:

public class Vect0<T extends Number> {
    // Attributs
    private Double[] _vec;

    // Constructeur
    public Vect0(T[] vec) {
        System.out.println("Construction du _vec !");
        if (vec instanceof Double[]) {
            _vec = (Double[]) Arrays.copyOf(vec, vec.length);
        } else {
            _vec = Arrays.stream(vec).map(Number::doubleValue).toArray(Double[]::new);
        }
    }

    // Getter
    public int get_length() {
        return _vec.length;
    }

    // Methodes
    public void print() {
        System.out.print("[");
        for (int i = 0; i < _vec.length; ++i) {
            if (i != _vec.length - 1) {
                System.out.print(_vec[i] + ", ");
            } else {
                System.out.print(_vec[i]);
            }
        }
        System.out.println("]");
    }

    public Double index(int i) {
        return _vec[i];
    }

    public void sum(Vect0<T> other) {
        if (other.get_length() == this.get_length()) {
            for (int i = 0; i < this.get_length(); ++i) {
                // Now you're only working with Doubles despite of the other object's true type
                _vec[i] = index(i) + other.index(i);
            }
        }
    }
}

为了使用它,你应该使用超类Number引用对象,如下所示:

Vect0<Number> vect2 = new Vect0<>(ints1);
Vect0<Number> vect3 = new Vect0<>(doubles1);
// now it will be able to add two different types without complaining
vect2.sum(vect3);

如果您想要更精细的内容,可以先查看以下问题:How to add two java.lang.Numbers?

干杯!

参考文献: