This question already has an answer here:
Java generics 2 set of <K,V> or <T> in method declaration [duplicate]
(1 answer)
Closed 5 years ago.
I am learning Java generic from: https://docs.oracle.com/javase/tutorial/java/generics/bounded.html and I have some doubts on the code sample below:
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public <U extends Number> void inspect(U u) {
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect("some text"); // error: this is still String!
}
}
Why wasnt the inspect() method to be written as shown below instead it was ?
public <T extends Number> void inspect(T t) { }
There are some other code samples which has the following syntax. What does the 1st pair stands for?
public <K,V> SomeClass<K,V>
What does static stands for?
public static <T> int countGreaterThan(T[] anArray, T elem)
The method Box.inspect() expects a type that extends Number so it is not applicable when the argument is a String.
Box.inspect() is just an example of generic type applied to a method.
On other hand you have a class Box with generic type T, but you can also have a method that accepts another type U which is broader (upper bounded) than T.
The class itself does not say how to use inspect and why, it just give you the possibility to handle different types. Don't put great expectations by this sample.
Consider that it is a just a sample that explain how to use Generics (not great logic behind).
Regarding public class SomeClass<K,V> declaration, this a declaration with multiple generics types.
The class HashMap<K,V>() is a real sample of this case, K is the type for the key value and V is the type for the value.
public <U extends Number> void inspect(U u) {
waits for a parameter that is of Number type or a derived of it.
So you cannot of course pass a String value :
integerBox.inspect("some text"); // error: this is still String!
In your class, you declare two parameterized type :
one in the class declaration : public class Box<T> {
another in the public <U extends Number> void inspect(U u) method.
These set two distinct constraints.
When you declare an instance of Box with Integer as generic type:
Box<Integer> integerBox = new Box<>();
This following field using the T type will be associated to an Integer type :
private T t;
but the public <U extends Number> void inspect(U u) method doesn't use the T
type.
So you can use distinct types in the two cases:
Box<Integer> integerBox = new Box<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect(Float.valueOf(10)); // I pass a float and it is valid.
If you would declare the method in this way :
public <T extends Number> void inspect(T t) { }
you would have the same behavior as T in the declared method would be another T type as which one declared in the class.
But this way is misleading as you use use twice the same type name (T) while these are distinct types.
Otherwise, to constraint the parameter of the method to the type declared in the class, you have not to declare still a type.
This is enough :
public void inspect(T t) { }
Now you can only use the same type in the two cases:
Box<Integer> integerBox = new Box<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect(Float.valueOf(10)); // doesn't compile
Yes. Freedev answer is correct.
Try
public static void main(String[] args) {
Test1<Integer> integerBox = new Test1<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect(78); // inspect method expect a interger value
}
Related
I found this code from a tutorial and I am guessing this method getUriBase return type is String, but not clear what part <T extends IEntity> is playing in this method and why it is placed in the beginning?
public interface IUriMapper {
<T extends IEntity> String getUriBase(final Class<T> clazz);
}
This is the convention of creating a generic method.
The syntax for a generic method includes a type parameter, inside
angle brackets, and appears before the method's return type. For
static generic methods, the type parameter section must appear before
the method's return type.
If you see then before your return type String you defining your type parameter T. Now, coming to <T extends IEntity>, by this basically you are creating a bounded type parameter, where-in you are telling the compiler that T should only be a subclass of IEntity.
An important thing to note is that you need to define <T extends IEntity> before your method (this is what you call "generic method", more info coming...) because your interface is not a generic type, suppose your interface was like below then you need not to define the T type parameter because compiler would know what is the T type parameter.
public interface IUriMapper<T extends IEntity> {
String getUriBase(final Class<T> clazz);
}
So, basically generic method are useful (or in other words meant for situations) when you want to define your own type. Consider below example where-in your generic type (your interface "IUriMapper") defines type parameter "T" but for method getUriBase you are creating a new type "E"
public interface IUriMapper<T extends IEntity> {
<E extends Number> String getUriBase(final Class<E> clazz);
}
This Oracle documentation is best source to learn Generics.
Generic Types
The type parameter section, delimited by angle brackets (<>), follows the class name. It specifies the type parameters (also called type variables) T1, T2, ..., and Tn.
public class Box {
private Object object;
public void set(Object object) { this.object = object; }
public Object get() { return object; }
}
To update the Box class to use generics, you create a generic type declaration by changing the code "public class Box" to "public class Box". This introduces the type variable, T, that can be used anywhere inside the class.
/**
* Generic version of the Box class.
* #param <T> the type of the value being boxed
*/
public class Box<T> {
// T stands for "Type"
private T t;
public void set(T t) { this.t = t; }
public T get() { return t; }
}
Source: https://docs.oracle.com/javase/tutorial/java/generics/types.html
Bounded Type Parameters:
There may be times when you want to restrict the types that can be used as type arguments in a parameterized type. For example, a method that operates on numbers might only want to accept instances of Number or its subclasses. This is what bounded type parameters are for.
public class Box<T> {
private T t;
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
public <U extends Number> void inspect(U u){
System.out.println("T: " + t.getClass().getName());
System.out.println("U: " + u.getClass().getName());
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
integerBox.set(new Integer(10));
integerBox.inspect("some text"); // error: this is still String!
}
}
Source: https://docs.oracle.com/javase/tutorial/java/generics/bounded.html
I "simply" want to write a static generic method that takes the generic Collection<E> of any type E as its input, and outputs a result of the appropriate type Vector<E>. Since the type E is always known at compile-time, this should not be a problem - but it is... Thus, a call should later look like:
Collection<String> coll = ...
Vector<String> vec = Convert.toVector(coll); // either this or...
Vector<String> vec = Convert<String>.toVector(coll);
Here is what I tried - all without success:
import java.util.Collection;
import java.util.Vector;
public class Convert<E> {
// 1st try, same type E as class => Error: Cannot make a static reference to the non-static type E
public static Vector<E> toVector1(Collection<E> coll) {
return new Vector<E>();
}
// 2nd try, a new type X. => Error: X cannot be resolved to a type
public static Vector<X> toVector2(Collection<X> coll) {
return new Vector<X>();
}
// 3rd try, using wildcard. => Error: Cannot instantiate the type Vector<?>
public static Vector<?> toVector3(Collection<?> coll) {
return new Vector<?>();
}
// 4th try, using bounded wildcard. => Error: Cannot make a static reference to the non-static type E
public static Vector<? extends E> toVector4(Collection<? extends E> coll) {
return new Vector<E>();
}
}
Is this not possible at all? And if not, is there a good reason why not? Or am I just doing it wrong? Probably there is some solution using Lambda expressions?
You should give your static method its own generic type parameter :
public static <T> Vector<T> toVector1(Collection<T> coll) {
return new Vector<T>();
}
You were missing the generic type parameter declaration (<T>) before the return type of the method.
From the JDK documentation: "For static generic methods, the type parameter section must appear before the method's return type.". So it should look like
public static <E> Vector<E> toVector1(Collection<E> coll) {
return new Vector<E>();
}
// 1st try, same type E as class => Error: Cannot make a static reference to the non-static type E
public static Vector<E> toVector1(Collection<E> coll) {
return new Vector<E>();
}
This is because you've already defined a type-parameter, called E, on instance context and the compiler doesn't allow you to use it on static context.
// 2nd try, a new type X. => Error: X cannot be resolved to a type
public static Vector<X> toVector2(Collection<X> coll) {
return new Vector<X>();
}
Here, even though you don't use the instance type-parameter E, but another one, called X, the former is not correctly defined. When introducing method-scoped type-parameters, you have to do:
public static <X> Vector<X> toVector2(Collection<X> coll) {
return new Vector<X>();
}
// 3rd try, using wildcard. => Error: Cannot instantiate the type Vector<?>
public static Vector<?> toVector3(Collection<?> coll) {
return new Vector<?>();
}
The error is simply because the wildcard <?> can be only used in return-types and on initialization, but not on instantiation (like you've done).
// 4th try, using bounded wildcard. => Error: Cannot make a static reference to the non-static type E
public static Vector<? extends E> toVector4(Collection<? extends E> coll) {
return new Vector<E>();
}
The reason is the same as 1st try. You can fix this by having:
public static <X> Vector<? extends X> toVector4(Collection<? extends X> coll) {
return new Vector<X>();
}
However, note that when you use this method, you won't be able to add anything but null to the resulting list.
Is there any difference between object of class MyClass and object of class MyClass<String> apart from the fact that one is of 'Raw Type' and other is of 'Generic type'.If we call 'getClass()' method on object of Raw type 'MyClass' and on object of Generic Type MyClass<String> both will return same answer. So what exactly the difference is ?. Thanks
class MyClass
{
}
class MyClass<String>
{
}
Generics provides compile time type-safety and ensures that you only insert correct Type in collection and avoids ClassCastException in runtime.
Now for example to show you simple advantage I have provided this code
public class Box<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}
public static void main(String[] args) {
Box<Integer> integerBox = new Box<Integer>();
Box<String> stringBox = new Box<String>();
integerBox.add(new Integer(10));
stringBox.add(new String("Hello World"));
System.out.printf("Integer Value :%d\n\n", integerBox.get());//10
System.out.printf("String Value :%s\n", stringBox.get());//Hello World
}
}
For more detail you can check this link
I want my T type to be instance of java.lang.reflect.Type interface or java.lang.Class<T>
I have created sample code like below
public class Car<T extends Type> {
private T t;
public Car(T t) {
this.t = t;
}
public static void main(String[] args) {
Car<String.class> car = new Car(String.class);//Error String.class
}
}
I know above in above example I can use Class<T> instead of using T. I wanted to know if there is any way in which T can be made to understand that it is of Type or Class?
Instead of Car<String.class>, write Car<Class<String>>.
String.class is an object. Between the angle brackets you must specify a type. The type you're looking for is Class<String>.
I have the following code that won't compile and although there is a way to make it compile I want to understand why it isn't compiling. Can someone enlighten me as to specifically why I get the error message I will post at the end please?
public class Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(null);
}
public <T extends Test> void testT(Class<T> type) {
Class<T> testType = type == null ? Test.class : type; //Error here
System.out.println(testType);
}
}
Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>
By casting Test.class to Class<T> this compiles with an Unchecked cast warning and runs perfectly.
The reason is that Test.class is of the type Class<Test>. You cannot assign a reference of type Class<Test> to a variable of type Class<T> as they are not the same thing. This, however, works:
Class<? extends Test> testType = type == null ? Test.class : type;
The wildcard allows both Class<T> and Class<Test> references to be assigned to testType.
There is a ton of information about Java generics behavior at Angelika Langer Java Generics FAQ. I'll provide an example based on some of the information there that uses the Number class heirarchy Java's core API.
Consider the following method:
public <T extends Number> void testNumber(final Class<T> type)
This is to allow for the following statements to be successfully compile:
testNumber(Integer.class);
testNumber(Number.class);
But the following won't compile:
testNumber(String.class);
Now consider these statements:
Class<Number> numberClass = Number.class;
Class<Integer> integerClass = numberClass;
The second line fails to compile and produces this error Type mismatch: cannot convert from Class<Number> to Class<Integer>. But Integer extends Number, so why does it fail? Look at these next two statements to see why:
Number anumber = new Long(0);
Integer another = anumber;
It is pretty easy to see why the 2nd line doesn't compile here. You can't assign an instance of Number to a variable of type Integer because there is no way to guarantee that the Number instance is of a compatible type. In this example the Number is actually a Long, which certainly can't be assigned to an Integer. In fact, the error is also a type mismatch: Type mismatch: cannot convert from Number to Integer.
The rule is that an instance cannot be assigned to a variable that is a subclass of the type of the instance as there is no guarantee that is is compatible.
Generics behave in a similar manner. In the generic method signature, T is just a placeholder to indicate what the method allows to the compiler. When the compiler encounters testNumber(Integer.class) it essentially replaces T with Integer.
Wildcards add additional flexibility, as the following will compile:
Class<? extends Number> wildcard = numberClass;
Since Class<? extends Number> indicates any type that is a Number or a subclass of Number this is perfectly legal and potentially useful in many circumstances.
Suppose I extend Test:
public class SubTest extends Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(new SubTest());
}
}
Now, when I invoked testT, the type parameter <T> is SubTest, which means the variable testType is a Class<SubTest>. Test.class is of type Class<Test>, which is not assignable to a variable of type Class<SubTest>.
Declaring the variable testType as a Class<? extends Test> is the right solution; casting to Class<T> is hiding a real problem.
Remove the conditional and the error is a little nicer...
public class Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(null);
}
public <T extends Test> void testT(Class<T> type) {
Class<T> testClass = Test.class;
System.out.println(testClass);
}
}
Test.java:10: incompatible types
found : java.lang.Class<Test>
required: java.lang.Class<T>
Class<T> testClass = Test.class;