Can javac infer the right generics for using x.getClass() and x together?

Viewed 89

I'd like to have a generic method that takes in an object of some type T, and also a Class representing that type. Eventually I plan to use this to create a Map<Class<?>, Object>, where I know that each class will map to an object of exactly its own type; I know I won't be able to convince the compiler of this, but I'd like to keep compile-time generic safety for as much of the code as I can. Here's a minimal example demonstrating the problem I'm running into:

public class Example {
  public static <T extends Number> void foo(Class<T> c, T x) {
    ;
  }

  public static void bar(int x) {
    foo(Integer.class, x);
  }

  public static void baz(Number x) {
    foo(x.getClass(), x);
  }
}

I can write the foo method with no problem, and it has the signature I want, and I can use it if I know exactly what types I have at compile time, as in bar, but I can't use it on objects of any type, as I try to in baz: baz does not compile, citing:

Example.java:11: error: method foo in class Example cannot be applied to given types;
    foo(x.getClass(), x);
    ^
  required: Class<T>,T
  found: Class<CAP#1>,Number
  reason: inferred type does not conform to lower bound(s)
    inferred: CAP#1
    lower bound(s): Number
  where T is a type-variable:
    T extends Number declared in method <T>foo(Class<T>,T)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Number from capture of ? extends Number

I think I understand the problem here: x.getClass() returns Class<? extends Number>, which establishes <? extends Number> as T, but x continues to have type Number, requiring T to be Number, thus the conflict. When I wrote this, I was hoping that the compiler would know that x.getClass() and x do share exactly the same T, but it makes sense that it can't know that.

So, what do I do here? Is there a way I can write something like foo and also something like baz? Should I abandon compile-time safety and do some casts at runtime? Is there a better way altogether to approach my end goal of Map<Class, Object>?

2 Answers
Related