Java 使用泛型检索泛型类型的类列表

Java 使用泛型检索泛型类型的类列表,java,generics,Java,Generics,我对Java中的泛型比较陌生,所以如果这是学校里经常教的东西,我很抱歉(我几乎是自学成才的)。假设我有下面的接口和抽象类 public interface IChallenge<T> { boolean handle(T e); Class<? extends T> getType(); } 当我试图将一个特定的类传递给handle方法时,我的问题就出现了。由于泛型可以是任何类,并且同一类型可以有多个质询,因此我将质询存储在一个映射中,其类型作为键 pr

我对Java中的泛型比较陌生,所以如果这是学校里经常教的东西,我很抱歉(我几乎是自学成才的)。假设我有下面的接口和抽象类

public interface IChallenge<T> {
    boolean handle(T e);
    Class<? extends T> getType();
}
当我试图将一个特定的类传递给
handle
方法时,我的问题就出现了。由于泛型可以是任何类,并且同一类型可以有多个质询,因此我将质询存储在一个映射中,其类型作为键

private Map challenge.handle(A));
但我很难弄清楚“某物”里有什么。如果我使用通配符
符号,那么IntelliJ表示
句柄
必须包含一个需求参数:捕获?当我通过A级考试时,我最好不要指定
AbstractChallenge
的类型,但我想要一个更好的解决方案


有什么想法吗?谢谢

你想要的是这样的(我在这里接受了评论):

以下是一个例子:

Integer a = Integer.valueOf(5);
// #1 -> ok: a is a Number
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #2 -> ok: a is an Integer
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #3 -> ok: a is an Object
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #4 ->ko: a is not a String
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
如果您希望避免这种情况,但仍然能够处理任何挑战,您应该确保持有/构建挑战的类正确地执行此操作:

public <T> void addChallenge(Class<T> type, IChallenge<T> challenge) {
  challenges.computeIfAbsent(type, ignored -> new ArrayList<>()).add(challenge);
}
由于除了
ChallengeHolder
类提供的功能外,公众无法访问挑战,因此使用
对象
应该没有问题

如果您需要按需创建
IChallenge
,那么您可能需要这样一个实现:

public class LazyChallenge<T> implements IChallenge<T> {
  private final Class<IChallenge<T>> impl;
  private IChallenge<T> value;

  public LazyChallenge(IChallenge<T> impl) {
    this.impl = impl;
  }

  public boolean handle(T o) {
    if (value == null) {
      try {
        value = impl.getConstructor().newInstance();
      } catch (java.lang.ReflectiveOperationException e) { // ... a bunch of exception your IDE will fill in ...
        throw new IllegalStateException(e);
      }
    }
    return value.handle(o);
  }
}
或者可以使用lambda来避免反射:

public class LazyChallenge<T> implements IChallenge<T> {
  private final Class<IChallenge<T>> supplier;
  private IChallenge<T> value;

  public LazyChallenge(Supplier<IChallenge<T>> supplier) {
    this.supplier = supplier;
  }

  public boolean handle(T o) {
    if (value == null) {
      value = supplier.get();
    }
    return value.handle(o);
  }
}
如果我要实现它,我会使用lambda方法,因为这样可以避免反射陷阱(try-catch、可见性问题,特别是考虑到java9++引入了模块,…)

上面定义的
LazyChallenge
可能有助于避免创建多个
StringChallenge
。在这种情况下,最好让it实现
Supplier
,而不是
IChallenge


整个离题并没有改变我之前指出的:确保只有
ChallengeHolder
读/写地图。

