This question already has answers here:
Return Type of Java Generic Methods
(5 answers)
Closed 6 years ago.
I am reading generics and tried writing the below code. There are no compilation error.
import java.util.*;
public class JavaApplication14 {
public<T> void run (T obj ) {
//Do Something
}
public static void main(String[] args) {
JavaApplication14 m= new JavaApplication14();
m.run(new ArrayList<>());
m.run(new Interger(5);
m.run(5);
}
}
If the function is
public<T extends Number> void run (T obj) {
//Do Something
}
It makes sense as we can restrict the arguments of this function to a Number and its subtypes. But am terribly confused what the function 'run' without any bound mean?
Can it now take any object as the argument ? In what scenario do i need to use such a function with generics ?
Part of your confusion may stem from the fact that there is no point in having run be a generic method in this case. You normally use a type parameter to create a relationship between two parameter types and/or between parameter type and return type. In your example run could just as well have been declared as requiring an Object parameter (a type parameter without a declared bound effectively has Object as its bound).
There is one case I know of where you might usefully use a type parameter in a single parameter type: when you want to be able to manipulate a collection in a way that doesn't depend on the element type, but which does require inserting elements into the collection. Consider for example a hypothetical "reverse list" method:
<T> void reverse(List<T> list)
{
List<T> reversed = new ArrayList<T>();
for (int i = list.size(); i > 0; i--) {
reversed.add(list.get(i - 1));
}
list.clear();
list.addAll(reversed);
}
It would be difficult to write this in a way that didn't require a type parameter, i.e. that takes a List<?> parameter. The only way to do it without casts is to do:
void reverse2(List<?> list)
{
reverse(list); // call reverse as defined above!
}
But again, this doesn't apply in the example you discuss.
So in summary:
A type parameter without an explicit bound effectively has an Object bound.
There are two reasons why a method might need a type parameter (either with or without an explicit bound):
Specify a relationship between parameter types and/or return type
Capture a potential wildcard as a type parameter to allow operations that wouldn't otherwise be possible (as in the reverse example).
The example method you discussed:
public<T> void run (T obj )
... does neither of these, and so the type parameter is pointless. The method might just as well have been declared as public void run(Object obj).
It allows you to avoid any cast.
public class SomeClass {
void doStuff();
}
public<T extends SomeClass> void run (T obj) {
//can call doStuff without any casting
obj.doStuff();
}
public<T> void run (T) {
//Here, there's no clue to perform the implicit cast.
obj.doStuff(); //won't compile
}
While in this case the function could take Object just as well, the variant that makes sense to you is equivalent to public void run(Number obj) { ... } as well. For an example where lack of bound makes sense consider a case where the return type mentions T: public <T> List<T> singletonList(T obj).
Some theory
There're generic methods. Their main goal is generic algorithms (receive and return same types).
Code that uses generics has many benefits over non-generic code:
Elimination of casts.
Stronger type checks at compile time.
Enabling programmers to implement generic algorithms.
A little practice
Consider the following code:
class MyClass {
public void method() {}
public static void main(String[] args) {
runFirst(new MyClass());
runSecond(new MyClass());
}
public static <T extends MyClass> void runFirst(T obj) {
obj.method();
}
public static <T> void runSecond(T obj) {
((MyClass) obj).method();
}
}
The runFirst() method allows us to avoid cast to class and all its subclasses. In runSecond() method we can get any type of parameter (<T>, roughly speaking, means <T extends Object>). Firstly, we must cast to MyClass and then call its method.
First of all I will start with the meaning of public <T> void run(T object) { ... }. Yes when you use that kind of code you than you may use any object as a parameter of run. If you want to restrict the arguments of this function to a specific interface, class or its sub classes you can just write code like NotGenericRun which is shown below.
public class NotGenericRun {
public void run(ArrayList<?> list) {
String message = "Non Generic Run List: ";
System.out.println(message.concat(list.toString()));
}
public void run(int intValue) {
String message = "Non Generic Run Int: ";
System.out.println(message.concat(String.valueOf(intValue)));
}
}
Here I tested output of GenericRun and NotGenericRun classes.
public class TestClass {
public static void main(String[] args) {
GenericRun m = new GenericRun();
m.run(new ArrayList<>());
m.run(new Integer(5));
m.run(5);
NotGenericRun n = new NotGenericRun();
n.run(new ArrayList<>());
n.run(new Integer(5));
n.run(13);
}
}
Output of this code was following:
Generic Run: []
Generic Run: 5
Generic Run: 5
Non Generic Run List: []
Non Generic Run Int: 5
Non Generic Run Int: 13
When you use Generic run as I already said arguments may be any object but there is other way of restricting the arguments while still using generics.
public class GenericRun {
public <T> void run(T object) {
String message = "Generic Run: ";
System.out.println(message.concat(object.toString()));
}
}
This is how.
public class GenericRun <T> {
public void run(T object) {
String message = "Generic Run: ";
System.out.println(message.concat(object.toString()));
}
}
In this case you'll be using GenericClass like this:
GenericRun<Integer> m = new GenericRun<Integer>();
m.run(new Integer(5));
m.run(5);
and only value that it will be tacking should be stated while creating class. I can't think of scenario when public <T> void run(T object) { ... } may be needed but it might occur when you'll need the method to get every argument or you don't know what arguments will be (but it's really less likely). I think more often when you'll be using generics with run like this:
public class GenericRun <T> {
public void run(T object) {
...
}
}
I was searching about usage of generic methods here you can read more about why may we need generic methods.
Here is another example:
public class GenericRun {
public <T> void run(T[] inputArray) {
for (T element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
}
Using this class you can print array of different type using a single Generic method:
public class TestClass {
public static void main(String[] args) {
GenericRun m = new GenericRun();
// Create arrays of Integer, Double and Character
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'H', 'E', 'L', 'L', 'O' };
System.out.println("Array integerArray contains:");
m.run(intArray); // pass an Integer array
System.out.println("\nArray doubleArray contains:");
m.run(doubleArray); // pass a Double array
System.out.println("\nArray characterArray contains:");
m.run(charArray); // pass a Character array
}
}
I hope I answered your question.
The only thing makes sense here is if this was some kind of pseudo-abstract or base class, that provided framework for behaviour and let another coders implement their own logic, but also provided default null action.
It could allow for better generic type-setting, for example as:
class MySubClass extends JavaApplication14 {
public <T> void run(T obj){
new ArrayList<T>().add(obj);
}
}
Related
I have the following code and it doesn't work: the error both methods have same erasure appears.
public class Foo<V> {
public static void main(String[] args) {
}
public void Bar(V value) {
}
public void Bar(Object value) {
}
}
Also I have this code:
public class Foo<V> {
public static void main(String[] args) {
}
public void Bar(B value) {
}
public void Bar(A value) {
}
}
class A {
}
class B extends A {
}
And this works. In the first case V is a child of Object, just like in the second case B is a child of A. Then why the first case results in error, while the second compiles successfully?
EDIT: What should I do to achieve method overloading, without raising an error?
What should I do to achieve method overloading, without raising an error?
Simple: don't try to overload the method with parameters with the same erasure.
A few options:
Just give the methods different names (i.e. don't try to use overloading)
Add further parameters to one of the overloads, to allow disambiguation (ideally only do this if you actually need those parameters; but there are examples in the Java API where there are junk parameters simply to avoid overloading issues).
Bound the type variable, as suggested by #Kayaman:
<V extends SomethingOtherThanObject>
V isn't "a child of Object". V is an unbounded generic type that erases to Object, resulting in the error. If the generic type were bounded, such as <V extends Comparable<V>>, it would erase to Comparable and you wouldn't get the error.
I am trying to understand how to use wildcard in Java.
import java.util.List;
public class WildcardError{
void foo(List<?> i){
i.set(0, i.get(0));
}
}
public class WildcardFixed{
void foo(List<?> i){
fooHelper(i);
}
private <T> void fooHelper(List<T> l){
l.set(0, l.get(0));
}
}
Why the first class cannot be compiled whereas the second one can?
What happen when compiler sees the wildcard? turns it into Object? like void foo(Object i) in the first class, or void foo(List<Object> i).
How type inference works in the second class ?
In the first example you could have passed a List<String>, so if you set an element with an Object (the result of l.get(0)), you cannot actually do that type-safely. A bit of a myopic view.
In the second example, l.get(0) is a T, and fits perfectly in the l.set,
Good tutorial explaining this https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
...
It isn't safe to add arbitrary objects to it however:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
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.
On the other hand, given a List, we can call get() and make use of the result. The result type is an unknown type, but we always know that it is an object. It is therefore safe to assign the result of get() to a variable of type Object or pass it as a parameter where the type Object is expected.
When I do this:
import java.util.ArrayList;
import java.util.List;
public class Wildcard {
public static void main(String[] args) {
WildcardFixed wf = new WildcardFixed();
List<Integer> li = new ArrayList<>();
li.add(0);
wf.foo(li);
System.out.println("Success");
}
}
class WildcardError{
void foo(List<?> i){
i.set(0, i.get(0));
}
}
class WildcardFixed{
void foo(List<?> i){
fooHelper(i);
}
private <T> void fooHelper(List<T> l){
l.set(0, l.get(0));
}
}
The WildcardError class fails to compile with message
The method set(int, capture#1-of ?) in the type List is not applicable for the arguments (int, capture#2-of ?)
In plainer English, the compiler is saying that it doesn't know what type of thing is contained in i, i.e. it doesn't know what type is returned by the get(), and it doesn't know what type of argument the set() takes, so it can't guarantee that the set() operation will succeed.
WildcardFixed, however, compiles simply because we reassure the compiler that, whatever type is in l, the result of the get will be the same type, T, as the argument type of the set. The compiler doesn't need much to go on, but it needs more than ?.
You can get simpler, though. If you put the type parameter T into the original foo() method, everything compiles and runs perfectly.
import java.util.ArrayList;
import java.util.List;
public class Wildcard {
public static void main(String[] args) {
WildcardFixed wf = new WildcardFixed();
List<Integer> li = new ArrayList<>();
li.add(0);
wf.foo(li);
System.out.println("Success WildcardFixed");
WildcardWithT wt = new WildcardWithT();
wt.foo(li);
System.out.println("Success WildcardWithT");
}
}
class WildcardError{
void foo(List<?> i){
i.set(0, i.get(0));
}
}
class WildcardFixed{
void foo(List<?> i){
fooHelper(i);
}
private <T> void fooHelper(List<T> l){
l.set(0, l.get(0));
}
}
class WildcardWithT {
<T> void foo(List<T> i) {
i.set(0, i.get(0));
}
}
I'm having some problems with a method returning a generic list. The code is basically this:
public class MyClass{
private List<MyListElement> myList = new ArrayList<MyListElement>();
public <E> List<E> getGenericList(){
return new ArrayList<E>();
}
public void thisWorks(){
List<MyListElement> newList = getGenericList();
myList.addAll(newList);
}
public void thisDoesntWork(){
myList.addAll(getGenericList());
}
public void thisDoesntWorkEither(){
for(MyListElement elem : getGenericList()){
fiddle();
}
}
}
Why does the thisDoesntWork() method not work, and is there any other way around it (other than doing it the thisWorks() way which isn't always practical)?
The compiler cannot infer what type to choose for the type parameter <E> of the generic method getGenericList() in thisDoesntWork().
In this case you need to explicitly state the Type for the type argument by calling <MyListElement>getGenericList()
Alternatively you can change the signature of getGenericList() to accept a Class<E> argument. Then you would invoke getGenericList(MyListElement.class) in both thisWorks() and thisDoesntWork(). Admittedly that's a bit more verbose, but definitly more intuitive to clients of your method.
I would say as a general rule, try to make the type arguments of your generic methods be inferrable from that method's arguments.
You can change thisDoesntWork() like so:
public void thisDoesntWork(){ // well, it works now
myList.addAll(this.<String>getGenericList());
}
You need to tell the compiler what type getGenericList() is dealing with.
The type argument to the generic method <E> getGenericsList() can be passed at call time:
this.<String>getGenericsList()
otherwise the compiler does its best to deduce it from the context. When you assign the returned object to a List<String> reference, the compiler hence infers that you passed String as the type argument.
Given the List API:
List<E> {
void addAll(Collection<? extends E> c);
}
the compiler doesn't seem to be able to infer the correct type, and to be honest I don't know if this is because it is not smart enough, or because it doesn't want to carry the responsibility by design.
I even made a test to see if the problem is the wildcard, or if addAll() cannot infer the type arguments from the parameterized type, but nothing seems to work:
public class GenericsList {
public static void main(String[] args) {
// same signature as Java API
List<String> base = new List<String>();
base.addAll(GenericsList.getList()); // ERROR!
// addAll() doesn't use a wildcard
List2<String> base2 = new List2<String>();
base2.addAll(getList2()); // ERROR!
// what about a generic method?
addAll(base, getList()); // ERROR!
}
static <E> List<E> getList() {
return new List<E>();
}
static <E> void addAll(List<E> src, List<E> other) {}
static <E> List2<E> getList2() {
return new List2<E>();
}
static class List<E> {
void addAll(List<? extends E> other) {}
}
static class List2<E> {
void addAll(List2<E> other) {}
}
}
This code will work for you.
getGenericList() should know what it is returning and that should be compatible with your list type.
You need not cast it to String or any other as suggested by others as it will restrict your getGenericList method intention by tying it to string type.
public class MyClass{
private List<MyListElement> myList = new ArrayList<MyListElement>();
public <E extends MyListElement> List<E> getGenericList(){
return new ArrayList<E>();
}
public void thisWorks(){
List<MyListElement> newList = getGenericList();
myList.addAll(newList);
}
public void thisDoesntWork(){
myList.addAll(getGenericList());
}
public void thisDoesntWorkEither(){
for(MyListElement elem : getGenericList()){
fiddle();
}
}
}
When writing a generic method to process data for a form, I came across with the following (as I see it) unexpedted behavior. Given the following code:
public class Test {
public <T> void someGenericMethod(Integer a) {
#SuppressWarnings("unchecked")
T t = (T) a;
System.out.println(t);
System.out.println(t.getClass());
}
public static void main(String[] args) {
Test test = new Test();
test.<BigDecimal>someGenericMethod(42);
}
}
AFAIK, the code above should generate a ClassCastException in the line T t = (T) a because the method call in main is setting the parametrized type to BigDecimal and casting from Integer to BigDecimal is not allowed, conversely to what I expected, the program executed well and printed the following:
42
class java.lang.Integer
In fact, if I add another parameter to the method signature (like String b) and make another assigment T t2 = (T) b, the program prints
42
class java.lang.String
Why the t variable changed it's type to Integer (is, by any chance, making some kind of promotion on the type T to Object)?
Any explanation on this behavior is welcome
(T) a is an unchecked cast: due to type erasure, the runtime has no way of knowing what type T is, so it can't actually check if a belongs to type T.
The compiler issues a warning when you do this; in your case, you've suppressed that warning by writing #SuppressWarnings("unchecked").
Edited to add (in response to a further question in the comments below):
If you want to check the cast, you can write this:
public class Test {
public <T> void someGenericMethod(Class<T> clazz, Integer a) {
T t = clazz.cast(a);
System.out.println(t);
System.out.println(t.getClass());
}
public static void main(String[] args) {
Test test = new Test();
// gives a ClassCastException at runtime:
test.someGenericMethod(BigDecimal.class, 42);
}
}
by passing in clazz, you allow the runtime to check the cast; and, what's more, you allow the compiler to infer T from the method arguments, so you don't have to write test.<BigDecimal>someGenericMethod anymore.
Of course, the code that calls the method can still circumvent this by using an unchecked cast:
public static void main(String[] args) {
Test test = new Test();
Class clazz = Object.class;
test.someGenericMethod((Class<BigDecimal>) clazz, 42);
}
but then that's main's fault, not someGenericMethod's. :-)
When compiling, your code above basically becomes the following non-generic method:
public void someGenericMethod(Integer a) {
Object t = a;
System.out.println(t);
System.out.println(t.getClass());
}
There is no cast. No exception.
You specify a type parameter in your method signature, but never use it.
I think you want something like this:
public class Test {
public <T> void someGenericMethod(T someItem) {
System.out.println(someItem);
System.out.println(someItem.getClass());
}
}
public static void main(String[] args) {
Test test = new Test();
BigDecimal bd = new BigDecimal(42);
test.someGenericMethod(42); // Integer
test.someGenericMethod("42"); // String
test.someGenericMethod(42L); // Long
test.someGenericMethod(bd); // BigDecimal
}
Note that there's no need to cast.
The parameter type is declared in the method signature and inferred from the parameter.
In your code you're parameterizing the method call (which I've never seen) and passing in an int.
It's kinda hard to understand what you're trying to do, since your example code does nothing.
How can I iterate over a wildcard generic? Basically I would like to inline the following method:
private <T extends Fact> void iterateFacts(FactManager<T> factManager) {
for (T fact : factManager) {
factManager.doSomething(fact);
}
}
If this code is in a separate method as shown, it works because the generic method context allows to define a wildcard type (here T) over which one can iterate. If one tries to inline this method, the method context is gone and one cannot iterate over a wildcard type anymore. Even doing this automatically in Eclipse fails with the following (uncompilable) code:
...
for (FactManager<?> factManager : factManagers) {
...
for ( fact : factManager) {
factManager.doSomething(fact);
}
...
}
...
My question is simply: Is there a way to put some wildcard type one can iterate over, or is this a limitation of generics (meaning it is impossible to do so)?
No. In situation like this, the workaround is to create a helper method.
The JLS has this example http://java.sun.com/docs/books/jls/third_edition/html/conversions.html#5.1.10
public static void reverse(List<?> list) { rev(list);}
private static <T> void rev(List<T> list) { ... }
The issue is, we have a List<?> object. We know it must be a List<X> of some X, and we'd like to write code using X. Internally compiler does convert the wildcard to a type variable X, but Java language does not offer programmers a direct way to access it. But if there's a method accepting List<T>, we can pass the object to the method. Compiler infers that T=X and the call is good.
If there's no type erasure, X can be known at runtime, then Java would definitely give us a way to access X. However as of today since X isn't available at runtime, there's not much point. A purely synthetic way could be provided, which is unlikely to be simpler than the helper method workaround.
Type parameters can only defined on
types (i.e. classes/interfaces),
methods, and
constructors.
You would need a type parameter for a local block, which is not possible.
Yeah, I missed something like this sometimes, too.
But there is not really a problem with having the method non-inlined here - if it presents a performance bottleneck where inlining would help, Hotspot will inline it again (not caring about the type).
Additionally, having a separate method allows giving it a descriptive name.
Just an idea, if you need this often:
interface DoWithFM {
void <T> run(FactManager<T> t);
}
...
for (FactManager<?> factManager : factManagers) {
...
new DoWithFM() { public <T> run(FactManager<T> factManager) {
for (T fact : factManager) {
factManager.doSomething(fact);
}
}.run(factManager);
...
}
...
You can always fall back to Object
for (FactManager<?> factManager : factManagers) {
...
for ( Object fact : factManager) {
factManager.doSomething(fact);
}
...
}
This, of course, is subject to what is the actual declaration of doSomething.
If doSomething is declared as this void doSomething( T fact ), then your recourse here would be to use a raw type and swallow unchecked warnings. If you can guarantee that FactManager can only have homogeneous Facts inserted, then that may be an OK solution.
for (FactManager factManager : factManagers) { // unchecked warning on this line
...
for ( Object fact : factManager) {
factManager.doSomething(fact);
}
...
}
Well, I can think of a way to do it using inner classes, because the inner class shares the type parameter with its enclosing type. Also, even using wildcards you could still process your collections thanks to wildcard capture conversion.
Let me create an example. This code compiles and runs fine. But I cannot be certain if the use of inner classes would be an issue for you.
//as you can see type parameter belongs to the enclosing class
public class FactManager<T> implements Iterable<FactManager<T>.Fact> {
private Collection<Fact> items = new ArrayList<Fact>();
public void doSomething(Fact fact) {
System.out.println(fact.getValue());
}
public void addFact(T value) {
this.items.add(new Fact(value));
}
#Override
public Iterator<Fact> iterator() {
return items.iterator();
}
public class Fact {
//inner class share its enclosing class type parameter
private T value;
public Fact(T value) {
this.value = value;
}
public T getValue() {
return this.value;
}
public void setValue(T value) {
this.value = value;
}
}
public static void main(String[] args) {
List<FactManager<String>> factManagers = new ArrayList<FactManager<String>>();
factManagers.add(new FactManager<String>());
factManagers.get(0).addFact("Obi-wan");
factManagers.get(0).addFact("Skywalker");
for(FactManager<? extends CharSequence> factManager : factManagers){
//process thanks to wildcard capture conversion
procesFactManager(factManager);
}
}
//Wildcard capture conversion can be used to process wildcard-based collections
public static <T> void procesFactManager(FactManager<T> factManager){
for(FactManager<T>.Fact fact : factManager){
factManager.doSomething(fact);
}
}
}
This is more precisely matched to the method you defined (that is, if you can call iterateFacts() with the FactManagers in factManagers, you know that the FactManager contain items that are some subclass of Fact).
for (FactManager<? extends Fact> factManager : factManagers) {
for (Fact fact : factManager) {
factManager.doSomething(fact);
}
}
I would tend to think, however, that you would declare FactManager to be generic for subtypes of Fact (just given the name of the class), e.g.
class FactManager<T extends Fact> implements Iterable<T> {
...
}
The Eclipse refactoring fails because it cannot infer the type of an object contained by FactManager<?>.