Nishant123
Nishant123

Reputation: 1966

Shadowing of type parameters

I have a very basic question regarding type parameters which I came across while solving a problem.

I have a class with a string array which I am sorting using a custom Comparator class. Below is my Comparator class

class SortComparator implements Comparator<String>
    {

        @Override
        public int compare(String o1, String o2) {
            // TODO Auto-generated method stub
            return  o1.compareTo(o2);
        }

    }

The above class runs fine and outputs the desired result.

If the class name is changed from SortComparator to SortComparator<String> the compare method needs to be changed. The class after changes looks like this

class SortComparator<String> implements Comparator<String>
{

    @Override
    public int compare(String o1, String o2) {
        // TODO Auto-generated method stub
        return  ((java.lang.String) o1).compareTo((java.lang.String) o2);
    }

}

The above class also runs fine and outputs the desired result

Why is there a need to explicitly cast the String objects o1 and o2 to java.lang.String when they already are objects of the same class?

I searched for this query of mine for some time on net and found a very similar question

Comparing two Integers with my own Comparator

The answer to this question says that it is because of shadowing.

I know shadowing in terms of local variables, instance variables and class variables but how does it work in this case?

Upvotes: 3

Views: 454

Answers (1)

Braj
Braj

Reputation: 46861

The problem is with generic type that is called String. It's collision between generic type parameter and actual class String.

Because the type parameter String is unbounded, the Java compiler replaces it with Object hence arguments of method compare works as Object and object class doesn't have compareTo method hence you have to cast.

Try below example that works fine.

class SortComparator<T> implements Comparator<String>
{

    @Override
    public int compare(String o1, String o2) {
        // TODO Auto-generated method stub
        return  o1.compareTo(o2);
    }

}

Please have a look at Java documentation on Erasure of Generic Types

During the type erasure process, the Java compiler erases all type parameters and replaces each with its first bound if the type parameter is bounded, or Object if the type parameter is unbounded.

Below Example copied directly from above Java documentation for more clarity.

Consider the following generic class that represents a node in a singly linked list:

public class Node<T> {

    private T data;
    private Node<T> next;

    public Node(T data, Node<T> next) }
        this.data = data;
        this.next = next;
    }

    public T getData() { return data; }
    // ...
}

Because the type parameter T is unbounded, the Java compiler replaces it with Object:

public class Node {

    private Object data;
    private Node next;

    public Node(Object data, Node next) {
        this.data = data;
        this.next = next;
    }

    public Object getData() { return data; }
    // ...
}

Upvotes: 8

Related Questions