如果我理解正确,您希望类作为地图的键,而不是对象的键。所以这应该是私有的
Map>challenges=newhashmap()。还要注意,我将列表类型从
AbstractChallenge
更改为
IChallenge
。使用接口而不是抽象实现总是更好的。获取所有处理特定类型的“挑战”类。2.从该列表中,删除任何成功处理事件的“挑战”?@markspace Yes!我已经正确地计算了删除挑战(如果已完成)的方法,但还没有计算出如何获取具有指定类型的挑战列表。我将重新编辑我的帖子以使其更清晰。@magicmn我最初尝试过(虽然是用AbstractChallenge而不是IChallenge),IntelliJ说
Required type:List Provided:List我不完全确定如何使用您指定的
addChallenge
方法。现在,对于创建的每个质询,我都有一个
类>
列表,当加载特定质询时,程序将使用
.newInstance()
实例化。我应该换一种方式吗?我只需要一次加载一定数量的挑战,而不是全部
challenges.get(Integer.class).add((Number a) -> a.intValue() > 10); // #1
challenges.get(Integer.class).add((Integer a) -> a.intValue() > 10); // #2
challenges.get(Integer.class).add((Object a) -> a != null); // #3
challenges.get(Integer.class).add((String a) -> a.length() > 10); // #4
Integer a = Integer.valueOf(5);
// #1 -> ok: a is a Number
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #2 -> ok: a is an Integer
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #3 -> ok: a is an Object
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
// #4 ->ko: a is not a String
challenges.get(a.getClass()).removeIf(c -> c.handle(a));
public <T> void addChallenge(Class<T> type, IChallenge<T> challenge) {
  challenges.computeIfAbsent(type, ignored -> new ArrayList<>()).add(challenge);
}
class ChallengeHolder {
  private final Map<Class<?>, List<IChallenge<?>>> challenges;
  public ChallengeHolder() {
    this.challenges = new HashMap<>();
  }

  public <T> void addChallenge(Class<T> type, IChallenge<T> challenge) {      
      challenges.computeIfAbsent(type, ignored -> new ArrayList<>()).add(challenge);
  }

  public boolean handle(Object a) {
    List<IChallenge<T>> challengers = challenges.get(a);
    if (challengers == null) return false;
    return challengers.removeIf(c -> c.handle(a));
  }   

}
public class LazyChallenge<T> implements IChallenge<T> {
  private final Class<IChallenge<T>> impl;
  private IChallenge<T> value;

  public LazyChallenge(IChallenge<T> impl) {
    this.impl = impl;
  }

  public boolean handle(T o) {
    if (value == null) {
      try {
        value = impl.getConstructor().newInstance();
      } catch (java.lang.ReflectiveOperationException e) { // ... a bunch of exception your IDE will fill in ...
        throw new IllegalStateException(e);
      }
    }
    return value.handle(o);
  }
}
challengeHolder.addChallenge(String.class, new LazyChallenge<>(StringChallenge.class));
public class LazyChallenge<T> implements IChallenge<T> {
  private final Class<IChallenge<T>> supplier;
  private IChallenge<T> value;

  public LazyChallenge(Supplier<IChallenge<T>> supplier) {
    this.supplier = supplier;
  }

  public boolean handle(T o) {
    if (value == null) {
      value = supplier.get();
    }
    return value.handle(o);
  }
}
challengeHolder.addChallenge(String.class, new LazyChallenge<>(StringChallenge::new));
class ChallengeHolder {
  private final Map<Class<?>, List<Supplier<IChallenge<?>>>> challenges;
  public ChallengeHolder() {
    this.challenges = new HashMap<>();
  }

  public <T> void addChallenge(Class<T> type, Supplier<IChallenge<T>> challenge) {      
      challenges.computeIfAbsent(type, ignored -> new ArrayList<>()).add(challenge);
  }

  public boolean handle(Object a) {
    List<IChallenge<T>> challengers = challenges.get(a);
    if (challengers == null) return false;
    return challengers.removeIf(c -> c.get().handle(a));
  }   

}

StringChallenge existing = ... ;
// always reuse an existing
challengeHolder.addChallenge(String.class, () -> existing);
// bring a new challenge each time that ChallengeHolder::handle is called
challengeHolder.addChallenge(String.class, StringChallenge::new);