我很好奇如何在java中为任意数量的组件编写一个类?这些组件都是通用类型。是否有语言功能或任何聪明的方法来做到这一点?
谢谢!
答案 0 :(得分:1)
如果元组的组件都是T
的数据类型,那么您只需使用List<T>
。
如果元组的组件都有不同的数据类型,那么就没有简单的方法了。实际上,Scala(位于JVM之上)通过为n的每个值设置一个单独的类(在引擎盖下)来实现n维元组。例如,以下是二维元组的代码:
public class TwoTuple<T1, T2> {
private T1 e1;
private T2 e2;
public TwoTuple(T1 e1, T2 e2) {
this.e1 = e1;
this.e2 = e2;
}
public T1 getE1() {
return this.e1;
}
public T2 getE2() {
return this.e2;
}
}
您可以类似地实现3元组,4元组等。
不幸的是,如果你想避免强制转换,没有通用的方法来实现它。当然,如果你不介意投射,你可以简单地使用List<Object>
。
答案 1 :(得分:1)
这是类型安全,因为我可以得到它。我提出的解决方案取决于在“获取”时知道对象的类型:ting或“set”:ting it。如果该类型错误,则抛出一个有意义的运行时异常,解释你做错了什么。
此解决方案在编译期间不是类型安全的。如果你犯了错误,它不会产生编译器错误。但它在运行时是类型安全的,因为它不允许类型的错误。你在构造函数中声明了元组成员的类型,并且这些类型在对象的整个生命周期内得到了加强。
元组类:
/**
* A utility class for run time type safe mixed collections.
*
* @author davogotland
*/
public class Tuple {
private Class<?>[] m_types;
private Object[] m_objects;
/**
* Constructor, initializes members.
*
* @param objects
* An array of class objects, representing the
* objects of this tuple, followed by the
* objects of this tuple. The order these
* objects are passed to the constructor will
* decide what index they will be referred to
* with as they are being fetched or updated.
*/
public Tuple(Object... objects) {
if(objects.length == 0) {
m_types = new Class<?>[] {};
m_objects = new Object[] {};
} else {
try {
m_types = (Class<?>[])objects[0];
} catch(ClassCastException cce) {
throw new RuntimeException("the first parameter of Tuplet constructor must be an array of class objects.");
}
m_objects = new Object[m_types.length];
if(objects.length != 1) {
if(m_types.length != (objects.length - 1)) {
throw new RuntimeException("the first parameter of Tuplet constructor must be an array with the same length as the number of following arguments.");
}
System.arraycopy(objects, 1, m_objects, 0, m_types.length);
for(int i = 0; i < m_types.length; i++) {
try {
m_types[i].cast(m_objects[i]);
} catch(ClassCastException cce) {
throw new RuntimeException("the class objects of the first parameter to Tuple constructor must match the types of the following parameters. error at parameter " + i + ", type of " + m_objects[i] + " declared as " + m_types[i].getName() + " but was " + m_objects[i].getClass().getName() + ".");
}
}
}
}
}
/**
* Gets an element from the tuple.
*
* @param <T>
* The type of the element to fetch.
* @param c
* A class object representing the
* elements type.
* @param i
* The index of the element to fetch. This
* index is decided by the order the elements
* are added during construction of the
* tuple.
* @return
* The element at the given index, cast to
* the given type.
*/
public <T> T get(Class<T> c, int i) {
if(c != m_types[i]) {
throw new RuntimeException("the get method for index " + i + " must return a " + m_types[i].getName() + ". (attempted was " + c.getName() + ")");
}
return c.cast(m_objects[i]);
}
/**
* Sets an element in the tuple.
*
* @param i
* The index where the object should be set.
* @param object
* The object to set.
*/
public void set(int i, Object object) {
if(m_types[i] != object.getClass()) {
throw new RuntimeException("the set method for index " + i + " must take a " + m_types[i].getName() + ". (attempted was " + object.getClass().getName() + ")");
}
m_objects[i] = object;
}
}
考试班(为了更好的安慰):
/**
* A representation of a fraction.
*
* @author davogotland
*/
public class Fraction {
private int m_numerator;
private int m_denominator;
/**
* Constructor, initializes members.
*
* @param numerator
* @param denominator
*/
public Fraction(int numerator, int denominator) {
m_numerator = numerator;
m_denominator = denominator;
}
/**
* Calculates the value of this fraction as a double.
*
* @return
* The value of this fraction as a double.
*/
public double getDoubleValue() {
return (double)m_numerator / (double)m_denominator;
}
/* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
builder.append(m_numerator);
builder.append("/");
builder.append(m_denominator);
return builder.toString();
}
}
和预期用途:
/**
* Proving that the class Tuple works.
*
* @author davogotland
*/
public class Main {
/**
* @param args
*/
public static void main(String[] args) {
Tuple t = new Tuple(new Class<?>[] {Float.class, Fraction.class, Integer.class}, 2.2f, new Fraction(1, 3), 4);
System.out.println("first: " + t.get(Float.class, 0));
//expected output: first: 2.2
System.out.println("second: " + t.get(Fraction.class, 1));
//expected output: second: 1/3
System.out.println("third: " + t.get(Integer.class, 2));
//expected output: third: 4
t.set(0, 3.5f);
double sum = t.get(Float.class, 0);
sum += t.get(Fraction.class, 1).getDoubleValue();
sum += t.get(Integer.class, 2);
System.out.println("sum: " + sum);
//expected output: sum: 7.833333333333334
t = new Tuple(new Object[] {new Class<?>[] {Float.class, Fraction.class, Integer.class}});
t.set(0, 3.5f);
System.out.println("first: " + t.get(Float.class, 0));
//expected output: first: 3.5
System.out.println("second: " + t.get(Fraction.class, 1));
//expected output: second: null
System.out.println("third: " + t.get(Integer.class, 2));
//expected output: third: null
sum = t.get(Float.class, 0);
sum += t.get(Fraction.class, 1).getDoubleValue();
//expected null pointer exception on the above line
sum += t.get(Integer.class, 2);
System.out.println("sum: " + sum);
}
}
答案 2 :(得分:0)
元组 - 在数学和计算机科学中,元组是一个有序的元素列表(wikipedia)
所以我会使用List<T>
答案 3 :(得分:0)
使用任意数量的组件对元组建模的简单方法是:
SomeType[]
如果元组的大小没有改变List<SomeType>
如果元组的大小必须能够改变,Object[]
或List<Object>
如果元组需要能够保存任意(引用)类型的值(通过强制转换使用运行时类型安全),或Tuple2<T1, T2>
,Triple3<T1, T2, T3>
等...即N
的每个值的不同通用类。在Java中没有通用的方法来使用单个类来建模静态类型安全的一般N元组。
(我认为你确实需要静态类型安全;即你希望元组中每个位置的getter和setter都有适当的静态返回类型,这样你就不需要进行类型转换了。不幸的是,那是这部分很难。)