如何使用类型参数实现容器/元素类? [英] How to implement container/element classes by using type parameters?

查看:111
本文介绍了如何使用类型参数实现容器/元素类?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的问题很简短而且很抽象:

我想实现一个 Container 类,是由它所包含的元素(即<$​​ c $ c> Container< T extends Element> )的 Element 类类型进行类型参数化。迄今为止没有什么特别的。但是:元素类及其子类应提供一个寄存器方法,该方法将元素实例到给定的 Container 类(即 register(Container<?super xxx>容器){...}



我觉得这个问题应该可以通过以下几种方式实现。但是,以下代码无效。特别是, ElementBasis#register Sub1Element#register 中的类型参数会导致名称冲突错误。不过,我认为应该有可能找到适当的解决方案。
$ b

public interface Element {
void register(Container< T super Element> container) ;

$ b public class ElementBasis {
@Override
void register(Container< ;? super ElementBasis> container){
container.add(this);



public class Sub1Element extends ElementBasis {
// ...
@Override
void register(Container<?super Sub1Element>容器){
container.add(this);



public class Sub2Element extends ElementBasis {
// ...
}

此外,我希望能够通过提供 ElementGroup 子元素来为元素提供结构。类元素

  public class ElementGroup< T扩展元素>扩展ElementBasis {
// ...
@Override
void register(Container< ;? super T> container){
foreach(T member:groupMemebers){
container.add(member)
}
}
}

我还尝试通过参数化 Element 类来解决这个问题,使得它的类型参数可以在寄存器方法中使用。不幸的是没有成功。



任何人都可以找到适当的实现吗?

解决方案

与其他一些语言不同。 Java没有提供关键字来表示这个类。因此,执行 register >仅接受 Container 类型的方法并不简单。超级这个类。因此,获取 container.add(this); 这一行是有问题的。



一种可能的解决方法如元素良好的一起>此处。这种方法存在种种问题(我个人很不喜欢它),包括getThis trick解决的问题。



一个问题是它使用3个类/接口的链很难工作

  Sub1Element扩展ElementBasis实现元素
ElementBasis
泛型,您可以 以及元素(链接问题的所有解决方案仅涉及长度为2的链)。这里我简单地用集合代替 Container

  public interface Element< E extends Element< E>> {
void register(Collection<?super E>容器);
}

public class ElementBasis< E extends ElementBasis< E>>实现Element< E> {
@Override
public void register(Collection< ;? super E> collection){
collection.add((E)this); //取消选中cast b $ b}
}

public class Sub1Element< E extends Sub1Element< E>>扩展ElementBasis< E> {
@Override
public void register(Collection< ;? super E> collection){
collection.add((E)this); //未经检查的转换


$ $ $
$ b

这是行得通的,但是因为 ElementBasis 是一个具有自引用约束的具体泛型类,您只能在通配符中使用它。



干净地:

  ElementBasis<?> e = new ElementBasis<>(); 
List< ElementBasis<>> list = new ArrayList<>(Arrays。< ElementBasis<> asList(e,e));
e.register(list);
System.out.println(list);

但是,通配符非常混乱,似乎一开始是不必要的(尽管它们不是) 。

考虑到这种方法的所有问题,我会避免它。



我的首选方法是删除所有类型参数,停止尝试使 register 成为 Element 的成员,并使用静态方法。

  public static< E extends Element>无效注册(E e,Collection<?super E> collection){
collection.add(e);
}


My problem in a short and rather abstract form:

I would like to implement a Container class which is type-parametrized by the Element class type of the elements it contains (i.e. Container<T extends Element>). Nothing really special so far. But: The Element class and its sub-classes shall provide a registermethod that adds the Element instance to a given Containerclass (i.e. register(Container<? super xxx> container) { ...} )

I think this problem should be approachable in the following kind of way. However, the following code is not valid. In particular, the type parameters in ElementBasis#register and Sub1Element#registerleads to name clash errors. Still I think it should be possible to find a proper implementation of that problem.

public interface Element {
  void register(Container<T super Element> container);
}

public class ElementBasis {
  @Override
  void register(Container<? super ElementBasis> container) {
    container.add(this);
  }  
}

public class Sub1Element extends ElementBasis {
  // ...
  @Override
  void register(Container<? super Sub1Element> container) {
    container.add(this);
  }  
}

public class Sub2Element extends ElementBasis {
  // ... 
}

Moreover, I would like to be able to give the elements a structure by providing an ElementGroup sub-class of Element:

public class ElementGroup<T extends Element> extends ElementBasis {
  // ...
  @Override
  void register(Container<? super T> container) {
    foreach(T member : groupMemebers) {
      container.add(member)
    }
  }  
}

I also tried to solve the problem by parametrizing the Elementclasses such that its type parameter can be used in the register method. Unfortunately with no success.

Can anyone find a proper implementation?

解决方案

Unlike some other languages. Java does not provide a keyword to mean "this class". So there is no easy way to enforce that register accepts only Containers of type ? super this class. As a result, getting the line container.add(this); to work is problematic.

One possible workaround is to make Element generic, as explained here. There are all sorts of problems with this approach (I personally dislike it strongly), including the issue that is solved by the "getThis trick".

One problem is that it doesn't work easily with a chain of 3 classes/interfaces

Sub1Element extends ElementBasis implements Element

You can do it if you make ElementBasis generic as well as Element (all the solutions to the linked question only involve chains of length 2). Here I have substituted Collection for Container for simplicity.

public interface Element<E extends Element<E>> {
    void register(Collection<? super E> container);
}

public class ElementBasis<E extends ElementBasis<E>> implements Element<E> {
    @Override
    public void register(Collection<? super E> collection) {
        collection.add((E) this);     // Unchecked cast
    }
}

public class Sub1Element<E extends Sub1Element<E>> extends ElementBasis<E> {
    @Override
    public void register(Collection<? super E> collection) {
        collection.add((E) this);     // Unchecked cast
    }
} 

This does work, but because ElementBasis is a concrete generic class with a self-referential constraint, you can only use it with wildcards.

This compiles cleanly:

ElementBasis<?> e = new ElementBasis<>();
List<ElementBasis<?>> list = new ArrayList<>(Arrays.<ElementBasis<?>>asList(e, e));
e.register(list);
System.out.println(list);

However, the wildcards are extremely confusing, and seem at first to be unnecessary (though they are not).

Considering all the problems with this approach, I would avoid it.

My preferred approach would be to get rid of all the type parameters, stop trying to make register a member of Element, and use a static method instead.

public static <E extends Element> void register(E e, Collection<? super E> collection) {
    collection.add(e);
}

这篇关于如何使用类型参数实现容器/元素类?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