我目前正在嘗試撰寫一個方法,該方法通過 Ant-Objects 串列并回傳AntScouts擴展 Ant 的串列。一般來說,List<Ant>可以包含很多不同的繼承自 Ant 的 Objects。
我也有不同種類螞蟻的列舉:
public enum AntType {
QUEEN,WARRIOR,GATHERER,SCOUT;
public Class getClass(AntType type){
return switch (type) {
case QUEEN -> AntQueen.class;
case WARRIOR -> AntWarrior.class;
case GATHERER -> AntGatherer.class;
case SCOUT -> AntScout.class;
};
}
}
此列舉會導致警告:
Raw use of parameterized class 'Class'
這是當前回傳 a 的方法List<Ant>。
public List<Ant> getAntsType(AntType type){
return ants.stream().filter(ant -> ant.getType() == type).toList();
}
如何撰寫該方法以使其將AntType列舉作為引數并回傳一個List<AntScout>或List<AntWarrior>對應于列舉?我真的不想使用Class<T>clazz 作為論據,因為這會破壞列舉的意義。(我也在其他地方使用那個列舉,所以我無法擺脫它)
如何撰寫方法以獲取 AntType 列舉作為引數并回傳與列舉對應的 List 或 List?
編輯:此評論可能最接近所需的解決方案: Java Method that return different types of generic Lists
uj5u.com熱心網友回復:
使用多型的力量
如何撰寫方法以獲取 AntType 列舉作為引數并回傳與列舉對應的 List 或 List?
你沒有充分的理由過度設計你的代碼。
當你使用繼承時,你的類的設計方式應該允許從多型中受益。
即,通過對所有物件使用超型別Ant并通過覆寫行為與它們進行互動,而無需區分具體實作并通過型別轉換進行操作。
因此,您的方法回傳List<Ant>非常好。
即使您想獲得 a List<AntQueen>orList<AntScout>作為方法執行的結果,那么您也需要 a 使用泛型型別變數T,或者更確切地說T extends Ant,這意味著您需要一個表示T. 并且enum不會幫助您完成這項任務,因為在 Java 中列舉不能是通用的。您需要提供作為方法引數的實體T或Class<T>.
public <T extends Ant> List<T> getAntsByType(Class<T> tClass) {
return ants.stream().filter(tClass::isAssignableFrom).toList();
}
但我建議堅持使用回傳一個超型別Ant宣告方法串列的初始版本,該方法getType()回傳一個 enum 實體AntType。
public List<Ant> getAntsByType(AntType type) {
return ants.stream().filter(ant -> ant.getType() == type).toList();
}
正如我所說,Java 列舉不能是通用的,沒有辦法Class<T>通過它獲得。因此,您可以getClass()從AntType.
public enum AntType {
QUEEN, WARRIOR, GATHERER, SCOUT;
}
模擬自型
但是,如果您仍然確信您的應用程式邏輯需要能夠List<AntScout>從超型別串列中生成具體型別串列,那么您可以使用遞回型別系結。
為此,您需要將超型別定義為Ant<T extends Ant<T>>.
這種方法也稱為模擬自型別習語,可以在所有列舉的父型別的宣告中java.lang.Enum<E extends Enum<E>>以及在Collections.sort(List<T>)定義T為<T extends Comparable<? super T>>.
讓我們為這種情況應用自我型別的成語。
考慮Ant定義為介面的超型別,宣告一個自回傳方法(如果需要宣告一些骨架實作和公共欄位,可以更改為抽象類):
interface Ant<T extends Ant<T>> {
T self();
AntType getType();
}
這里有幾個具體的類:
public static class AntWarrior implements Ant<AntWarrior> {
@Override
public AntWarrior self() {
return this;
}
@Override
public AntType getType() {
return AntType.WARRIOR;
}
}
public static class AntScout implements Ant<AntScout> {
@Override
public AntScout self() {
return this;
}
@Override
public AntType getType() {
return AntType.SCOUT;
}
}
那我們如何使用self()方法執行轉換:
@SuppressWarnings("unchecked")
public static <T extends Ant<T>> List<T> getAntsByType(List<Ant<?>> ants,
AntType type) {
return ants.stream()
.filter(ant -> ant.getType() == type)
.map(ant -> (T) ant.self())
.toList();
}
使用示例:
public static void main(String[] args) {
List<Ant<?>> ants = List.of(new AntWarrior(), new AntScout());
// compiles and runs without issues
List<AntWarrior> antWarriors = getAntsByType(ants, AntType.WARRIOR);
System.out.println(antWarriors);
// compiles and runs without issues
List<AntScout> antScouts = getAntsByType(ants, AntType.SCOUT);
System.out.println(antScouts);
}
輸出:
[AntWarrior{}]
[AntScout{}]
在線演示的鏈接
uj5u.com熱心網友回復:
我會更改您的AntType列舉方法,使其充當流中的過濾器。我不得不猜測類層次結構的其余部分,但這可能會給你一個起點。
import java.util.List;
import static java.util.stream.Collectors.toList;
public class Demo {
private List<Ant> ants = List.of(
new AntQueen(),
new AntScout(),
new AntGatherer(),
new AntWarrior());
public static void main(String[] args) {
var demo = new Demo();
System.out.println(demo.getAntsType(AntType.QUEEN));
}
public List<Ant> getAntsType(AntType type) {
return ants.stream().filter(type::matches).collect(toList());
}
}
class Ant {}
class AntQueen extends Ant {}
class AntWarrior extends Ant {}
class AntGatherer extends Ant {}
class AntScout extends Ant {}
enum AntType {
QUEEN, WARRIOR, GATHERER, SCOUT;
public boolean matches(Ant a) {
return switch (this) {
case QUEEN -> a instanceof AntQueen;
case WARRIOR -> a instanceof AntWarrior;
case GATHERER -> a instanceof AntGatherer;
case SCOUT -> a instanceof AntScout;
};
}
}
uj5u.com熱心網友回復:
如果 s 可以是通用的,這可能是可能enum的,但它們不能。不過,這沒什么大不了的。只需使用帶有一堆public static final欄位和私有建構式的最終類。確實有點冗長,但與enum.
此外,您的getClass()方法應該是帶有 的靜態方法,switch或者是不帶switch. 后者好很多,所以就這樣走了。此外,呼叫它getClass()不是一個好主意,因為它與Object.getClass()方法無關。所以我叫它getAntTypeClass().
這是結果:
public class Main {
public static void main(String[] args) {
System.out.println(AntType.QUEEN.getAntTypeClass().getName());
System.out.println(AntType.SCOUT.getAntTypeClass().getName());
}
}
final class AntType<T extends Ant> {
public static final AntType<AntQueen> QUEEN = new AntType<>(AntQueen.class );
public static final AntType<AntWarrior> WARRIOR = new AntType<>(AntWarrior.class );
public static final AntType<AntGatherer> GATHERER = new AntType<>(AntGatherer.class);
public static final AntType<AntScout> SCOUT = new AntType<>(AntScout.class );
private final Class<T> antTypeClass;
private AntType(Class<T> antTypeClass) {
this.antTypeClass = antTypeClass;
}
public Class<T> getAntTypeClass() {
return antTypeClass;
}
}
interface Ant {}
class AntWarrior implements Ant {}
class AntGatherer implements Ant {}
class AntScout implements Ant {}
class AntQueen implements Ant {}
看到它在 ideone 上作業。
uj5u.com熱心網友回復:
有幾種方法可以做到這一點。
首先,修復列舉中的方法:
public enum AntType {
QUEEN,WARRIOR,GATHERER,SCOUT;
public Class<? extends Ant> getImplClass(){
return switch (this) {
case QUEEN -> AntQueen.class;
case WARRIOR -> AntWarrior.class;
case GATHERER -> AntGatherer.class;
case SCOUT -> AntScout.class;
};
}
}
由于這是一個非靜態方法,因此您不需要將型別作為引數。在您的示例中,尚不清楚串列的來源,但如果我將其添加為引數,它將如下所示:
public static List<Ant> getAntsType(AntType type, List<Ant> ants){
return ants.stream().filter(ant -> ant.getClass() == type.getImplClass()).toList();
}
第二種方法是在 Ant 類中添加一個名為 getType() 的方法,該方法回傳由建構式設定的型別變數。
public class Ant {
private AntType type;
protected Ant(AntType type) {
this.type = type;
}
public AntType getType() {
return type;
}
}
然后在每個子類的建構式中設定型別:
public class AntQueen extends Ant {
protected AntQueen() {
super(AntType.QUEEN);
}
}
那么過濾代碼是這樣的:
public static List<Ant> getAntsType(AntType type, List<Ant> ants){
return ants.stream().filter(ant -> ant.getType() == type).toList();
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/529768.html
標籤:爪哇列表仿制药枚举
