0

First, I have a simple template, nothing fancy:

public abstract class ListOfK<K> {
   private List<K> insides = new ArrayList<>(); 
}

Next, I'm creating a service interface using the template

public abstract interface SomeService<K extends ListOfK<K>> {
    int calculateSomething (K input);
    int calculateAnother (ListOfK<K> list);
}

So far so good with the abstraction.

Now, let's get to the implementation

public class ListOfString extends ListOfK<String> {

}

and implementation of SomeService:

public class SomeServiceImpl extends SomeService<String> {
  @Override
  public int calculateSomething(String input) {
    return 0;  // TODO impl
  }

  @Override
  public int calculateAnother(ListOfK listOfK) {
    return 0;  // TODO impl
  }
}

Somehow, when SomeServiceImpl extends SomeService<String>, it marks Type parameter java.lang.String is not within its bound; should extend ListOfK<String>

What should I input as implementation of SomeService so it doesn't give error? Or do I make mistake with SomeService? I just want a class whom input is a another class using Generic.

Thanks in advance.

Yuliana
  • 13
  • 2
  • 6
    What do you think `SomeService>` means? – Sotirios Delimanolis May 09 '19 at 12:44
  • an interface named `SomeService` registering `K` as generic while using class `ListOfK` please correct me if I'm wrong. I tried `SomeService>` but it doesn't give. – Yuliana May 09 '19 at 12:51
  • [What is PECS (Producer Extends Consumer Super)?](https://stackoverflow.com/q/2723397/5515060) – Lino May 09 '19 at 12:53
  • What do you mean by _using class_? Using it how/where? What role does the `extends` keyword play? – Sotirios Delimanolis May 09 '19 at 12:55
  • @SotiriosDelimanolis it utilizes `ListOfK` in its process, for example later in the form of method ```int calculateSomething (K input); int calculateAnother (ListOfK list);``` – Yuliana May 09 '19 at 13:47
  • `SomeService` is invalid, because `K` cannot be `String`, because you said `K` must be a `ListOfK`, and `String` does not extend from `ListOfK`. This would be a problem even if it weren't for the recursive use of `K` in the definition of `K`. – Daniel Pryden May 09 '19 at 13:58
  • @DanielPryden Change it into `public class SomeServiceImpl extends SomeService` doesn't solve it either, the message becomes `Type parameter ListOfString is not within its bound; should extend ListOfK` – Yuliana May 09 '19 at 14:03

2 Answers2

0

The key insight here is that K in the context of the ListOfK class is not the same type as K in the context of the SomeService class. In fact, in your definition of SomeService, you're saying that K needs to itself be a ListOfK, which I suspect is your problem.

  • Does calculateSomething need to take (1) a single value, or (2) a ListOfK of values?
  • Does calculateAnother need to take (1) a ListOfK of values, or (2) a ListOfK of ListOfK values?

I think you want option 1, but you've actually chosen option 2.

To fix this, don't constrain K in SomeService:

public interface SomeService<K> {
    int calculateSomething(K input);
    int calculateAnother(ListOfK<K> list);
}
Daniel Pryden
  • 59,486
  • 16
  • 97
  • 135
  • It works like a charm. Thank you @daniel-pryden. You're right, I want option 1 but somehow got myself option 2. Thanks again :) – Yuliana May 09 '19 at 14:18
-1

The issue lies in the way you are defining the SomeService interface. Your code of <K extends ListOfK<K>> says that "we need a class K which extends ListOfK, which uses K as its type parameter." So that class would have to look something like:

public class Test extends ListOfK<Test> {

Which doesn't make any sense. It shouldn't only use itself inside of the list. If you change the interface to something like:

public abstract interface SomeService<K extends ListOfK<?>> {

It should fix your issue.

Fishy
  • 1,275
  • 1
  • 12
  • 26
  • You say that that code "doesn't make any sense" but that's not true. There are definitely good use cases for recursive parameterized types. Using an unbounded type wildcard is not a good solution (probably better to introduce a new type variable instead, in most cases). – Daniel Pryden May 09 '19 at 13:56