如何创建一个包含泛型嵌套类实例的数组?

huangapple go评论77阅读模式
英文:

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&lt;V&gt;
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&lt;Object&gt;[]
found:    Table.Column[]
2 warnings

And if I follow the requirement in the warning and do the following

delivery.columns = new Delivery.Column&lt;Object&gt;[] { 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&lt;Object&gt;
delivery.columns = new Delivery.Column&lt;Object&gt;[] { delivery.new Number (), delivery.new Date () };
^
Table.java:58: error: incompatible types: Delivery.Date cannot be converted to Table.Column&lt;Object&gt;
delivery.columns = new Delivery.Column&lt;Object&gt;[] { delivery.new Number (), delivery.new Date () };
^
Table.java:58: error: generic array creation
delivery.columns = new Delivery.Column&lt;Object&gt;[] { 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&lt;Object&gt;[] columns = null;
abstract class Column&lt;V&gt;
{
String  name = null;
Integer type = null;
class Value
{
V value;
Value (V value)
{
this.value = value;
}
}
public String toString ()
{
return name + &quot;: &quot; + type.toString();
}
}
public String toString ()
{
return this.name + &quot; (&quot;
+ Stream.of(columns).map (Column&lt;Object&gt;::toString).collect (Collectors.joining (&quot;, &quot;))
+ &quot;)&quot;;
}
}
class Delivery extends Table
{
{ name = &quot;Delivery&quot;; }
class Number extends Delivery.Column&lt;String&gt;
{
{ name = &quot;Number&quot;; }
}
class Date extends Delivery.Column&lt;String&gt;
{
{ name = &quot;Date&quot;; }
}
public static void main (String[] args)
{
String[] strings;
Delivery delivery = new Delivery ();
delivery.columns = new Delivery.Column&lt;Object&gt;[] { 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&lt;Column&lt;?&gt;&gt; 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&lt;Column&lt;?&gt;&gt; columns;
    protected Column&lt;?&gt;[] arrColumns = null;

    public Column&lt;?&gt;[] getColumnsAsArray() {
        if (null == columns) {
            return null;
        }
        Column&lt;?&gt;[] arr = (Column&lt;?&gt;[]) Array.newInstance(Column.class, columns.size());
        return columns.toArray(arr);
    }

    public String toString() {
        return this.name 
            + &quot;\nlist: (&quot; + columns.stream().map(Column::toString).collect(Collectors.joining(&quot;, &quot;)) + &quot;)&quot;
            + &quot;\narr: (&quot; + Stream.of(arrColumns).map(Column::toString).collect(Collectors.joining(&quot;, &quot;)) + &quot;)&quot;;
    }

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 = &quot;Delivery&quot;; }
 
  class Number extends Table.Column&lt;Number&gt; {
    { name = &quot;Number&quot;; type = 1; }  // define _type_ to prevent NPE in Column&lt;V&gt;::toString
  }
 
  class Date extends Table.Column&lt;String&gt; {
    { name = &quot;Date&quot;; 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

Online demo (updated)

Verified with compiler option -Xlint:all

huangapple
  • 本文由 发表于 2020年8月26日 17:44:42
  • 转载请务必保留本文链接:https://go.coder-hub.com/63594889.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定