-1
public static void main(String ...args) {
  Service<?> s = determine(args[0]);

  //getting error here: cannot pass Object to ?
  s.process(new Object());
}

static Service<?> determine(String name){
   //return a service
}

interface Service<I> {
  void process(I in);
}

I'm not able to pass my Object to service method. Why and how to resolve it? Thanks

SoT
  • 898
  • 1
  • 15
  • 36

1 Answers1

2

A Service<?> instance's process method accepts an instance of a specific but unknown class.

You can't directly create a Service<?>: you have to create an instance of with a concrete value of the type variable. All of the following are subtypes of Service<?>: Service<Object>, Service<Integer>, Service<Map<String, List<Object>>> etc. The process method of these example types expect an Object, Integer and Map<String, List<Object>> respectively.

But the compiler doesn't know which of these it is, so it doesn't allow you to invoke the process method with a non-null value, because it might be the wrong kind of non-null value.

You can only invoke this with a literal null, which is the only thing that can be cast to any type.

s.process(null);

If you want to be able to pass Object into the process method, you have to make determine return a Service<Object>; or remove the type variable from the Service interface, and make process just accept Object.

Andy Turner
  • 137,514
  • 11
  • 162
  • 243
  • I decide to use raw type. Thanks for your replying – SoT Feb 22 '23 at 14:27
  • 2
    No. [Don't use raw types](https://stackoverflow.com/questions/2770321/what-is-a-raw-type-and-why-shouldnt-we-use-it). If you need to be able to pass "anything" into the Service, remove the generic and make `process` accept a plain `Object`. – Andy Turner Feb 22 '23 at 14:28
  • The difference is that using Object places the burden onto the implementor of `Service` to handle the fact it might be given something of the wrong type; using raw types makes it look to the caller like you can pass anything, and to the implementor of the interface like they will get a specific type. Things may fail immediately, or maybe proceed OK until much later, when it turns out that you have introduced heap pollution and you get a random, untraceable failure elsewhere in your code. – Andy Turner Feb 22 '23 at 14:31
  • I mean raw type of `determine(String name)`. It will return raw Service. Is it ok? – SoT Feb 22 '23 at 14:34
  • 2
    No. Don't use raw types at all. They exist purely for backwards compatibility with code written pre-Java 5 (which was released nearly 20 years ago). Do not use them in new code. – Andy Turner Feb 22 '23 at 14:35
  • I cannot make `process` accept Object. It must be . And the `determine` will return Service which will be dynamic. So the method signature must be > or raw type. Am i correct? – SoT Feb 22 '23 at 14:39
  • 1
    `I` may be dynamic; but unless you know something about the concrete type, you cannot safely pass in a non-null value. The code's design is fundamentally broken from a type safety perspective. – Andy Turner Feb 22 '23 at 14:40
  • 1
    For the code you've shown above, a better approach is to use a `switch (name)` inside the `main` method: then you can choose an appropriate `Service`, `Service` etc and process it type-correctly. – Andy Turner Feb 22 '23 at 14:42