4

I have the class

public class ReportItem<ReportType extends Report>{ }

and the class

public abstract class Report implements Iterable<ReportItem>{

    private List<ReportItem<? extends Report> > itemList;

    public void add(ReportItem<? extends Report> item){
        itemList.add(item);
    }

    //Some other staff

}

public class ConcreteReport extends Report{ 
    //Some staff
}

The thing is the method add(ReportItem<? extends Report>) is unsafe in the way I could provide items aren't tied with the current report, but tied with some another and the compiler won't complain.

Is it possible to write the method add in a type-safe way, i.e. we could pass as an argument only that ReportItem<T> where T is the type of a current report.

user3663882
  • 6,957
  • 10
  • 51
  • 92

1 Answers1

4

I think you are looking for the following.

public abstract class Report<T extends Report<T>> implements Iterable<ReportItem<T>>{

    private List<ReportItem<T>> itemList;

    public void add(ReportItem<T> item){
        itemList.add(item);
    }

    //Some other stuff

}

public class ConcreteReport extends Report<ConcreteReport> { 
    //Some stuff
}

The way it works is that:

  • You want to parametrize ReportItem<T> with something that extends from Report
  • You want to make sure that the list of ReportItem<T> all belong to the same type of Report

In order to bind the T parameter of ReportItem<T> to something that extends from Report, you need to parametrize the Report itself:

public abstract class Report<T> implements Iterable<ReportItem<T>>

you add the bind that it needs to extend from Report

public abstract class Report<T extends Report> implements Iterable<ReportItem<T>>

But you are specifying the bound for the raw type of report, which doesn't work, so you need to provide Report with the type parameter that the report receives, which is T.

public abstract class Report<T extends Report<T>> implements Iterable<ReportItem<T>>

This way you can parametrize the List<ReportItem<T>> with the concrete type that you extend with:

public class ConcreteReport extends Report<ConcreteReport> { 

This way the list will be

public List<ReportItem<ConcreteReport>> itemlist;

Which is what you wanted.

And it works! :) I just hope my explanation of it makes sense.

EpicPandaForce
  • 79,669
  • 27
  • 256
  • 428