将泛型和泛型数组作为参数传递的可变长度参数列表 - Java
Variable-Length Argument List passing generics and generic arrays as params - Java
我正在尝试编写一个辅助打印方法,这样我就可以用更少的代码和更简单的方式将项目打印到控制台。
但是,我 运行 遇到打印传递到我的方法中的数组的问题,因为我无法遍历常规通用变量 (E),但我没有找到一种可以在不重载的情况下修复它的方法方法。
为什么当我检查变量是泛型数组时,循环在我的实例中不起作用?我觉得这至少应该允许转换为数组(这是注释代码现在显示的内容),但这也失败了,这让我认为在 Java 中不可能从 E 转换为 E[] .
这是我的代码:
@SafeVarargs@SuppressWarnings("unchecked")//SAFE
public static <E> void print(E... toPrint){
//USED TO ENHANCE SYSTEM.OUT.PRINTLN AND MAKE EASIER TO TYPE
E[] itemArray;
for(E item: toPrint){
if(item.getClass().isArray()){//IS ARRAY
//System.out.println(item.getClass());
//itemArray = (E[]) item;//WILL NOT WORK, CANNOT CONVERT
////IF LOOP ITEM ERROR NOT ITERABLE, BUT IT IS ARRAY?
//for(E innerItem: itemArray)
//System.out.println(innerItem);
}else{
System.out.println(item);
}
}
}
根据@Sweeper 的建议更新了代码:
@SafeVarargs//SAFE
public static <E> void print(E... toPrint){
//USED TO ENHANCE SYSTEM.OUT.PRINTLN AND MAKE EASIER TO TYPE
for(E item: toPrint){
if(item.getClass().isArray()){//IF IS ARRAY
printHelperForArrays(item);//MUST CHECK IF PRIMITIVE[] OR OBJECT[]
}else if (item instanceof List){//IF ITEM IS LIST
String[] stringArray = item.toString()
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else{
System.out.println(item);
}
}//END FOR
}
@SuppressWarnings("unchecked")//SAFE
public static <E> void printHelperForArrays(E item){
//USED TO PRINT OUT ARRAY ELEMENTS
if(item.getClass() == int[].class){//IS INT[]
String[] stringArray = Arrays.toString((int[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING
}else if(item.getClass() == double[].class){//IS DOUBLE[]
String[] stringArray = Arrays.toString((double[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == float[].class){//IS FLOAT[]
String[] stringArray = Arrays.toString((float[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == char[].class){//IS CHAR[]
String[] stringArray = Arrays.toString((char[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == boolean[].class){//IS BOOLEAN[]
String[] stringArray = Arrays.toString((boolean[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == byte[].class){//IS BYTE[]
String[] stringArray = Arrays.toString((byte[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == short[].class){//IS SHORT[]
String[] stringArray = Arrays.toString((short[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == long[].class){//IS LONG[]
String[] stringArray = Arrays.toString((long[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else{//IS OBJECT[] LIKE INTEGER[], STRING[], CHARACTER[]... SO E[] WORKS
String[] stringArray = Arrays.toString((E[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}
}
传递的参数:
int[] int1 = {4, 5, 6};
Integer[] Integer2 = {7, 8, 9};
double[] double3 = {10.01, 11.01, 12.01};
Double[] Double4 = {13.01, 14.01, 15.01};
char[] char5 = {'A', 'B', 'C'};
Character[] Character6 = {'D', 'E', 'F'};
float[] float7 = {1.999f, 2.999f};
Float[] Float8 = {3.999f, 4.999f};
LinkedList<String> listOfStrings = new LinkedList<>();
listOfStrings.add("List Item 1");
listOfStrings.add("List Item 2");
//CALLED AS
print(1, 2, 3, "Hello", int1, Integer2, double3,
Double4, char5, Character6, float7, Float8, listOfStrings);
输出
1
2
3
Hello
4
5
6
7
8
9
10.01
11.01
12.01
13.01
14.01
15.01
A
B
C
D
E
F
1.999
2.999
3.999
4.999
List Item 1
List Item 2
现在所有内容都打印在自己的行上,无论它是基元、包装器 class 中的元素、数组、列表还是其他任何东西。
如果你写 public static <E> void print(E... toPrint){
它将要求所有输入都相同 class (E
)。并调用 print(1, 2, 3, "Hello");
之类的方法
不会工作
您应该将方法更改为 public static void print(Object... toPrint)
而且你可以自由施放(Object[])item
。
public static void print(Object... items) {
for (Object item: items) {
if (item.getClass().isArray()) {
Object[] objs =primitiveArrayFrom(item);
if (objs == null) {
objs = (Object[]) item;
}
for (Object obj: objs) {
System.out.println(obj);
}
} else {
System.out.println(item);
}
}
}
private static Object[] primitiveArrayFrom(Object obj) {
if (obj instanceof int[]) {
int[] integers = (int[]) obj;
return IntStream.of(integers).boxed().toArray();
}
// Test for other primitives here
//finally
return null;
}
不幸的是,没有办法直接将原始数组的对象转换为Object[]
,所以你必须通过primitiveArrayFrom ()
函数将其转换。
如果您确定您的输入是同一类型(例如,您没有将 String
与 int
混合,那么您绝对应该编写接受原始类型的重载版本).否则,请尝试上面的实现。
您的代码不起作用,因为您试图将数组类型 E
转换为数组数组 - E[]
.
如果执行进入if语句,则表示E
是一个数组类型。所以 E[]
是一个数组的数组。 E[]
和 E
是不相关的类型。
所以你需要知道如何让编译器知道你确定 E
是一个数组并且它可以循环。但是,在 Java.
中无法做到这一点
所以是的,你需要超载 print
。这种技术在标准库中被广泛使用。只要看看 Arrays
class,那里几乎每个方法都有针对各种数组的重载。 Java 数组有许多您必须忍受的限制。
顺便问一下,你知道有一个叫做 Arrays.toString
的好用方法吗?它可以简化您的阵列打印过程:
System.out.println(Arrays.toString(arr));
也许你根本不需要 print
。
注:
您的代码有效,只是不适用于基本类型数组,因此如果您传入 Integer[]
,它将成功打印出来。
编辑:
您可以通过针对每种原始数组类型检查类型来解决此问题:
public static void print(Object... toPrint) {
for (Object item : toPrint) {
if (item.getClass() == int[].class) {
System.out.println(Arrays.toString((int[])item));
} else if (item.getClass() == double[].class) { // check for all primitive types
System.out.println(Arrays.toString((double[])item));
} else if (item instanceof Object[]){
System.out.println(Arrays.toString((Object[])item));
} else {
System.out.println(item);
}
}
}
使用原始类型 int
的 Array
包装器 class 可以解决您的问题。
Integer[] arr = {4, 5, 6};
print(arr);
而不是:
print(1, 2, 3, "Hello");
int[] arr = {4, 5, 6};
print(arr);
现在,当您传递 int[]
数组并尝试将其转换为 E[] 时会发生什么,它实际上会尝试转换为 Integer[]
。所以,基本上尝试自动装箱数组,但只有 autoboxing
原始类型是可能的,但我们不能 auto box
primitive
类型数组 inke int[]
.
您可以使用 Array.get()
在不知道数组类型的情况下对数组进行索引:
for (int i = 0, len = Array.getLength(item); i < len; i++)
System.out.println(Array.get(item, i));
我正在尝试编写一个辅助打印方法,这样我就可以用更少的代码和更简单的方式将项目打印到控制台。
但是,我 运行 遇到打印传递到我的方法中的数组的问题,因为我无法遍历常规通用变量 (E),但我没有找到一种可以在不重载的情况下修复它的方法方法。
为什么当我检查变量是泛型数组时,循环在我的实例中不起作用?我觉得这至少应该允许转换为数组(这是注释代码现在显示的内容),但这也失败了,这让我认为在 Java 中不可能从 E 转换为 E[] .
这是我的代码:
@SafeVarargs@SuppressWarnings("unchecked")//SAFE
public static <E> void print(E... toPrint){
//USED TO ENHANCE SYSTEM.OUT.PRINTLN AND MAKE EASIER TO TYPE
E[] itemArray;
for(E item: toPrint){
if(item.getClass().isArray()){//IS ARRAY
//System.out.println(item.getClass());
//itemArray = (E[]) item;//WILL NOT WORK, CANNOT CONVERT
////IF LOOP ITEM ERROR NOT ITERABLE, BUT IT IS ARRAY?
//for(E innerItem: itemArray)
//System.out.println(innerItem);
}else{
System.out.println(item);
}
}
}
根据@Sweeper 的建议更新了代码:
@SafeVarargs//SAFE
public static <E> void print(E... toPrint){
//USED TO ENHANCE SYSTEM.OUT.PRINTLN AND MAKE EASIER TO TYPE
for(E item: toPrint){
if(item.getClass().isArray()){//IF IS ARRAY
printHelperForArrays(item);//MUST CHECK IF PRIMITIVE[] OR OBJECT[]
}else if (item instanceof List){//IF ITEM IS LIST
String[] stringArray = item.toString()
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else{
System.out.println(item);
}
}//END FOR
}
@SuppressWarnings("unchecked")//SAFE
public static <E> void printHelperForArrays(E item){
//USED TO PRINT OUT ARRAY ELEMENTS
if(item.getClass() == int[].class){//IS INT[]
String[] stringArray = Arrays.toString((int[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING
}else if(item.getClass() == double[].class){//IS DOUBLE[]
String[] stringArray = Arrays.toString((double[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == float[].class){//IS FLOAT[]
String[] stringArray = Arrays.toString((float[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == char[].class){//IS CHAR[]
String[] stringArray = Arrays.toString((char[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == boolean[].class){//IS BOOLEAN[]
String[] stringArray = Arrays.toString((boolean[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == byte[].class){//IS BYTE[]
String[] stringArray = Arrays.toString((byte[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == short[].class){//IS SHORT[]
String[] stringArray = Arrays.toString((short[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else if(item.getClass() == long[].class){//IS LONG[]
String[] stringArray = Arrays.toString((long[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}else{//IS OBJECT[] LIKE INTEGER[], STRING[], CHARACTER[]... SO E[] WORKS
String[] stringArray = Arrays.toString((E[])item)
.replace("[","")//REMOVE [
.replace("]","")//REMOVE ]
.split(", ");//TURN TO ARRAY
for(String innerItem: stringArray)
System.out.println(innerItem);//NOW PRINT EVERYTHING OUT
}
}
传递的参数:
int[] int1 = {4, 5, 6};
Integer[] Integer2 = {7, 8, 9};
double[] double3 = {10.01, 11.01, 12.01};
Double[] Double4 = {13.01, 14.01, 15.01};
char[] char5 = {'A', 'B', 'C'};
Character[] Character6 = {'D', 'E', 'F'};
float[] float7 = {1.999f, 2.999f};
Float[] Float8 = {3.999f, 4.999f};
LinkedList<String> listOfStrings = new LinkedList<>();
listOfStrings.add("List Item 1");
listOfStrings.add("List Item 2");
//CALLED AS
print(1, 2, 3, "Hello", int1, Integer2, double3,
Double4, char5, Character6, float7, Float8, listOfStrings);
输出
1
2
3
Hello
4
5
6
7
8
9
10.01
11.01
12.01
13.01
14.01
15.01
A
B
C
D
E
F
1.999
2.999
3.999
4.999
List Item 1
List Item 2
现在所有内容都打印在自己的行上,无论它是基元、包装器 class 中的元素、数组、列表还是其他任何东西。
如果你写 public static <E> void print(E... toPrint){
它将要求所有输入都相同 class (E
)。并调用 print(1, 2, 3, "Hello");
之类的方法
不会工作
您应该将方法更改为 public static void print(Object... toPrint)
而且你可以自由施放(Object[])item
。
public static void print(Object... items) {
for (Object item: items) {
if (item.getClass().isArray()) {
Object[] objs =primitiveArrayFrom(item);
if (objs == null) {
objs = (Object[]) item;
}
for (Object obj: objs) {
System.out.println(obj);
}
} else {
System.out.println(item);
}
}
}
private static Object[] primitiveArrayFrom(Object obj) {
if (obj instanceof int[]) {
int[] integers = (int[]) obj;
return IntStream.of(integers).boxed().toArray();
}
// Test for other primitives here
//finally
return null;
}
不幸的是,没有办法直接将原始数组的对象转换为Object[]
,所以你必须通过primitiveArrayFrom ()
函数将其转换。
如果您确定您的输入是同一类型(例如,您没有将 String
与 int
混合,那么您绝对应该编写接受原始类型的重载版本).否则,请尝试上面的实现。
您的代码不起作用,因为您试图将数组类型 E
转换为数组数组 - E[]
.
如果执行进入if语句,则表示E
是一个数组类型。所以 E[]
是一个数组的数组。 E[]
和 E
是不相关的类型。
所以你需要知道如何让编译器知道你确定 E
是一个数组并且它可以循环。但是,在 Java.
所以是的,你需要超载 print
。这种技术在标准库中被广泛使用。只要看看 Arrays
class,那里几乎每个方法都有针对各种数组的重载。 Java 数组有许多您必须忍受的限制。
顺便问一下,你知道有一个叫做 Arrays.toString
的好用方法吗?它可以简化您的阵列打印过程:
System.out.println(Arrays.toString(arr));
也许你根本不需要 print
。
注:
您的代码有效,只是不适用于基本类型数组,因此如果您传入 Integer[]
,它将成功打印出来。
编辑:
您可以通过针对每种原始数组类型检查类型来解决此问题:
public static void print(Object... toPrint) {
for (Object item : toPrint) {
if (item.getClass() == int[].class) {
System.out.println(Arrays.toString((int[])item));
} else if (item.getClass() == double[].class) { // check for all primitive types
System.out.println(Arrays.toString((double[])item));
} else if (item instanceof Object[]){
System.out.println(Arrays.toString((Object[])item));
} else {
System.out.println(item);
}
}
}
使用原始类型 int
的 Array
包装器 class 可以解决您的问题。
Integer[] arr = {4, 5, 6};
print(arr);
而不是:
print(1, 2, 3, "Hello");
int[] arr = {4, 5, 6};
print(arr);
现在,当您传递 int[]
数组并尝试将其转换为 E[] 时会发生什么,它实际上会尝试转换为 Integer[]
。所以,基本上尝试自动装箱数组,但只有 autoboxing
原始类型是可能的,但我们不能 auto box
primitive
类型数组 inke int[]
.
您可以使用 Array.get()
在不知道数组类型的情况下对数组进行索引:
for (int i = 0, len = Array.getLength(item); i < len; i++)
System.out.println(Array.get(item, i));