The Java Collections interfaces (for example, List or Set) define the contains method to accept any Object.
public boolean contains(Object o)
However, when it comes to implementing this method, the particular collection I'm working on requires that I have a type which is compatible with the generic type E of the class (i.e. either be class E, or a subclass of E, or a class which implements E if E is an interface). In other words, if o is castable to type E, then it is compatible. This presents an issue because Java erases the Generic type information, so something like this isn't possible:
public boolean contains(Object o)
{
if(o instanceof E) // compile error due to type erasures
{
// ... check if this collection contains o
}
return false;
}
My question is what would be the best way to accomplish something like this? The Oracle Article on Type Erasures mentions that this forbidden, but does not offer any solutions to this problem.
I can only think of one semi-elegant way to get around this:
Make a cast to type E. If the cast fails, o cannot be type E or a subclass of type E.
public boolean contains(Object o)
{
try
{
E key = (E) o; // I know it's unsafe, but if o is castable to E then the method should work
// check if this collection contains key
}
catch(ClassCastException e)
{
// invalid type, cannot contain o
}
return false;
}
While this would work, it looks messy (I'm not a big fan of using Exceptions in this manner).
Is there a better way to accomplish this same goal (changing the method signature is not allowed)?
edit: yeah, this doesn't work because E gets erased to Object :(
This is only possible by (1) passing in the expected Class, or (2) examining the generic type parameters of some reflective element that defines <E>. Let me elaborate.
The most common case is to simply require the caller to pass in the runtime class of E.
public class MyClass<E> {
private final Class<E> realType;
public MyClass(Class<E> realType) {
this.realType = realType;
}
public boolean Contains(Object o) {
E e = realType.cast(o); // runtime cast - will throw ClassCastException.
// Could also use realType.isInstance(o)
// or realType.isAssignableFrom(o.getClass())
...
}
}
Caller:
new MyClass<MyObject>(MyObject.class)
This is generally type safe since the compiler will verify that the <E>'s match. Of course the caller can bypass the compiler's checks...nothing you can do about that!
For (2), what I mean is that you can use reflection to examine static generic type parameters. This probably isn't a good option in your case because you must have access to some field, method, or superclass declaration that statically defines <E>. The most common way is to make your class abstract and have callers extend it. This approach is used by Hamcrest's TypeSafeMatcher (see ReflectiveTypeFinder) to great effect. (Note that TypeSafeMatcher is basically just making option (1) easier for the programmer; it still provides a constructor that takes the Class for cases when reflection doesn't work!) If you want to get really fancy, you can inspect getClass().getGenericSuperclass().getActualTypeArguments(). This isn't as easy as it sounds -- see this good article. I'm not even sure that article covers all the edge cases -- you're basically reimplementing the compiler! So just go with option (1) and be happy you're not using generics in C# :-)
I don't get why you are messing with .contains() in this way. The specification of contains() in Collection says that it returns true if the given object equals (in the sense of .equals()) some element of the container. So are you changing the meaning of .contains()? How is your equality defined?
Related
I'm having 2 classes, their internals doesn't matter at all.
class ClassA {
//...
}
class ClassB {
//...
}
And I'm having 2 predicates that use those classes, let's say they look like this
private Predicate<ClassA> classAPredicate() {
return Objects::nonNull;
}
private Predicate<ClassB> classBPredicate() {
return Objects::nonNull;
}
Now, I'm having generic method in external library that is already beeing used by many users and unfortunatelly, it has pretty generic input parameter which is Object which in 90% of cases is Predicate.
What I need to do, is to extend this method functionality by checking type of passed Predicate and based on that, perform some operations.
public void test(Object obj) {
Predicate predicate = (Predicate)obj;
if(predicate.getClass().isAssignableFrom(ClassA.class)) {
System.out.println(predicate.test(new ClassA()));
// logic specific to Predicate<ClassA>
} else {
System.out.println(predicate.test(new ClassB()));
// logic specific to Predicate<ClassB>
}
}
But, during tests I'm passing both Predicates and it fails with Exception in thread "main" java.lang.ClassCastException:
test(classAPredicate());
test(classBPredicate());
I've been debugging and isAssignableFrom() is always returning false so the error is obvious here. I'm not sure if that is the right approach, but I didn't came up with anything else yet. Is there any way to check what is the type of that Predicate?
I know that what I'm trying to implement isn't ideal, but that is current requirement...
In the above, the predicate class is not assignable from Class A.
if(predicate.getClass().isAssignableFrom(ClassA.class))
This causes the else condition to run which passes an instance of B to the Predicate for type A which causes a cast exception. Due to type erasure, it will not be easy to resolve whether an instance of A or B should be passed to the predicate. 3 options are:
Try each input type until one doesn't throw a ClassCastException.
Handle the expected behavior in a new method instead of the existing test function.
Define a more specific interface than Predicate which also has a method to get the type the predicate tests and use the test type in the condition instead. Ex:
public interface TypedPredicate<T> extends Predicate<T> { Class<T> getTestType(); }
Well,
I have been doing Java Generics for going on three years now. I can cite a dozen Stack Overflow posts about "Reifying Java Generics" here: SO1, SO2, SO3. Most importantly, if you are intending to write Java for years and years, you must know that the "Generic Type Parameter" are simply NOT ACCESSIBLE at Run-Time without fields, or extra methods to retrieve them. Java Generics (The syntax that looks like: STUFF<TYPE> with the greater-than, less-than symbols is STRICTLY A COMPILE-TIME FEATURE). At RunTime, the JRE simply has no idea what the Type of the Type-Parameter is - and all it can do is throw ClassCastException if an attempt to misuse occurs.
NOTE: 'Misuse' the generic type such that it throws ClassCastException should sound odd if you are thinking that the JRE does not know and does not care what the type of the type parameter is. Mostly, the way exceptions are thrown, is such that if the code you write inside of a generic makes presumptions, and if it has made faulty presumptions, then this exception will throw.
Read Sun / Oracle's "To Do" list about "Reifying Generic Type Parameters." Also, most importantly, this concept has a very real name that you should read about all the time in Java - and it is called "Run Time Type Erasure" The solution posted before this Stack Overflow Answer says to use try-catch (ClassCastException) blocks, which is, actually, a valid answer.
ALSO: The answer about creating this type of TypedPredicate<T> extends Predicate<T> is not the correct answer if you intend to use your TypedPredicate<T> in any way that expects to allow Java Lambda Syntax to work with it. When you add the following method:
public interface TypedPredicate extends Predicate { Class
getTestType(); }
You will not be able to use the syntax #FunctionalInterface - which is one of the primary benefits of the class java.util.function.Predicate<T> Furthermore, there is a more severe problem in that, the Type of T is not accessible to the programmer and is not known at RunTime by the JRE
You see this part right here (since the answer has a green check mark):
{ Class<T> getTestType(); }
// Can you answer what you would write inside the method body of this
// 'extra-method' that you have added to Predicate<T> ???
The following implementation of a class that extends "Predicate" cannot be instantiated without a constructor. It cannot be called a "#FunctionalInterface" and lambda-expression cannot be used to create them:
// #FunctionalInterface (Commented Out)
public class TypedPredicate<A> implements Predicate<A>
{
public boolean test(A a) { return pred.test(a); }
// This is how the "Class of A" becomes accessible. It this
// version it is a public (and final) field.
public final Class<A> className;
// NOTE: This is the most important part here, the class of
// Variable-Type Parameter 'A' must be passed as a parameter
// to the constructor. The programmer *LITERALLY* has to tell
// the code what type 'A' actually is! This is the *BANE* of
// what I call the Java-Erasure-Fiasco programming.
public TypedPredicate(Predicate<A> pred, Class<A> className)
{
this.pred = pred;
this.className = className;
}
// Again, because a constructor is necessary, this cannot be
// called a "Functional Interface" and it will not work very
// much like a java.util.function.Predicate<T>, but it will
// indeed implement the interface.
}
The best solution would realign whatever logic you have such that you do not need to guess what type a Predicate is! The next best thing would be to try the catch (ClassCastException) version that was suggested in the previous answer.
FINALLY: This idea regarding the java.lang.Class.isAssignableFrom(...) has the right idea behind it - but only if you actually have the Class<T> clazz as an instance in front of you, so to speak. The only way to get an instance of Class<T> would be to pass it to a constructor as in the example I have posted.
I have an Object o that can be casted to type A and type B.
I need a function transformForType(Type t, Object o) that takes a type, lets say A or B and checks if o its that type and process it to transform it.
The usage of the function would be something like that: B result = tranformForType(B.class, o);
My question is whats the way to define the tranformForType function, and if its posible whats the best way using generic types.
Regards.
The Class class already has a method to cast an object at runtime -- the cast method:
Casts an object to the class or interface represented by this Class object.
You just need to call it. It'll throw a ClassCastException like a normal cast would.
B result = B.class.cast(o);
A simple way would be:
static <T> T transformForType(Class<T>, Object o) { ...
that one has no restrictions whatsoever on that T type, but of course, if A/B implement the same interface, or have the same base class, you can further refine that T:
static <T extends ABInterface> T transformForType(Class<T>, Object o) { ...
for example.
And please note: obviously, when you don't have any restrictions on that type you wish to cast, you go with the other answer and call SomeClass.class.cast(). But if you want to allow only specific types, you might want to use such a transformForType() method (which would then use that very cast() method)!
Let's say I've a java base class:
class base {
public Class<? extends base> type;
// ...
}
type stores the classtype of classes which inherit from base
There's another class which stores base objects in a container, it also has a get method which returns objects stored in that container:
class container {
private Vector<base> v;
//...
public <something here> get(int i){
base b=v.get(i);
return b.type.cast(b);
}
How do I implement such a function(container.get), which casts the object to it's correct type before returning it?
It would be nice to be able to program in a cascading style:
JSONObject o;
//...
o.get("nestedObject").get("array").get(3);
You may be misunderstanding what a "cast" is in Java. Except for casts that involve primitive types (such as casting an int to a float), casts don't change objects at all.
One of your instance variables is
private Vector<Base> v;
(Please use the Java convention and start class names with upper-case letters. I've changed base to Base to set a good example.)
The objects that you put in this vector can be of type Base or any subclass of Base. The type of the object is fixed when the object is constructed. Suppose Base has three subclasses, Child1, Child2, and Child3. Those objects can be construted with new Child1(...), new Child2(...), new Child3(...). As soon as you say new Child1(...), you have an object whose type is Child1, and you can't do anything to change that. But since a Child1 is a Base, you can use your Child1 anywhere you can use a Base, such as putting it into your vector v.
Casting just causes the compiler to look at a variable differently. Suppose you say
Base x = v.get(i);
x (if not null) will be a Base or some object of a subclass. The type of x will be whatever you used to construct the object. Now if you say
Child1 y = (Child1)x;
If x is a Child1, y will be a reference to the same object as x. But the compiler will know that y is a Child1, and you can access new methods that are defined in a Child1. (If x isn't a Child1, you get an exception.) But it's important to note that a cast does not create a new object and it does not change the type of anything. It just tells the compiler to look at a variable or expression in a different way.
Given this, you cannot gain anything by trying to write a method that returns a "variable" type. You may as well just write
public Base get(int i){
return v.get(i);
}
The object that it returns could be a Base, Child1, Child2, etc.; it will be the same type as the object was when you put it into the vector. When you call get, if you are expecting the result to be a Child1, you can say
Child1 child = (Child1)container.get(n);
which will throw an exception if the object isn't a child1. Or you can use instanceof to check yourself:
Base child = container.get(n);
if (child instanceof Child1) {
...
}
If this isn't good enough, you'll need to explain more clearly what you want to accomplish and why this won't work.
MORE: After reading your edit, that says you want to do something like this:
JSONObject o;
//...
o.get("nestedObject").get("array").get(3);
You don't need any casting to accomplish this. What you need is an abstract JSONValue base type that represents any kind of value that can be returned from a JSON parser. The subclasses would be things like "object", "array", and whatever scalar types you need (integer, string, etc.). get would return JSONValue. In actuality, it will return an object of one of the other types, but all the compiler needs to know is that it returns JSONValue.
Now a JSONValue will need two get methods, one that takes a String and one that takes an int or Integer. These will be polymorphic methods. Say v is a JSONValue and you say v.get("array"): the method it actually calls may be different based on the actual type of v. So if v is your "object" type, it will call the method you've defined for the object type; if v is an integer type, it will call the method defined for the integer type, and so on. What you want is for the get method that takes a String to look up the field for the JSON "object" type, and throw an exception for everything else. Similarly, for the get method that takes an integer parameter, the method for the JSON "array" type will look up a list or something, and the method for every other subclass of JSONValue will throw an exception. No "casting" is needed for this. Casting is a compile-time concept. At all points, the compiler will know only that it's working with a JSONValue. But at run time, the object's actual type is used to determine which method to call, so the compiler doesn't need to know anything more.
This is a basic concept that all Java programmers need to know (also Javascript, Python, and pretty much every other language these days, although polymorphism is handled differently in interpreted languages like Javascript and Python). The tutorial https://docs.oracle.com/javase/tutorial/java/IandI/index.html covers this and related concepts. There may be better Java tutorials on "polymorphism" out there also.
type stores the classtype of classes which inherit from base
This is equivalent to this.getClass().
How do I implement such a function(container.get), which casts the object to it's correct type before returning it?
Not possible in theory. People will create more subclasses and put it in the container, after the code is compiled and shipped. That's the purpose of have a base class -- so that the other part of your codebase only has to work with a single interface/concept.
So basically what you want to write is just some generic container code.
interface Container<T extends Base> {
public T get(int i);
}
But the real question was How can the container accommodates a set of known subclasses? Just use different method names. Gson does it.
public class Container {
public Base get(int i) { ... }
public SubType1 getAsSubType1(int i) { ... }
public SubType2 getAsSubType2(int i) { ... }
}
And you can add custom cast methods to Base too.
You can't do that. Generics doesn't really work that way. There's no way to know the exact subtype of your object at compile time.
This b.type.cast(b); casting will need to be done on the result of your method public <something here> get(int i) wherever it's called.
If you have designed the system well you won't need to cast the object back to the exact subclass much, if at all.
Otherwise your best bet is to do a instanceof type check where needed.
I think you are referring to Generics
class container<GenericType> {
private Vector<GenericType> v;
//...
public GenericType get(int i){
GenericType b=v.get(i);
return b;
}
}
As a practical example of the general question in the subject, I'd like to implement the containsAll method in the Set interface with
public boolean containsAll(Iterable<?> c) { /* ... */ }
I figure this should be allowed, since Collection is Iterable meaning such a containsAll would cover the interface requirement. Likewise, more generally being able to implement interfaces with argument superclasses seems like it should work.
However, Eclipse says no way (haven't tried just javac straight-up) - can someone explain the reason for that? I'm sure there's something in the spec which makes it the way it is, but I'd like to understand the motivation for requirement as well. Or am I missing something like Iterable<?> not being a superclass of Collection<?>?
As a side question - given I'm declaring two methods would the method with the Iterable signature always be preferred on calls with a Collection argument?
Eclipse Error:
If I remove the method with the Collection signature, just leaving the Iterable one (see after error), I get the following:
The type BitPowerSet must implement the inherited abstract method Set<Long>.containsAll(Collection<?>)
The exact implementation being:
#Override public boolean containsAll(Collection<?> c) {
for (Object o : c) if (!contains(o)) return false;
return true;
}
public boolean containsAll(Iterable<?> c) {
for (Object o : c) if (!contains(o)) return false;
return true;
}
Since the interface you are implementing declares the (abstract) method containsAll(Collection<?>), you must implement it with this exact signature. Java does not allow you to implement/override a method with a wider parameter type than the original. This is why you get the error you show when you comment out your method with the Collection signature.
You don't show the other error you claim to get when the method is not commented out, but I guess it might have to do something with ambiguous method overloading.
My guess as to why java has this restriction is, say you have:
class A {
void foo(String s) { ... }
}
class B extends A {
// Note generalized type
#Override void foo(Object s) { ... }
}
Now if you have class C extends B and it wants to override foo, it's not clear what argument it should take.
Say for example C extended A directly at first, overriding void foo(String s), and then it was changed to extend B. In this case C's existing override of foo would become invalid because B's foo should be able to handle all Objects, not just Strings.
The argument types are part of the method signature so the jvm needs a method with exact the same signature to find overrides. A containsAll( Iterable) will have a different signature than containsAll(Collection).
If I remember right the compiler has to use some workarounds to make generics work in spite of this limitation.
To your second question, the compiler would prefer the Collection argument since it is a subtype of Iterable, this makes the Collection method more specific than the Iterable one.
I saw a java function that looked something like this-
public static<T> foo() {...}
I know what generics are but can someone explain the in this context? Who decides what T is equal to? Whats going on here?
EDIT: Can someone please show me an example of a function like this.
You've missed the return type out, but apart from that it's a generic method. As with generic types, T stands in for any reference type (within bounds if given).
For methods, generic parameters are typically inferred by the compiler. In certain situations you might want to specify the generic arguments yourself, using a slightly peculiar syntax:
List<String> strings = Collections.<String>emptyList();
In this case, the compiler could have inferred the type, but it's not always obvious whether the compiler can or can't. Note, the <> is after the dot. For syntactical reasons the type name or target object must always be specified.
It's possible to have generic constructors, but I've never seen one in the wild and the syntax gets worse.
I believe C++ and C# syntaxes place the generic types after the method/function name.
The context is a generic method as opposed to a class. The variable <T> applies only to the call of the method.. The Collections class has a number of these; the class itself is not generic, but many of the methods are.
The compiler decides what T is equal to -- it equals whatever gets the types to work. Sometimes this is easier then others.
For example, the method static <T> Set<T> Collections.singleton(T o) the type is defined in the parameter:
Collections.singleton(String T)
will return a Set<String>.
Sometimes the type is hard to define. For example sometimes there is not easily enough information to type Collection.emptyList(). In that case you can specify the type directly: Collection.<String>emptyList().
T it's the formal type parameter wich will be replaced by the actual type
argument used at the instantiation of the object.
For example, here is the List and Iterator definitios in package java.util:
public interface List<E>{
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E>{
E next();
boolean hasNext();
}
Then you can instantiate a List this way:
List<String> ls = new ArrayList<String>()
Where you might imagine that List stands for a version of List where E has
been uniformly replaced by String:
public interface StringList{
void add(String x)
Iterator<String> iterator();
}