>So, a colleague of mine recently is trying to use generics to enforce
>type-correctness (good) in an interface method that takes object. He
>needs a specific subtype and so we try this:
I don't see any generics in your example.
>public void someMethod(Object myType)
>if(SomeGeneric instanceof MyType) ... // compile error
>if(SomeGeneric.class.isAssignableFrom(MyType.class)) // compile error
You're already confusing me with names - myType isn't a type, it's an object
reference. I have no idea what SomeGeneric is, and you don't tell me the
compile errors, so I can't guess what you're trying to do.
A small self-contained code sample, and actual error messages would help a
lot.
--
Mark Rafn dagon@dagon.net <http://www.dagon.net/>
if(T instanceof arg) ... // compile error
if(T.class.isAssignableFrom(arg.getClass())) // compile error
public interface I {
public void method1(Object arg);
}
public class C<T> implements I {
public void method1(Object arg);
// If arg is of type T, use it, otherwise ignore it
// Note: I can't use T.class to compare because T doesn't exist at
runtime
T var = null;
try {
var = (T)arg;
}
catch (ClassCastException e) {
return;
}
... some more code here
}
}
Is this better?
Mark Rafn - 10 Aug 2007 23:04 GMT
>if(T instanceof arg) ... // compile error
Right. T doesn't exist at runtime, only at compile.
>if(T.class.isAssignableFrom(arg.getClass())) // compile error
Here too. The type parameter T can't be used except for compile-time checking
and shortcuts.
>public interface I {
> public void method1(Object arg);
[quoted text clipped - 4 lines]
> // If arg is of type T, use it, otherwise ignore it
> // Note: I can't use T.class to compare because T doesn't exist at runtime
There is no runtime type T. In other words, you cannot make a runtime
choice based on whether an object is type T.
> T var = null;
> try {
> var = (T)arg;
This will generate a warning "[unchecked] unchecked cast" so you know that the
cast isn't actually doing anything.
> }
> catch (ClassCastException e) {
[quoted text clipped - 4 lines]
> }
>}
>Is this better?
Clearer, but you're trying to do something that type erasure prevents you from
doing. Depending on your object model, you might prefer to have two different
methods rather than (or in addition to, if you have cases where it's needed)
generics.
Have multiple methods method1(Foo arg), method1(Bar arg), which each behave
correctly for their arg.
--
Mark Rafn dagon@dagon.net <http://www.dagon.net/>
Joshua Cranmer - 10 Aug 2007 23:10 GMT
> if(T instanceof arg) ... // compile error
arg is a variable not a typename.
> if(T.class.isAssignableFrom(arg.getClass())) // compile error
What is 'T.class'? At runtime, the type argument is statically compiled
into the class file.
> var = (T)arg;
Is this even legal?
> Is this better?
No. Not by a long shot.
When one needs to work with generics, one ends up working with Class
objects a lot. Your class again:
class C<T> implements I {
private Class<T> tClass;
public C(Class<T> tClass) {
this.tClass = tClass;
}
public void method1(Object arg) {
T var = tClass.cast(arg);
// [...]
}
}
Even better would be to make your interface generic as well, so that
less runtime checks would be needed.
Java Generics are NOT C++ Templates. Only one class file is ever used,
so the types of type arguments are erased to the tightest bound known,
which is generally Object. Because each invocation of T is more or less
are equivalent to Object (or the relevant type erasure), constructs like
T[], T.class, (T), and instanceof T are prohibited.
For more information, read Sun's generics information (look at one of
the more recent generics threads for the link; I don't know it off the
top of my head).

Signature
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
Ben Phillips - 11 Aug 2007 23:15 GMT
> Because each invocation of T is more or less
> are equivalent to Object (or the relevant type erasure), constructs like
> T[], T.class, (T), and instanceof T are prohibited.
Not quite. (T) is permitted but gives the "unchecked" warning. If you
are in say "class Bar <T extends Foo>" a cast like (T) ends up checking
only that the thing is a Foo. Quite often Foo is Object and then it
checks nothing, of course.
There's some way to suppress those warnings but it's usually a sign of a
broken design if you get the urge to do so. Try to find another way to
do what you want to do in a type-safe manner. It will usually involve a
Class<T>.
Danno - 10 Aug 2007 23:22 GMT
> if(T instanceof arg) ... // compile error
public static <T> void testElement(T t) {
if (t instanceof String) {
System.out.println("t is a String");
}
}
Yeah that works
> if(T.class.isAssignableFrom(arg.getClass())) // compile error
Looks like that works too.
if(t.getClass().isAssignableFrom(String.class))
System.out.println("Weee");
> public interface I {
> public void method1(Object arg);
[quoted text clipped - 18 lines]
>
> }
public class C<T> {
public void method1(T arg) { //arg is of type T
//There is no need to test. T
// is going be what you declare for in the first place.
}
}
> So, a colleague of mine recently is trying to use generics to enforce
> type-correctness (good) in an interface method that takes object. He
[quoted text clipped - 22 lines]
>
> I don't get why those fail. Can someone explain?
You can only do instance tests on reified types. A reified type is a
type that has runtime representation. Including raw types, type
variables (like T), Parameterized types with actual parameters, etc.