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.
Related
How can I fix this problem?
rv_groupAddMember.setAdapter(new GroupAdapter(groupModelList, position -> {
selectedGroup = groupModelList.get(position);
addMember_groupName.setText("Seçili Grup :"+selectedGroup.getGroupName());
}));
public class GroupAdapter extends RecyclerView.Adapter<GroupAdapter.GroupViewHolder>{
List<GroupModel> groupModelList;
OnClickItem onClickItem;
public GroupAdapter(List<GroupModel> groupModelList, OnClickItem onClickItem) {
this.groupModelList = groupModelList;
this.onClickItem = onClickItem;
}
I added my GroupAdapter class and constructor
error
I'm watching tutorial everything is the same and there shouldn't be an error.
The problem is, java needs to figure out what the lambda is actually trying to be, and only then can it know what the type of position is. For example, given:
void foo(Consumer<String> x) { ... }
If you then write: foo(s -> System.out.println(s)); - java knows that the type of s is String only because of this sequence of events:
There is only one foo method.
That method takes a param of type Consumer<String>.
That type is a functional interface (an interface with a single method), and that method's signature is void accept(String t).
The lambda is an implementation of that method, therefore, s must be String.
And only then can java continue to actually understand what the lambda contains.
Your error is telling you in a somewhat odd way that the compiler is not currently capable of figuring out what the functional interface is that this lambda is implementing. Therefore, it does not know what the type of position is, therefore, the call groupModelList.get(position) does not work; int is required, but the type of position is 'I do not know yet; I cannot know until I know what functional interface this lambda is trying to implementation and for some reason I can't know that right now'. Which isn't int, so you get that error.
one trivial fix is to be explicit. Make that (int position) -> { ... } instead. This may then lead you to the real error you're interested in. For example, if you haven't imported GroupAdapter, this would happen.
Given the interface:
interface GenericInterface<T> {
Class<T> getGenericType();
}
and the following implementation "skeletons":
class GenericInterfaceImpl<T> implements GenericInterface<T> { /* impl */ }
class TypedInterfaceImpl implements GenericInterface<String> { /* impl */ }
define an implementation for getGenericType in a manner that it would pass the following assertions:
assertEquals(new GenericInterfaceImpl<String>().getGenericType(), String.class, "Type should resolve to String.class");
assertEquals(new TypedInterfaceImpl().getGenericType(), String.class, "Type should resolve to String.class");
I'm perfectly aware of a good implementation that solves this problem on the TypedInterfaceImpl "scenario". The following code passes the assertion for the second case:
#Override
#SuppressWarnings("unchecked")
Class<T> getGenericType() {
Type t = this.getClass().getGenericInterfaces()[0];
ParameterizedType pt = (ParameterizedType) t;
return (Class<T>) pt.getActualTypeArguments()[0];
}
But I can't find a way to get the same result if I'm working with the GenericInterfaceImpl version of this problem. When using the above implementation with GenericInterfaceImpl, the "type argument" resolves to a sun.reflect.generics.reflectiveObjects.TypeVariableImpl instead of java.lang.String like it does when handling TypedInterfaceImpl.
The Javadocs for getGenericInterfaces explicitly states that it will not resolve type parameters if it's not defined in the source code (for reference: https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getGenericInterfaces-- I'm using Java 11 in my particular case but it's the same nonetheless), so by definition, I understand that this particular method can't solve this problem.
Is there a way to solve this problem at all or is this a "core limitation" of the Java language?
assertEquals(new GenericInterfaceImpl<String>().getGenericType(), String.class, "Type should resolve to String.class");
impossible.
assertEquals(new TypedInterfaceImpl().getGenericType(), String.class, "Type should resolve to String.class");
Possible, but a bad idea; it would require you to document your interface with 'when implementing this interface, you must pick a concrete, non-type-parameterized type for T or nothing works right.', which is a weird caveat.
Class<T> getGenericType() {
Bad idea; the thing in the <> does not have to be a Class - for example, it could be List<String>, which is not representable as a class object (only List is, there is one object that represents all lists, there's no way to have an instance of j.l.Class that represents List<String>).
The Javadocs for getGenericInterfaces
getGenericInterfaces is a reflective tool, but it reflects on the definition of the type only. Given class Foo<T> implements Thingie<T>, getGenericInterfaces can only be executed on the entire Foo class, and you get back an object that presents Thingie<T>. Given an instance such as new Foo<String>() it is not possible to derive String.
Is there a way to solve this problem at all or is this a "core limitation" of the Java language?
It's a core limitation, so, no. Not directly.
One trick is to add a method:
public interface Foo<T> {
public Class<T> getType();
}
and let implementers worry about the problem. This is still a bad idea, for example, a Class object cannot represent List<String>, so you've effectively made it impossible for Foo to properly represent anything where you want the T to be anything that has type params.
Take a step back instead. What are you actually trying to do? Nobody wakes up and goes: I know! I'll build an interface that can report its own type parameter but reified! What did you want to build? A chat app? A plugin system for photoshop?
java.lang.Class, with the intent to invoke .newInstance() on it, is a piss poor factory. Thus, if that is what you intend to do, use factories instead.
Anotehr solution, but you probably don't want this, and before you got all excited, it's got plenty of limitations, are a concept called Super Type Tokens; you can search the web if you must know.
This question already has answers here:
Java Generics: Generic type defined as return type only
(6 answers)
Closed 7 years ago.
Preface: I understand generics and how they're declared at the class level (e.g. class MyClass<T>) but I've never seen it declared at the level of a static method, and without any explicit bindings (e.g. class MySubclass<String> extends MyClass).
I found this code snippet in an app I'm working on (I didn't write this part). I've never seen a method declared this way. <T> is not defined anywhere else in the class. Intent.getExtras().get() returns an Object which may actually be a String, Boolean ...etc.
private static <T> T getItemExtra(final Intent intent, final String extraName) {
T item = null;
if(intent != null && intent.getExtras() != null) {
item = (T) intent.getExtras().get(extraName);
}
return item;
}
Sample usage:
String s1 = getItemExtra(someIntent, "some_string_extra");
Uri u1 = getItemExtra(someIntent, "some_uri_extra");
How does the JVM know what type to use for <T>? (Yes this method compiles and executes successfully).
How does the JVM know what type to use for <T>?
The basic answer is, it doesn't. In Java, generic types are used by the type checker at compile time, but are removed from the program when the program actually runs. So for instance, the cast to T in item = (T) intent.getExtras().get(extraName) doesn't actually do anything at runtime: it's effectively a cast to Object, always, regardless of what type the caller expects T to be. (This is different from a cast to a normal type like String, where the program will fail with an exception immediately if you try to cast the wrong thing.)
The fact that you can cast to T without a check is a loophole in Java's type system that can cause weird class-cast exceptions. For instance, if you say
String s = getItemExtra(...);
s.toLowerCase();
but getItemExtra doesn't return a string, then you'll get an exception on the second line telling you that s isn't a string, even though there's no cast on that line. For that reason, when the Java compiler sees a cast to T it will generate an unchecked-cast warning, telling you that it can't check that your typecast was legal and you might run into problems like this.
That is what is known in Java as a generic method. The T in represents a type, which you would normally specify. The compiler would then replace any instances of T with the type you replaced it with. If you don't, the compiler will attempt to infer the correct type from the available information.
You should look through the Java Generics Tutorial for a more in depth explanation.
T is what is known as a type interface. In this instance, the return type is a type interface so simply saying that getItemExtra(...) will return a String or Uri is enough for the compiler to know that this method will return that object. That being said, this isn't the best example to be introduced to type interfaces so here is an easier example.
ArrayList is implemented using a type interface except you are telling the ArrayList what object type it will contain, except instead of T they are using E, which is fine because the character is arbitrary so long as you use that same character throughout your implementation.
Here is a relevant snippet from the actual implementation:
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
{
So if you declare ArrayList<String> the compiler will replace E with String at compile time. Same goes for ArrayList<YourCustomObject> it will replace E with YourCustomObject throughout the implementation.
I'm designing the interface as follows:
public interface Parameters {
public <T> T getValue(ParameterName pn, Class<T> valueType) throws ClassCastException;
}
An implementation is obligated to throw ClassCastException if the Class instance of the value to be returned is not an assignableForm of the Class passed as a parameter.
Does it make sesnse? It provides compile-time type-safety, but we can do the same with just explicit cast.
Or it's much better to declare just
public Object getValue(ParameterName pn)
leaving all class-cast issues to the client.
I have used this form of API where I add the ability to convert the type to the one desired. e.g. if it's a String but you need an Integer it will attempt to parse it.
Otherwise, as you suggest you are not adding much that this method doesn't provide.
public <T> T getValue(ParameterName pn);
This avoid needing an explicit cast.
It is a misunderstanding that you gain any compile-time type-safety by passing the Class object of the expected return type as a parameter. If the client passes a Class of the wrong type the error will only get detected at runtime.
But I think the design with a Class parameter has other advantages:
The parameters creates a natural place to document the behaviour of the method regarding the return type.
You can write code in the method to check the Class parameter and provide a specific and meaningful error message if the user makes a mistake.
It is very visible in the calling code and brings attention to the behaviour of the method.
I can think of two disadvantages of that design:
The existence of the parameter might give users the impression that the parameter affects the return value of the method.
It is more verbose than using an unrestricted generic return type as Peter suggests in his answer.
I'm currently brushing up my Java and reading up on Generics. Since they were not treated extensively in my Java class, I'm still having some trouble wrapping my mind about it, so please keep that in mind when answering.
First of all, I'm pretty sure that what I'm trying to is not possible. However, I'd like to find out where my thinking is wrong and how I should go about achieving what I want.
What I'm trying to do is manipulating an object that implements a generic interface from another class that has no knowledge about the instantiated type. Thus, I have something like the following classes:
public interface CalledInterface<E> {
public E get() { ... }
public set(E e) { ... }
}
public class Called implements CalledInterface<String> {
...
}
Now what I want to do is:
public class Caller {
protected CalledInterface<?> c;
public Caller (CalledInterface<?> arg) {
c = arg;
}
public void run(){
// I can do this:
c.set(c.get());
// But I'd want to be able to do something like:
<?> element = c.get();
c.set(element);
}
}
What is the fundamental flaw in my thinking, if there is one? And what approach should I rather be taking?
First of all, keep in mind that generics is a compile time thing not a runtime.
Now in your Caller you defined Called c. Called is defined to implement CalledInterface<String>, so automatically, Called has the following methods generated at compile time:
String get();
void set(String e); //i assume you wanted to return void
So essentially this doesn't really make sense:
<?> element = c.get();
The Caller class isn't even aware Called is using generics internally, for it, Called just deals with strings.
UPDATE
Based on your comment, since you don't want Caller to use Called directly but use CalledInterface first thing you have to do is change the type of c to that. In this case you should not use generics, because the whole point of generics is that the same class is used in different scenarios with different types (again determined at compile time), enforcing types without having repeated code.
If I understand correctly you don't want to restrict Caller to use String, so what you have to do is change CalledInterface to not use generics, and change the methods to:
Object get();
void set(Object o);
This is how we used to do things before Generics in Java 1.4. You obviously run the risk of not having type safety, so think through whether what you want really makes design sense, because it probably does not because you have to do instanceof anyway to check the type to use the Object in a useful way (i.e. to access its methods).
If on the other hand you just change the c member (and the constructor argument of Caller) to:
CalledInterface<String> c;
Your Caller will be interacting with the CalledInterface rather than the implementation and at the same time still be type safe. So you can still pass an instance of Called and set it to c.
After your edit:
// I can do this:
c.set(c.get());
No you can't. It won't compile with c being CalledInterface<?>. (Have you even tried it?)
To do this, you can use a "capture helper":
private static <T> void helper(CalledInterface<T> c) {
c.set(c.get());
}
public void run(){
helper(c);
}
Which also solves your second problem:
private static <T> void helper(CalledInterface<T> c) {
T element = c.get();
c.set(element);
}
public void run(){
helper(c);
}
There are a few minor mistakes in your code:
protected Called c;
public Caller (CalledInterface arg) {
c = arg;
}
You are not allowed to assign arg here, because the type CalledInterface is not a subtype of Called (it is the other way around)
Also you should give type information when using CalledInterface (it is allowed to leave it out, but only for legacy purposes).
Now to the part you are wondering about. For the type Called, the compiler knows get() returns a String, if you are not interested in that, you can of course always use Object as the type of element. The compiler also knows that set() takes a String as argument, so it requires you to give one. In generics is essentially the same as using Object in a case without generics (even though it isn't allowed on the location you use it, because it doesn't make sense). This means that you would be telling the compiler to forget the type on the first line (calling get()) and to unforget it on the line below.