简体   繁体   中英

JAVA function overloading with generic type issue

A method in class Test<T> which returns an integer....

public int getIndex(T a) //generic parameter
    {
        return 1; // purposely left simple
    }

An array instantiated with default size 5: boolean[] arr = new boolean[5]; now I have a couple of overloading function, purposely made simple....

public void add(T a) // generic parameter
    {
        add(getIndex(a));
    }

public void add(int a)
{
        //boolean array with default size 5
        arr[a] = true;
    }
}

In main:

public static void main(String[] args) {
     Test<Character> test = new Test<Character>();
     test.add('A'); // throws exception
} 

it always gives me arrayOutOfBoundException: 65

To my understaing the compiler only recognize the character as an ASCII integer value instead of invoking the method with generic type parameter, why does this happen, how do I make it work? EDIT: I made it work when I declare a Test of String type since there's no ASCII casting involved.

The value 'A' is of type char . In Java, char is a numeric type, so it can be assigned to int . Furthermore, when there are two overloaded methods - one taking int , the other taking the boxed type Character - you will get the int one:

class Test {
    static void method(int a) {
        System.out.println("int");
    }
    static void method(Character a) {
        System.out.println("Character");
    }
}
> Test.method('A');
int

In particular, the integer value of 'A' is 65, since that's its Unicode value. So you are actually calling the add(int) method with the value 65, not the add(Character) method, hence the IOOBE.

To fix it, either cast to Character explicitly when calling the method, or change the names to addByIndex and addByValue so that Java won't select the wrong one based on the argument types.


To understand why Java chooses the add(int) method instead of add(Character) , requires wading through the Java Language Specification. Section §15.12 specifies how method calls are resolved:

The first phase (§15.12.2.2) performs overload resolution without permitting boxing or unboxing conversion, or the use of variable arity method invocation. If no applicable method is found during this phase then processing continues to the second phase.

So the add(int) method matches in the first phase because converting from a char to an int is not a boxing or unboxing conversion; and that method is chosen without proceeding to the second stage of method resolution where the boxing conversion from char to Character would be allowed.

When there's an ambiguity on which method to call due to overloading, Java clearly defines order of resolution:

  • Exact match
  • Implicit and up casts
  • Autoboxing

See for example this question for more information.

That's why, in your case, Java prefer to implicitly cast your char into int, rather than boxing char into Character and call the generic overload.

The same problem exists with a List and the remove method. Consider:

List<Integer> l = new ARrayList<>();
l.add(10);
l.remove(10); // crash because it calls remove(int) rather than remove(E) with E=Integer

The solution is to don't rely on autoboxing . For example for the List above, you can write:

l.remove(Integer.valueOf(10));

And therefore, in your case:

test.add(Character.valueOf('a'), Character.valueOf('b'));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM