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

问题描述 投票:1回答:1

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

#include <iostream>
#include <vector>
template <typename T>
class Vect{
    public:
        std::vector<T> vect;
        Vect(std::vector<T> t){vect = t;}
        T index(int i){return vect[i];}
        void print(){
            for(int i = 0; i < vect.size(); ++i){
                std::cout << vect[i] << " ";
            }
            std::cout << std::endl;
        }
        void add(Vect<T> other){
            for(int i = 0; i < vect.size(); ++i){
                vect[i] = vect[i]+other.index(i);
            }
        }
};

int main(){
    std::vector<int> p1;
    p1.push_back(1);
    p1.push_back(2);
    p1.push_back(3);
    p1.push_back(4);
    Vect<int> vec1 = Vect<int>(p1);;
    Vect<int> vec2 = Vect<int>(p1);;
    vec1.print();
    vec2.print();
    vec1.add(vec2);
    vec1.print();

    return 0;
}

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

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;
            }
        }
    }
}

所以它确实打印了一个double,但是然后转换不起作用,我得到一个错误:

线程“main”java.lang.ArrayStoreException中的异常:在Main.main(Main.java:12)的Vect0.sum(Vect0.java:37)处的java.lang.Double

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

java generics
1个回答
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抛出此异常表示已尝试将错误类型的对象存储到对象数组中。例如,以下代码生成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?

干杯!

参考文献:

© www.soinside.com 2019 - 2024. All rights reserved.