I need a custom method to check for a list containing an instance of a class and call this method but I do not understand this syntax "Class clazz" and I do not understand What's the second parameter of this method
public static <E> boolean containsInstanceOfOidInrArraylist(List<E> Arraylist, Class<? extends E> clazz) {
for (E e : Arraylist) {
if (clazz.isInstance(e)) {
return true;
}
}
return false;
}
Ok, so the first parameter of the function is a List<E> named Arraylist (You shouldn't capitalize variables in Java, name it as such arrayList).
The second parameter is a Class<? extends E> named clazz.
Check manub's explaination of Class<?>:
Class is a parameterizable class, hence you can use the syntax
Class<T> where T is a type. By writing Class<?>, you're declaring a
Class object which can be of any type (? is a wildcard). The Class
type is a type that contains meta-information about a class.
So now you know what Class<?> means, but what about Class<? extends E>?
<? extends E> basically means any class which extends E (or E itself).
So Class<? extends E> clazz means you have a varaible named clazz which is E class or a sub class of E.
See this tutorial: https://docs.oracle.com/javase/tutorial/java/generics/upperBounded.html
"Upper Bounded Wildcards
You can use an upper bounded wildcard to relax the restrictions on a variable. For example, say you want to write a method that works on List<Integer>, List<Double>, and List<Number>; you can achieve this by using an upper bounded wildcard.
To declare an upper-bounded wildcard, use the wildcard character ('?'), followed by the extends keyword, followed by its upper bound. Note that, in this context, extends is used in a general sense to mean either "extends" (as in classes) or "implements" (as in interfaces)."
The second parameter is a class that is the same as the class of the objects in the list, or extends it. clazz is used as a variable name because class is a reserved keyword and cannot be used.
Related
I'm using library which contains method I want to use. Simplified signature would look like this:
final class ThirdPartyClass
{
public static <T> void thirdPartyMethod(Class<T> clazz, T instance)
{
// does something
}
}
Inside thirdPartyMethod() it expects class of T as first argument and an instance of that specific class T as second argument.
Now I have this simple abstract class, which is calling that method:
abstract class Parent<T extends Number>
{
public Parent(T instance)
{
ThirdPartyClass.thirdPartyMethod(instance.getClass(), instance);
}
}
I'm getting an error:
method thirdPartyMethod in class ThirdPartyClass cannot be applied to given types;
required: java.lang.Class, T
found: java.lang.Class<capture#1 of ? extends java.lang.Number>, T
reason: inference variable T has incompatible bounds
equality constraints: capture#2 of ? extends java.lang.Number
lower bounds: T
How can I modify the Parent class so it conforms to expected arguments of thirdPartyMethod()?
If possible with explanation.
According to the return type of Object.getClass()
The actual result type is Class<? extends |X|> where |X| is the
erasure of the static type of the expression on which getClass is
called.
Since T extends Number, the resulting type would be Class<? extends Number>, i.e. means an unknown type extending Number. Which doesn't match T extends Number (i.e. a particular type extending Number which would be provided at runtime).
How can I modify the Parent class so it conforms to expected arguments of thirdPartyMethod()?
1. Introduce a second parameter of type Class<T> in your constructor.
abstract class Parent<T extends Number> {
public Parent(T instance, Class<T> tClass) {
ThirdPartyClass.thirdPartyMethod(tClass, instance);
}
}
2. Perform casting (as have been mentioned in the comments):
ThirdPartyClass.thirdPartyMethod((Class<T>) instance.getClass(), instance);
By the way, instead of calling methods from a constructor (especially ones that are not developed and tested by you/your colleagues) you might consider introducing a factory method that would produce your domain object based on the result of a method call.
I have been trying to create enum that contains generic attribute, for example:
public enum SomeEnum {
SOME_VALUE_1(SomeValue1.class),
SOME_VALUE_2(SomeValue2.class);
private final Class<T extends SomeValue> className;
}
SomeValue1 and SomeValue2 classes implement SomeValue interface. For some reason <T extends SomeValue> is marked with "Unexpected bound" error. If I replace T with ?, there is no error. But it is still puzzling me why it is happening when I use T.
Any help would be highly appreciated.
When you use T extends SomeValue in this way, you are referencing a type variable T that isn't defined, and you aren't allowed to define a type variable there. Only on type variable declarations are you allowed to define a bound such as T extends SomeValue.
On an interface or class, you could define T with the bound you want, but not on an enum. Enums are not allowed to be generic in Java.
You are probably getting the same error on the constructor you haven't shown that accepts a Class<T extends SomeValue> to assign to className. The same reason applies here too.
Using ? extends SomeValue is an upper-bounded wildcard. It basically means "a specific yet unknown type that is SomeValue or a subtype". This is appropriate here, because all you care about here is that the Class is for SomeValue or some implementation class.
<? extends SomeClass> and <T extends SomeClass> are two very different syntaxes.
The first is a wildcard bound, part of a type argument:
TypeArguments:
< TypeArgumentList >
TypeArgumentList:
TypeArgument {, TypeArgument}
TypeArgument:
ReferenceType
Wildcard
Wildcard:
{Annotation} ? [WildcardBounds]
WildcardBounds:
extends ReferenceType
super ReferenceType
The second is a type bound, part of a type parameter:
TypeParameter:
{TypeParameterModifier} Identifier [TypeBound]
TypeParameterModifier:
Annotation
TypeBound:
extends TypeVariable
extends ClassOrInterfaceType {AdditionalBound}
What's the difference between a type parameter and a type argument? A type parameter, like a method parameter, occurs at e.g. a generic class/method declaration:
class Foo<T extends SomeClass> {} // "T extends SomeClass" is a type parameter
class Bar<T> {} // "T" is a type parameter
This is analogous to method parameters:
void foo(int i) {} // "int i" is a method parameter
A type argument, like a method argument, occurs where you use a generic class/method. For example, in a field declaration:
Foo<? extends SomeClass> foo; // "? extends SomeClass" is a type argument
Bar<String> // "String" is a type argument
This is analogous to method arguments that you pass when you call a method:
foo(1); // "1" is a method argument
So really, using T extends SomeClass where you should use ? extends SomeClass makes no sense. You are not declaring a new type variable here. You are merely constructing a generic type.
When I created a instance of a class A and tried to access its getClass() method, its return type is different than what is mentioned in java Object class.
A a = new A() ;
Class<? extends A> clazz = a.getClass();
Even when I access the getClass method as mentioned above in Intellij, it says its return type is Class<? extends A> and even the java doc says it returns wildcard extends upper bound. I can totally accept it. Because I can create instance of B and reference to A and access getClass method.
But why does the return type of the getClass method is justClass<?> in the Object class
Edit 1 (After the comment from Andy Turner)
Class A {
List<?> returningNullList() {
return null;
}
}
When I create a instance of A , and tried to access returningNullList () method, it didn't give me return type as List<? extends A>. But when I tried to access getClass method it says return type is Class<? extends A> although the actual hard-coded return type is Class<? > in Object.java file
Is the getClass method is treated specially by compiler?
But why does the return type of the getClass method is justClass<?> in the Object class
Class<?> is the same as Class<? extends Object>, because all classes (except Object) have Object as a superclass. There's no reason to include that bound explicitly.
Read the documentation, i.e. the javadoc of getClass() in class Object:
The actual result type is Class<? extends |X|> where |X| is the erasure of the static type of the expression on which getClass is called. For example, no cast is required in this code fragment:
Number n = 0;
Class<? extends Number> c = n.getClass();
The bolding is from the javadoc, not added by me.
For class Object itself, it means that the return type is Class<? extends Object>, but since Class<?> is shorthand for Class<? extends Object>, the javadoc simply shows the shorthand.
Quoting the Java Language Specification, section 4.5.1. Type Arguments of Parameterized Types:
The wildcard ? extends Object is equivalent to the unbounded wildcard ?.
I have the following code:
String test = "[{\"color\":\"red\"}]";
Class<? extends Base> baseObject = Base.class;
Collection<? extends Base> elements = new ArrayList<Base>();
if (test.startsWith("[")) {
elements.addAll(new ObjectMapper().readValue(test, Collection.class));
} else {
elements.add(new ObjectMapper().readValue(test, baseObject));
}
However I get on
elements.addAll(new ObjectMapper().readValue(test, Collection.class));
a compilation warning:
The expression of type Collection needs unchecked conversion to conform to Collection<? extends capture#1-of ? extends Base>
and for elements.add(new ObjectMapper().readValue(test, baseObject));
a compilation error:
The method add(capture#2-of ? extends Base) in the type Collection<capture#2-of ? extends Base> is not applicable for the arguments (capture#3-of ? extends Base)
What is wrong?
Error can be easily explained. Your collection is defined to hold instances of classes that extends Base. ObjectMapper.readValue is defined as following:
public <T> T readValue(JsonParser jp, Class<T> valueType)
This means that it returns instance of class specified as a second argument. If second argument is Collection.class this method returns Collection. Just Collection, not Collection<? extends Base> and not Collection<Base>. So, java compiler cannot be sure that you are going to put collection that contains correct objects into elements defined as Collection<? extends Base>. Moreover java syntax does not allow to supply as a parameter class with generics, i.e. you cannot call readValue(c, Collection<Base>.class).
The second case is more complicated. baseObject is defined as Class<? extends Base>. elements collection is defined as Class<? extends Base> too. So, what's the problem. The problem is in ?. The question mark means "something that extends Base". But these are 2 different "something" in both cases.
The solution can be either change definition of collection to Class<Base> or to use one class or method generic parameter in both cases, e.g.:
public <T extends Base> myMethod() {
Class<T> baseObject = Base.class;
Collection<T> elements = new ArrayList<T>();
elements.add(new ObjectMapper().readValue(test, baseObject));
}
Now both baseObject and elements use the same type T that indeed extends Base.
You can't add things to a collection with a wildcard type (that doesn't have an explicit lower bound using super, according to Brian; that does make some sense, as a subclass can always be cast to one of its superclasses, but I haven't used super-bounded wildcards much before so I'm not too sure of the details).
http://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
Specifically:
Since we don't know what the element type of c stands for, we cannot
add objects to it. The add() method takes arguments of type E, the
element type of the collection. When the actual type parameter is ?,
it stands for some unknown type. Any parameter we pass to add would
have to be a subtype of this unknown type. Since we don't know what
type that is, we cannot pass anything in. The sole exception is null,
which is a member of every type.
Type erasure is a... well, you know.
This following is from generics tutorials:
Say class R extends S,
public void addR(List<? extends S> s) {
s.add(0, new R()); // Compile-time error!
}
You should be able to figure out why the code above is disallowed. The type of the second parameter to s.add() is ? extends S -- an unknown subtype of S. Since we don't know what type it is, we don't know if it is a supertype of R; it might or might not be such a supertype, so it isn't safe to pass a R there.
I have read it a few times but still I don't quite understand why the following is an error
Given the List.add()'s signature
void add(int index, E element)
isn't it equivalent to
void add(int index, <? extends S> element) // just to explain the idea, not a valid syntax
why is it an error call add(0, new R()) R being an S?
Here's what the text in italics is referring to:
The parameter s, of type List<? extends S>, could be not just an instance of List<S> or List<R>, but also List<T> where T extends S. In that case, even if R also extends S, R does not necessarily extend T (they could be, e.g. siblings in the class hierarchy). Since you can only put a value of type T in such a collection, the compiler can't guarantee at compile time that putting an R there would be safe.
To give a more concrete example, you can't add a Double to a List<? extends Number>, even though Double extends Number! That's because a variable of type List<? extends Number> could, for example, be assigned a List<Integer> at runtime, and adding a Double to such a list is not allowed.
In fact, you can't actually call the add method of a list declared to be List<? extends S>, because at runtime the wildcard could always represent some subtype of S that isn't a superclass of the thing you want to add. You can however read from such a list, since it's guaranteed that the wildcard is a subtype of S, and therefore can be assigned to a variable of type S:
public S getElement(List<? extends S> s) {
S result = s.get(0);
return result;
}
This general idea is referred to as PECS (producer-extends, consumer-super). Chapter 5 of Effective Java (conveniently enough, it's the sample chapter you can download from the book's website) has more to say about this and other subtleties of generics.
Figured this would be the simplest explanation
Class structure:
public class List<? extends S> {}
public class S {}
public class R extends S {}
public class T extends R {}
Code usage:
List<T> list = new List<T>();
in this case the following would be invalid:
list.add(new R());