class My<T> {
void overloadMethod(String s) {
System.out.println("string");
}
void overloadMethod(Integer i) {
System.out.println("integer");
}
void overloadMethod(T t) {
System.out.println("t");
}
}
public class MyClass01 {
public static void main(String[] args) {
String o = "abc";
new My<String>().overloadMethod(o);
}
}
This gives the following error:
/MyClass01.java:20: error: reference to overloadMethod is ambiguous
new My<String>().overloadMethod(o);
^
both method overloadMethod(String) in My and method overloadMethod(T) in My match
where T is a type-variable:
T extends Object declared in class My
1 error
I was expecting "string" output assuming that type erasure would ensure that the third method would be:
void overloadMethod(Object t) {
System.out.println("t");
}
What am I missing here?
Thanks.
By instantiating the generic class MyClass<T> into the specific parameterized type new My<String>().overloadMethod(o);, you've effectively declared two methods with this same signature: overloadMethod(String s).
That's what the compiler error is trying to tell you with: „error: reference to overloadMethod is ambiguous“.
„…What am I missing here?…“
Because you say: „I was expecting "string" output“, it sounds like you're mistakenly assuming that your declaration of class My<T> has somehow imbued your non-generic method overloadMethod(String s) with the powers of parametric polymorphism. It hasn't.
The problem is the void overloadMethod(T t), here T is generic Class, it could be anything, when you declared
new My<String>() then T = String
try to comment in the overloadMethod(String s), you will get "t" as output
The ambiguity comes into play since T = String in this case, so the class has 2 methods to call
void overloadMethod(String s) = void overloadMethod(T t)
And doesn't know wich one to call
Related
I know that when working with Generics we can't instantiate an object of unknown type i.e the statment :
T var = new T() will give compile time error , I tried it using Reflections after some search , but its not compiling and gives me the error I will mention at the end
Code :
public class HelloWorld{
public static void main(String []args){
Pair<Integer> obj = new Pair<Integer>(Integer.class);
obj.<Integer>func();
}
}
class Pair<T>
{
T var;
<T> Pair(){}
<T> Pair(Class<T> reflection){
var = reflection.newInstance() ;
}
<T> void func(){
System.out.println(var);
}
}
Error :
HelloWorld.java:12: error: incompatible types: T#1 cannot be converted to T#2
var = reflection.newInstance() ;
^
where T#1,T#2 are type-variables:
T#1 extends Object declared in constructor <T#1>Pair(Class<T#1>)
T#2 extends Object declared in class Pair
I am trying to find the cause of the error but can't reach it
class Pair<T>
{
T var;
<T> Pair(){}
<T> Pair(Class<T> reflection){
var = reflection.newInstance() ;
}
<T> void func(){
System.out.println(var);
}
}
The <T>s on the constructors and method are defining another type variable which hides the one on the class. They are all called "T", but they're different types.
(The ones on the zero-arg constructor and func are unused anyway).
Remove these extra type variable declarations.
class Pair<T> {
T var;
Pair() {}
Pair(Class<T> reflection) {
var = reflection.newInstance();
}
void func() {
System.out.println(var);
}
}
Then you just have to deal with the fact that not all classes have accessible zero-arg constructors; and that newInstance() throws checked exceptions that you would need to handle.
A better approach would be to provide a Supplier<T>:
Pair(Supplier<T> reflection) {
var = reflection.get();
}
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.
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);
}
}
I'd like to use the new method references of Java 8 to provide more validation of some code at compile time.
Let's say I have a validateMethod method which requires one parameter : a "method" to be validated. For example :
validateMethod(foo, "methodA");
Here, the method would validate that foo#methodA() exists, at runtime.
Using method references, I'd like to be able to do :
validateMethod(foo::methodA);
So the existence of the method would be validated at compile time.
The problem is that it seems method references have to be assigned to a functional interface. For example, this :
Object dummy = foo::methodA;
Generates the error : "The target type of this expression must be a functional interface".
If I create a functional interface that has a compatible signature with the methodA method, it works :
#FunctionalInterface
public interface MyFunctionalInterface
{
public String run();
}
MyFunctionalInterface dummy = foo::methodA;
Now the existence of foo#methodA() is validated at compile time, which is what I want!
But...
Let's say validateMethod doesn't know the signature of the method it has to validate. Is it still possible to implement it then?
Let's pretend we don't care about ambiguity and overloaded methods. Is it possible in Java 8 to implement some kind of method which would trigger the validation of any method reference?
For example :
public class Foo
{
public String methodA()
{
return "methodA";
}
public String methodB(String str)
{
return "methodB";
}
public String methodC(String str, int nbr)
{
return "methodC";
}
}
Foo foo = new Foo();
validateMethod(foo::methodA); // Compile
validateMethod(foo::methodB); // Compile
validateMethod(foo::methodC); // Compile
validateMethod(foo::methodD); // Error!
Would it be possible to implement validateMethod in such a way that any method reference would be accepted, so the existence of the method would be validated at compile time?
I tried :
public void validateMethod(Object obj){}
But it doesn't work : "The target type of this expression must be a functional interface"
This would work :
#FunctionalInterface
public interface MyFunctionalInterface
{
public String run();
}
public void validateMethod(MyFunctionalInterface param){}
But only for methodA of the Foo class, because its signature (no parameter) is compatible with the functional interface's method signature!
Would it be possible to implement the functional interface MyFunctionalInterface in such a way that any method reference would be a valid parameter and therefore would be validated at compile time?
Any other ways you see to validate the existence of a method at compile time?
You seem to be trying to use method references, which are really the short-hands for lambda expressions, as method literals, which are the syntactic references to methods (much like Foo.class is the syntactic reference to class instance of Foo). These two are not the same, and this is the reason for the impedance you encounter. Things you try are the abuse of language feature which javac compiler utterly resists.
Unfortunately, there is no method literals in Java, so you will have to describe the method by other means, e.g. Reflection, MethodHandles.Lookup, etc. I think it is very easy to come up with the reflective checker for this kind of thing, or even build up the annotation processor to check the existence of given methods in compile time.
You could try something like the following:
public class Validate {
public String methodA() { return "methodA"; }
public String methodB(String s) { return "methodB"; }
public String methodC(String s, int n) { return "methodC"; }
public static void main(String[] args) {
Validate foo = new Validate();
validateMethod(foo::methodA);
validateMethod(foo::methodB);
validateMethod(foo::methodC);
}
private interface Func0 { void method(); }
private interface Func1<T> { void method(T t); }
private interface Func2<T, U> { void method(T t, U u); }
private interface Func3<T, U, V> { void method(T t, U u, V v); }
public static void validateMethod(Func0 f) { }
public static <T> void validateMethod(Func1<T> f) { }
public static <T, U> void validateMethod(Func2<T, U> f) { }
public static <T, U, V> void validateMethod(Func3<T, U, V> f) { }
}
But you'll need to provide an interface and an overload of validateMethod for every arity of method you need to validate. Also, it will not work if the method to validate is overloaded, unless you add an explicit cast:
// if there are two methodA's:
public String methodA() { return "methodA"; }
public String methodA(long x) { return "methodA"; }
validateMethod(foo::methodA); // this doesn't work
validateMethod((Func0)foo::methodA); // this does
validateMethod((Func1<Long>)foo::methodA); // so does this
would interface Method { public Object runMethod(Object... args); } work? the only potential problem i see is methods that deal with primitive types, but perhaps they could be upcast automatically to Double's / Long's, dont really have a running java8 compiler atm.
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.