我目前正在学习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
我希望你能帮助我解决这个问题。非常感谢你。
看看下面的代码。您的问题的解释在评论中。
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?
干杯!
参考文献: