繁体   English   中英

泛型对象的扩展抽象类列表

[英]List of generic object s extending abstract class

我有

  • 1个表格视图
  • 我在电视上使用的1个可观察列表
  • 1个称为Media的抽象基类
  • 从Media继承的2个子类称为Book和CD

我想做什么

检查列表中的当前元素是CD还是Book,如果是,则将其名称设置为字段fldName中的字符串。

问题

final ObservableList<Object extends Media> medium = FXCollections.observableArrayList(

它说,

  • Main.Media是原始类型。 泛型Main.Media的引用应参数化
  • 类型安全性:为varargs参数创建Main.Media>的通用数组
  • 令牌“扩展”的语法错误,预期
  • ObserableList类型的参数数目不正确; 不能使用参数对其进行参数化
  • 行断点:主[行:35]-开始(阶段)

代码

final TableView<Object> mediaTable = new TableView<>();
final ObservableList<Object extends Media> medium = FXCollections.observableArrayList(
            new Book(),
            new CD(),
            new Book(),
            new CD(),
            new Book()
        );


/*Lots of other stuff in between here*/
/*The first if-statememen checks if any field(fldName) is empty*/

else if(medium.get(mediaTable.getSelectionModel().getSelectedIndex()).getClass()
         .getSimpleName() == "CD" || 
          medium.get(mediaTable.getSelectionModel().getSelectedIndex())
         .getClass().getSimpleName() == "Book"){
    String strName = mediaTable.getSelectionModel().getSelectedIndex()).getName();
                    if(!fldName.getText().isEmpty()){
                        strName = fldName.getText();
                    }
}

/*Lots of other stuff below here*/

这在一定程度上有所帮助,但不是完整的解决方案: 调用泛型成员的member-function

我认为这可能有一些解决方案,但我不明白: Java-通用抽象类的通用列表

那么我该如何解决呢?

编辑:媒体,书籍和CD类的定义,

    public abstract class Media<T>{
    private String author;
    private String name;
    private String genre;
    private String publisher;
    private String mediaType;
    private double price;
    private int year;
    private T length;
    //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*//
    public String getAuthor(){
        return author;
    }
    public String getName(){
        return name;
    }
    public String getGenre(){
        return genre;
    }
    public String getPublisher(){
        return publisher;
    }
    public String getMediaType(){
        return mediaType;
    }
    public double getPrice(){
        return price;
    }
    public int getYear(){
        return year;
    }
    public T getLength(){
        return length;
    }
    //*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*=*//
    public void setAuthor(String author){
        this.author = author;
    }
    public void setName(String name){
        this.name = name;
    }
    public void setGenre(String genre){
        this.genre = genre;
    }
    public void setPublisher(String publisher){
        this.publisher = publisher;
    }
    public void setMediaType(String mediaType){
        this.mediaType = mediaType;
    }
    public void setPrice(double price){
        this.price = price;
    }
    public void setYear(int year){
        this.year = year;
    }
    public void setLength(T length){
        this.length = length;
    }

    public Media(String name, String author, String genre, String publisher, String mediaType, double price, int year){

        setName(name);
        setAuthor(author);
        setGenre(genre);
        setPublisher(publisher);
        setMediaType(mediaType);
        setPrice(price);
        setYear(year);

    }
}

public class Book extends Media<Integer>{
    private String coverType;

    public String getCoverType(){
        return coverType;
    }
    public void setCoverType(String coverType){
        this.coverType = coverType;
    }
    public Book(String name, String author, String genre, String publisher, String mediaType, double price, 
                int year, int length, String coverType){
        super(name, author, genre, publisher, mediaType, price, year);
        setLength(length);
        setCoverType(coverType);
    }
    public Book(){
        super("N/A", "N/A", "N/A", "N/A", "N/A", 0.0, 0);
        setLength(0);
        setCoverType("N/A");
    }
}   

public class CD extends Media<Double>{
    private String type;

    public String getCdType(){
        return type;
    }
    public void setCdType(String type){
        this.type = type;
    }
    public CD(String name, String author, String genre, String publisher, String mediaType, double price, 
                int year, double length, String type){
        super(name, author, genre, publisher, mediaType, price, year);
        setLength(length);
        setCdType(type);
    }
    public CD(){
        super("N/A", "N/A", "N/A", "N/A", "N/A", 0.0, 0);
        setLength(0.0);
        setCdType("N/A");
    }
}

编辑2:在TableView和ObservableList中从“对象扩展媒体”更改为“媒体”,现在出现以下错误:

  • Main.Media是原始类型。 引用通用类型Main.Media应该参数化
  • 类型不匹配:无法从ObservableLIst >>转换为ObservableList
  • 类型安全性:为varargs参数创建Main:Media>的通用数组

代码

final TableView<Media> mediaTable = new TableView<>();
final ObservableList<Media> medium = FXCollections.observableArrayList(
            new Book(),
            new CD(),
            new Book(),
            new CD(),
            new Book()
        );

编辑3:

public class Main extends Application {

    @Override
    public void start(Stage primaryStage) {

    final TableView<Media<T>> mediaTable = new TableView<>();
    final ObservableList<Media<T>> medium = FXCollections.observableArrayList(
        new Book(),
        new CD(),
        new Book(),
        new CD(),
        new Book()
    );

ObservableList<Object extends Media>是语法错误的原因是,类型参数范围仅适用于定义类或方法,而不适用于变量。
更精确地讲-您可以在类型参数上设置边界,而不是在类型本身上设置边界: class MyClass<T extends OtherClass> {}可以,因为您将边界应用于类型参数 T

定义变量时,您必须具有特定的类型,因此在您的情况下,您将具有ObservableList<Media> ,因为您知道列表中的所有项目都是Media实例(无论是Book还是CD )。

请注意,在泛型类或方法的范围内,类型参数本身是绑定的,因此您可以进行如下操作:

class MyClass<T extends OtherClass> {
    // When instantiating a MyClass object, T will be bound, and while you don't know the exact type
    // you can be certain it will be `OtherClass`, or some class that extends it. 
    private List<T> myList;
}

TableViewTableViewObservableList都应将Media作为类型参数,因为这是您愿意接受的最通用的类​​型。

至于检查列表中每个项目实际上是哪种类型,正如@RC所说, instanceof是一个比比较类名更好(并且更安全,并且可能更快)的选项:

// Since we declared mediaTable as TableView<Media>, getSelectedItem() returns a Media object, which will either be a Book or a CD
Media currentMedia = mediaTable.getSelectionModel().getSelectedItem();
if (currentMedia instanceof Book) {
    // safe cast because we know currentMedia is indeed an instance of Book
    Book currentBook = (Book)currentMedia;
    ...
} else if (currentMedia instanceof CD) {
    CD currentCD = (CD)currentMedia;
}

像@sillyfly所说的那样将type参数更改为Media是正确的,但是您还必须在其中转换项目。

因此,如果以前的版本如下所示:

final TableView<Media> mediaTable = new TableView<>();
final ObservableList<Media> medium = FXCollections.observableArrayList(
            new Book(),
            new CD(),
            new Book(),
            new CD(),
            new Book()
        );

正常运行的版本将如下所示:

final TableView<Media<?>> mediaTable = new TableView<>();
final ObservableList<Media<?>> medium = FXCollections.observableArrayList(
            (Media<?>)new Book(),
            (Media<?>)new CD(),
            (Media<?>)new Book(),
            (Media<?>)new CD(),
            (Media<?>)new Book()
        );

并且分别将类型参数设置为Media ,然后将Book(例如)制作为(Media)new Book()

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM