在 Java 中,是否可以编写单个函数或 class 来处理任意多维 ArrayList?
In Java, is writing a single function or class to handle arbitrary multidimensional ArrayList possible?
在 C++ 中,我可以编写 2 个模板 类,例如:
#include <stdio.h>
#include <vector>
template <typename T>
class Printer{
public:
static void print(T& v){
printf("%d ",v.getValue());
}
};
template <typename T,typename Alloc>
class Printer<std::vector<T,Alloc> >{
public:
static void print(std::vector<T,Alloc>& v){
for(T& e : v){
Printer<T>::print(e);
}
printf("\n");
}
};
以便它可以接受任意自定义对象类型和 vector
in vector
in vector
...(无限嵌套 vector
):
class Student{
public:
int value;
Student(int value){ this->value=value; }
int getValue() const { return this->value; }
};
class Teacher{
public:
int value;
Teacher(int value){ this->value=value; }
int getValue() const { return this->value*10; }
};
int main(){
std::vector<Student> v2 = {Student(10),Student(20)};
Printer<std::vector<Student> >::print(v2);
std::vector<std::vector<Teacher> > v3 = {{Teacher(30),Teacher(40)},{Teacher(50),Teacher(60),Teacher(70)}};
Printer<std::vector<std::vector<Teacher> > >::print(v3);
return 0;
}
前提是自定义对象 Student
和 Teacher
具有 getValue()
功能。
但是在 Java 中,我怎么能写出像上面那样接受两者的东西呢
ArrayList<Student > v2;
和
ArrayList<ArrayList<Teacher> > v3;
(还有 ArrayList
in ArrayList
in ArrayList
in...)以通用方式?
我尝试转换代码时出现了一些问题,首先,通用对象方法无法编译:
public static void <T> print(T t){
System.out.print(t.getValue());
}
我不知道如何将 std::vector< T , Alloc >
转换成 Java 因为 ArrayList
只接受 1 个模板参数。
注意:我希望 vector 成为专用模板,因为当我想添加对 int
:
的支持时
std::vector<int> v1={1,2};
Printer<std::vector<int> >::print(v1);
我可以添加
template <>
class Printer<int>{
public:
static void print(int& v){
printf("%d ",v);
}
};
到代码。
有一个简单但非常丑陋的解决方案:转向 raw types,或者因为这是非常糟糕的做法,请转向 ? extends Object
。
你看,最终,Java 泛型根本无法与现代 C++ 模板相匹配。泛型不是模板——例如:您不能将它们用于基本类型,例如 int
。您只能使用 List<Integer>
代替。或者一些 T extends Number
当你需要一个包含 Double, Float, ... 对象的列表时。
重点是:最后,在运行时,所有这些 "generics" 都消失了。所有此类列表仅包含 Objects。
所以,理论上,如果您真的想要 "solution",那么您可以选择
void foo(List<? extends Object> thingies)
避免所有类型信息...并在运行时进行反射魔术以确定如何处理该列表的确切内容。
"more Java" 解决方案要求您后退。如前所述,Java 不是 C++,因此您根本不应该期望 Java 具有相同级别的 "expressiveness"。
相反:学习如何正确地利用Java泛型和Java类型系统;并根据 知识*构建解决方案。
或者换句话说:如果您需要 C++ 解决方案,请使用 C++。 Java 永远不会满足该要求(至少不会达到 100%)。
您可以通过 instanceof
检查来做到这一点:
public static <T> void print(List<? extends T> list) {
for (final T t : list) {
if (t instanceof List) print((List) t);
else System.out.println(t);
}
}
但是当然你不能使用方法 T.getValue()
如果它没有在接口的任何地方或某处定义。如果T
是一个接口
public interface T {
String getValue();
}
那么你有这样的东西
public static void print(List<? extends Object> list) {
for (Object t : list) {
if(t instanceof T) System.out.println(((T)t).getValue());
else if (t instanceof List) print((List) t);
else continue; // I don't know this type.
}
}
但它随后会附加到您的界面 T
。问题实际上是您无法访问未定义的方法,至少在没有反射的情况下是这样。 C++ 是如何做到这一点的?
编辑: 这当然行不通,如果你有一个 T
的实现,它也实现了 List
接口。
在 C++ 中,我可以编写 2 个模板 类,例如:
#include <stdio.h>
#include <vector>
template <typename T>
class Printer{
public:
static void print(T& v){
printf("%d ",v.getValue());
}
};
template <typename T,typename Alloc>
class Printer<std::vector<T,Alloc> >{
public:
static void print(std::vector<T,Alloc>& v){
for(T& e : v){
Printer<T>::print(e);
}
printf("\n");
}
};
以便它可以接受任意自定义对象类型和 vector
in vector
in vector
...(无限嵌套 vector
):
class Student{
public:
int value;
Student(int value){ this->value=value; }
int getValue() const { return this->value; }
};
class Teacher{
public:
int value;
Teacher(int value){ this->value=value; }
int getValue() const { return this->value*10; }
};
int main(){
std::vector<Student> v2 = {Student(10),Student(20)};
Printer<std::vector<Student> >::print(v2);
std::vector<std::vector<Teacher> > v3 = {{Teacher(30),Teacher(40)},{Teacher(50),Teacher(60),Teacher(70)}};
Printer<std::vector<std::vector<Teacher> > >::print(v3);
return 0;
}
前提是自定义对象 Student
和 Teacher
具有 getValue()
功能。
但是在 Java 中,我怎么能写出像上面那样接受两者的东西呢
ArrayList<Student > v2;
和
ArrayList<ArrayList<Teacher> > v3;
(还有 ArrayList
in ArrayList
in ArrayList
in...)以通用方式?
我尝试转换代码时出现了一些问题,首先,通用对象方法无法编译:
public static void <T> print(T t){
System.out.print(t.getValue());
}
我不知道如何将 std::vector< T , Alloc >
转换成 Java 因为 ArrayList
只接受 1 个模板参数。
注意:我希望 vector 成为专用模板,因为当我想添加对 int
:
std::vector<int> v1={1,2};
Printer<std::vector<int> >::print(v1);
我可以添加
template <>
class Printer<int>{
public:
static void print(int& v){
printf("%d ",v);
}
};
到代码。
有一个简单但非常丑陋的解决方案:转向 raw types,或者因为这是非常糟糕的做法,请转向 ? extends Object
。
你看,最终,Java 泛型根本无法与现代 C++ 模板相匹配。泛型不是模板——例如:您不能将它们用于基本类型,例如 int
。您只能使用 List<Integer>
代替。或者一些 T extends Number
当你需要一个包含 Double, Float, ... 对象的列表时。
重点是:最后,在运行时,所有这些 "generics" 都消失了。所有此类列表仅包含 Objects。
所以,理论上,如果您真的想要 "solution",那么您可以选择
void foo(List<? extends Object> thingies)
避免所有类型信息...并在运行时进行反射魔术以确定如何处理该列表的确切内容。
"more Java" 解决方案要求您后退。如前所述,Java 不是 C++,因此您根本不应该期望 Java 具有相同级别的 "expressiveness"。
相反:学习如何正确地利用Java泛型和Java类型系统;并根据 知识*构建解决方案。
或者换句话说:如果您需要 C++ 解决方案,请使用 C++。 Java 永远不会满足该要求(至少不会达到 100%)。
您可以通过 instanceof
检查来做到这一点:
public static <T> void print(List<? extends T> list) {
for (final T t : list) {
if (t instanceof List) print((List) t);
else System.out.println(t);
}
}
但是当然你不能使用方法 T.getValue()
如果它没有在接口的任何地方或某处定义。如果T
是一个接口
public interface T {
String getValue();
}
那么你有这样的东西
public static void print(List<? extends Object> list) {
for (Object t : list) {
if(t instanceof T) System.out.println(((T)t).getValue());
else if (t instanceof List) print((List) t);
else continue; // I don't know this type.
}
}
但它随后会附加到您的界面 T
。问题实际上是您无法访问未定义的方法,至少在没有反射的情况下是这样。 C++ 是如何做到这一点的?
编辑: 这当然行不通,如果你有一个 T
的实现,它也实现了 List
接口。