英文:
How to create an array of instances of generic nested classes?
问题
我试图创建一个由泛型内部类对象派生的实例数组。
当我这样做时
delivery.columns = new Delivery.Column[] { delivery.new Number (), delivery.new Date () };
我会收到以下警告:
Table.java:58: warning: [rawtypes] found raw type: Table.Column
delivery.columns = new Delivery.Column[] { delivery.new Number (), delivery.new Date () };
^
missing type arguments for generic class Table.Column<V>
where V is a type-variable:
V extends Object declared in class Table.Column
Table.java:58: warning: [unchecked] unchecked conversion
delivery.columns = new Delivery.Column[] { delivery.new Number (), delivery.new Date () };
^
required: Table.Column<Object>[]
found: Table.Column[]
2 warnings
如果我遵循警告中的要求,并执行以下操作:
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
我会得到以下错误:
Table.java:58: error: incompatible types: Delivery.Number cannot be converted to Table.Column<Object>
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
^
Table.java:58: error: incompatible types: Delivery.Date cannot be converted to Table.Column<Object>
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
^
Table.java:58: error: generic array creation
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
^
3 errors
如何在没有警告和错误的情况下解决此问题?
这是完整的示例代码:
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.lang.System.err;
abstract class Table
{
String name = null;
Column<Object>[] columns = null;
abstract class Column<V>
{
String name = null;
Integer type = null;
class Value
{
V value;
Value (V value)
{
this.value = value;
}
}
public String toString ()
{
return name + ": " + type.toString();
}
}
public String toString ()
{
return this.name + " ("
+ Stream.of(columns).map (Column<Object>::toString).collect (Collectors.joining (", "))
+ ")";
}
}
class Delivery extends Table
{
{ name = "Delivery"; }
class Number extends Delivery.Column<String>
{
{ name = "Number"; }
}
class Date extends Delivery.Column<String>
{
{ name = "Date"; }
}
public static void main (String[] args)
{
String[] strings;
Delivery delivery = new Delivery ();
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
err.println (delivery);
}
}
英文:
I try to create an array of instances of inner class objects, which are derived from generic inner classes.
When I do this
delivery.columns = new Delivery.Column[] { delivery.new Number (), delivery.new Date () };
I get the warnings:
<!-- language: none -->
Table.java:58: warning: [rawtypes] found raw type: Table.Column
delivery.columns = new Delivery.Column[] { delivery.new Number (), delivery.new Date () };
^
missing type arguments for generic class Table.Column<V>
where V is a type-variable:
V extends Object declared in class Table.Column
Table.java:58: warning: [unchecked] unchecked conversion
delivery.columns = new Delivery.Column[] { delivery.new Number (), delivery.new Date () };
^
required: Table.Column<Object>[]
found: Table.Column[]
2 warnings
And if I follow the requirement in the warning and do the following
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
I get the following errors:
<!-- language: none -->
Table.java:58: error: incompatible types: Delivery.Number cannot be converted to Table.Column<Object>
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
^
Table.java:58: error: incompatible types: Delivery.Date cannot be converted to Table.Column<Object>
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
^
Table.java:58: error: generic array creation
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
^
3 errors
How to solve this problem without warning and error?
This is the complete example:
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static java.lang.System.err;
abstract class Table
{
String name = null;
Column<Object>[] columns = null;
abstract class Column<V>
{
String name = null;
Integer type = null;
class Value
{
V value;
Value (V value)
{
this.value = value;
}
}
public String toString ()
{
return name + ": " + type.toString();
}
}
public String toString ()
{
return this.name + " ("
+ Stream.of(columns).map (Column<Object>::toString).collect (Collectors.joining (", "))
+ ")";
}
}
class Delivery extends Table
{
{ name = "Delivery"; }
class Number extends Delivery.Column<String>
{
{ name = "Number"; }
}
class Date extends Delivery.Column<String>
{
{ name = "Date"; }
}
public static void main (String[] args)
{
String[] strings;
Delivery delivery = new Delivery ();
delivery.columns = new Delivery.Column<Object>[] { delivery.new Number (), delivery.new Date () };
err.println (delivery);
}
}
答案1
得分: 2
以下是翻译好的部分:
我不确定这是否是一个适当的解决方案,更像是使用 List<Column<?>>
容器的一种变通方法(正如 @Andy Turner 在评论中建议的那样)。然后,如果需要,可以将列表转换为列数组。
// 抽象类 Table
protected List<Column<?>> columns;
protected Column<?>[] arrColumns = null;
public Column<?>[] getColumnsAsArray() {
if (null == columns) {
return null;
}
Column<?>[] arr = (Column<?>[]) Array.newInstance(Column.class, columns.size());
return columns.toArray(arr);
}
public String toString() {
return this.name
+ "\nlist: (" + columns.stream().map(Column::toString).collect(Collectors.joining(", ")) + ")"
+ "\narr: (" + Stream.of(arrColumns).map(Column::toString).collect(Collectors.joining(", ")) + ")";
}
因此,可以创建列的列表,并按如下所示转换为数组:
public class Main {
public static void main(String[] args) {
Delivery delivery = new Delivery();
delivery.columns = Arrays.asList(delivery.new Number(), delivery.new Date());
delivery.arrColumns = delivery.getColumnsAsArray();
err.println(delivery);
Arrays.stream(delivery.arrColumns)
.map(Object::getClass)
.forEach(System.out::println);
}
}
class Delivery extends Table {
{ name = "Delivery"; }
class Number extends Table.Column<Number> {
{ name = "Number"; type = 1; } // define _type_ to prevent NPE in Column<V>::toString
}
class Date extends Table.Column<String> {
{ name = "Date"; type = 10; } // define _type_ to prevent NPE
}
}
输出
# 错误输出
Delivery
list: (Number: 1, Date: 10)
arr: (Number: 1, Date: 10)
# 标准输出
class Delivery$Number
class Delivery$Date
已使用编译器选项 -Xlint:all
进行验证。
英文:
I am not sure if it is a proper solution, it's more like a workaround using a List<Column<?>>
container (as @Andy Turner suggested in the comments).
Then the list can be converted into array of columns if needed.
// abstract class Table
protected List<Column<?>> columns;
protected Column<?>[] arrColumns = null;
public Column<?>[] getColumnsAsArray() {
if (null == columns) {
return null;
}
Column<?>[] arr = (Column<?>[]) Array.newInstance(Column.class, columns.size());
return columns.toArray(arr);
}
public String toString() {
return this.name
+ "\nlist: (" + columns.stream().map(Column::toString).collect(Collectors.joining(", ")) + ")"
+ "\narr: (" + Stream.of(arrColumns).map(Column::toString).collect(Collectors.joining(", ")) + ")";
}
So, the list of columns can be created and converted to array as shown below:
public class Main {
public static void main(String[] args) {
Delivery delivery = new Delivery();
delivery.columns = Arrays.asList(delivery.new Number(), delivery.new Date());
delivery.arrColumns = delivery.getColumnsAsArray();
err.println(delivery);
Arrays.stream(delivery.arrColumns)
.map(Object::getClass)
.forEach(System.out::println);
}
}
class Delivery extends Table {
{ name = "Delivery"; }
class Number extends Table.Column<Number> {
{ name = "Number"; type = 1; } // define _type_ to prevent NPE in Column<V>::toString
}
class Date extends Table.Column<String> {
{ name = "Date"; type = 10; } // define _type_ to prevent NPE
}
}
Output
# stderr
Delivery
list: (Number: 1, Date: 10)
arr: (Number: 1, Date: 10)
# stdout
class Delivery$Number
class Delivery$Date
Verified with compiler option -Xlint:all
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论