what do you mean I can't (someObj instanceof MyGenericType) ?

S

Sideswipe

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:

public void someMethod(Object myType)

if(SomeGeneric instanceof MyType) ... // compile error

if(SomeGeneric.class.isAssignableFrom(MyType.class)) // compile error


SomeGeneric var = null;

try {
var = (SomeGeneric)myType; // compiles, and works as expected.

}
catch(ClassCastException cce) {
// invalid type, ignore
}

If Generics are a type substitution and erase, no matter WHAT type
'SomeGeneric' is from is MUST has '.class' and work with 'instanceof'

I don't get why those fail. Can someone explain?
 
M

Mark Rafn

Sideswipe said:
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.
 
S

Sideswipe

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?
 
D

Danno

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:

public void someMethod(Object myType)

if(SomeGeneric instanceof MyType) ... // compile error

if(SomeGeneric.class.isAssignableFrom(MyType.class)) // compile error

SomeGeneric var = null;

try {
var = (SomeGeneric)myType; // compiles, and works as expected.

}

catch(ClassCastException cce) {
// invalid type, ignore

}

If Generics are a type substitution and erase, no matter WHAT type
'SomeGeneric' is from is MUST has '.class' and work with 'instanceof'

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.
 
M

Mark Rafn

Sideswipe said:
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);
}

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

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) {
return;
}

... some more code here
}
}
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.
 
J

Joshua Cranmer

Sideswipe said:
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).
 
D

Danno

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);

}

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
}

}
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.
}
}
 
B

Ben Phillips

Joshua said:
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>.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top