扩展抽象类的通用对象列表

时间:2016-06-16 10:38:36

标签: java generics javafx abstract-class

我有

  • 1 TableView
  • 1我在该电视中使用的可观察列表
  • 1个抽象基类 叫媒体
  • 继承自Media的2个子类,名为Book and CD

我想做什么

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

问题

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

它说,

  • Main.Media是原始类型。对泛型类型Main.Media的引用应该参数化
  • 类型安全:Main.Media的通用数组&gt;是为varargs参数创建的
  • 令牌“extends”,预期
  • 上的语法错误
  • 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*/

这个在某种程度上有所帮助,但不是一个完整的解决方案: Calling member-function of generic member

我认为这个可能有一些解决方案,但我不明白: Java - Generic List of Generic Abstract Classes

那么我该如何解决这个问题?

编辑: Media,Book&amp; amp; 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中从“Object extends Media”更改为“Media”,现在出现了这些错误:

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

代码

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()
    );

2 个答案:

答案 0 :(得分:3)

ObservableList<Object extends Media>是语法错误的原因是类型参数边界仅在定义类或方法而非变量时适用。
更准确地说 - 您可以在类型参数上设置边界,而不是在类型本身上设置边界:class MyClass<T extends OtherClass> {}没问题,因为您在类型参数 T上应用了边界。

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

请注意,在泛型类或方法的范围内,类型参数本身是绑定的,因此您可以使用以下内容:

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;
}

总而言之,您的TableViewObservableList都应该有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;
}

答案 1 :(得分:0)

将类型参数更改为像@sillyfly这样的媒体说是正确的,但你也必须转换里面的项目。

所以如果以前的版本看起来像这样:

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,则必须将书籍(例如)设为(Media)new Book()