0

I know there are a lot of questions about similar issues already, but I haven't found one to directly address this one.

Here is the skeleton of the code I'm trying to implement:

class MyObj<T> {
    // Internals are unimportant ...
}

private <T> void foo(T arg) {
    Class<MyObj<T>> clazz = // What do I write here?

    // Here is one thing that works, but is quite ugly:
    @SuppressWarnings("unchecked")
    clazz = (Class<MyObj<T>>)(new MyObj<T>().getClass())

    // ...

    // Later, clazz is passed to a constructor of some other class
    OtherClass<MyObj<T>> foo = new OtherClass<>(clazz);
}

Question 1: Does anyone have a better suggestion of how to populate clazz ? Ideally, it would avoid calling new.

Question 2: Given the ugly (but working) code above, are there any situations where it could break? I don't like to @SuppressWarnings, and worry about problems I might be hiding.

jwd
  • 10,837
  • 3
  • 43
  • 67
  • Related: [How to access the .class from a class with a Generic?](http://stackoverflow.com/questions/17634631/how-to-access-the-class-from-a-class-with-a-generic) – rgettman Sep 23 '14 at 17:23
  • Due to erasure, `Class>` will just be bound to any `Object`. It may be better to use `Class>` instead; this way, you could also just pull the class information from `arg` via `arg.getClass()`. – Makoto Sep 23 '14 at 17:23
  • 1
    What are you trying to do with `clazz`? – Ted Hopp Sep 23 '14 at 17:23
  • @TedHopp clazz, in my case, is passed on to yet another layer of generics. It will be passed to another class constructor, which uses that Class internally to instantiate, etc. I'll update the question to reflect this. – jwd Sep 23 '14 at 17:47
  • @Makoto: If I understand correctly, I can't use `arg.getClass()` since that will give me a `Class`, whereas I want a `Class>`. – jwd Sep 23 '14 at 17:49

1 Answers1

3

To avoid instantiating, you can write:

Class<MyObj<T>> clazz = (Class) MyObj.class;

Due to erasure, there exists a single Class instance for MyObj, regardless of whatever type parameters it might have, so although this is ugly, it is safe.

ruakh
  • 175,680
  • 26
  • 273
  • 307
  • Thank you, this works! I also saw the following variant at another question linked in comments: `clazz = (Class>)(Class>)MyObj.class`. Funny how that double-cast is needed in that case... – jwd Sep 23 '14 at 17:54
  • @jwd: Imagine that you want to cast from `Integer` to `String`. They are incompatible types, so you couldn't write `String s = (String) i`: the compiler can tell that that's not O.K. You'd have to upcast to `Object` and *then* downcast to `String`: `String s = (String) (Object) i`. (And then you'd get a `ClassCastException`, of course.) As far as the type system is concerned, this is the same thing; you need to upcast your `Class` to a `Class` or a `Class>` in order to trick the compiler into letting you downcast to `Class>`. *[continued]* – ruakh Sep 23 '14 at 18:13
  • *[continued]* The reason that my version requires only a single explicit cast -- an upcast to `Class`, with no downcast to `Class>` -- is that raw types have special treatment in Java, and allow you to implicitly (and unsafely) convert to any corresponding parameterized type. – ruakh Sep 23 '14 at 18:15