How to compare two generic types in java

Get full access to Java Generics and Collections and 60K+ other titles, with free 10-day trial of O'Reilly.

Show

There's also live online events, interactive content, certification prep materials, and more.

Now that we have the basics, let’s look at some more advanced uses of generics. This chapter describes the interfaces Comparable<T> and Comparator<T>, which are used to support comparison on elements. These interfaces are useful, for instance, if you want to find the maximum element of a collection or sort a list. Along the way, we will introduce bounds on type variables, an important feature of generics that is particularly useful in combination with the Comparable<T> interface.

The interface Comparable<T> contains a method that can be used to compare one object to another:

interface Comparable<T> { public int compareTo(T o); }

The compareTo method returns a value that is negative, zero, or positive depending upon whether the argument is less than, equal to, or greater than the given object. When a class implements Comparable, the ordering specified by this interface is called the natural ordering for that class.

Typically, an object belonging to a class can only be compared with an object belonging to the same class. For instance, Integer implements Comparable<Integer>:

Integer int0 = 0; Integer int1 = 1; assert int0.compareTo(int1) < 0;

The comparison returns a negative number, since 0 precedes 1 under numerical ordering. Similarly, String implements Comparable<String>:

String str0 = "zero"; String str1 = "one"; assert str0.compareTo(str1) > 0;

This comparison returns a positive number, since "zero" follows "one" under alphabetic ordering.

Get Java Generics and Collections now with the O’Reilly learning platform.

O’Reilly members experience live online training, plus books, videos, and digital content from nearly 200 publishers.

2021-6-5 anglehua

I want to generate a binary tree with key - value pairs in their nodes.

In my binary tree I want to implement nodes at the beginning with an insert method, which implements a new left node if the key is smaller than the key of the current node. Then if there is already a left node it will check again for it. The same logic follows for right/greater node inserts.

I wrote my code first using the int type because it's way easier for me to test my code before I use generics (new topic for me). It worked when using int but I an unsure how to compare two generics with themselves by using "<" or ">".

public ListCell<Type> checkKey(Type key, ListCell<Type> checkCell) { ListCell<Type> newCell = null; if (key < checkCell.key && checkCell.left != null) { ... } ... }

I don't know if it's worth saying but I'm creating my binary tree with a selfcoded list. Above you can see my current checks but i can't compare my given key now with checkCell.key because of them not being numbers.

So my general question is how to compare the keys in generics if they are "smaller" or "greater" than the other for my implementation in a binary tree.

Thanks in advance

You would need to ensure that your generic type implemented the Comparable interface, and then use the compareTo method instead. Java does not support overloading the > operator (or any operator overloading, for that matter).

As per the documents, compareTo:

Returns a negative integer, zero, or a positive integer as this object is less than, equal to, or greater than the specified object.

An example (that you'll have to map on to your exact code), assuming that key is your item you will store in your node, and checkCell.key is your node

int compareResult = key.compareTo(checkCell.key); if (key < 0) { // it goes on the left } else if (key == 0) { // it is the same } else { // it goes on the right }

In your compareTo method you need to decide what fields in your class determine it's "ordering". For example, if you have a size and priority field, you might do:

@Override public int compareTo(Type other) { final int BEFORE = -1; final int EQUAL = 0; final int AFTER = 1; if (this == other) return EQUAL; if (this.size < other.size) return BEFORE; else if (this.size > other.size) return AFTER; else { // size is equal, so test priority if (this.priority < other.priority) return BEFORE; else if (this.priority > other.priority) return AFTER; } return EQUAL; }

Bounded type parameters are key to the implementation of generic algorithms. Consider the following method that counts the number of elements in an array T[] that are greater than a specified element elem.

public static <T> int countGreaterThan(T[] anArray, T elem) { int count = 0; for (T e : anArray) if (e > elem) // compiler error ++count; return count; }

The implementation of the method is straightforward, but it does not compile because the greater than operator (>) applies only to primitive types such as short, int, double, long, float, byte, and char. You cannot use the > operator to compare objects. To fix the problem, use a type parameter bounded by the Comparable<T> interface:

public interface Comparable<T> { public int compareTo(T o); }

The resulting code will be:

public static <T extends Comparable<T>> int countGreaterThan(T[] anArray, T elem) { int count = 0; for (T e : anArray) if (e.compareTo(elem) > 0) ++count; return count; }

bounded type parameters

采集自互联网,如有侵权请联系本人

2021-6-5 anglehua

I have the following method:

public <U, V> boolean isEqual(List<U> a, List<V> b) { // check if U == V }

I want to check if U and V are the same classes.

You can't do that because of type erasure, it is that simple.

Consider the following:

public static void main(String[] args) { List<? extends Number> l1 = Arrays.asList(1L, 2, 3L); List<? extends Number> l2 = Arrays.asList(1); isEqual(l1, l2); } public static <U, V> boolean isEqual(List<U> a, List<V> b) { // is U == V here? }

Is U == V here? l1 contains Long and Integer instances but l2 contains a single Integer instance.

I'm guessing from your comment:

The first condition should be that their type are the same

that what you should have instead is a single type U. In this case, use the following signature:

public static <U> boolean isEqual(List<U> a, List<U> b) { }

and with that, the above code won't compile anymore.

What you could also do is add 2 parameters accepting the classes:

public static <U, V> boolean isEqual(List<U> a, List<V> b, Class<U> uClass, Class<V> vClass) { if (!uClass.equals(vClass)) { // classes are different } }

In this case, you can print a message if the classes given are not the same.

If you are making your own class you can require that Class<T> be included in the constructor as demonstrated here

Ex:

public class SomeClass<T> { private final Class<T> clazz; public SomeClass(Class<T> clazz) { this.clazz = clazz; } public Class<T> getParam() { return clazz; } }

Now you can call SomeClass#getParam() to get the type param declared.

There is also a way to do this with reflection.

All this said, the reason you have to do weird work-arounds to this is because of Type Erasure. Basically at runtime Java sees all generics as Object, so while compiling your List may be a List<Integer> or List<Boolean>, but at runtime they're both List<Object>.

采集自互联网,如有侵权请联系本人

public: abstract int Compare(T x, T y); public abstract int Compare (T x, T y); public abstract int Compare (T? x, T? y); abstract member Compare : 'T * 'T -> int Public MustOverride Function Compare (x As T, y As T) As Integer Int32

A signed integer that indicates the relative values of x and y, as shown in the following table.

Value Meaning
Less than zero x is less than y.
Zero x equals y.
Greater than zero x is greater than y.

Examples

The following example defines a comparer of Box objects that can be used instead of the default comparer. This example is part of a larger example provided for the Comparer<T> class.

public class BoxLengthFirst : Comparer<Box> { // Compares by Length, Height, and Width. public override int Compare(Box x, Box y) { if (x.Length.CompareTo(y.Length) != 0) { return x.Length.CompareTo(y.Length); } else if (x.Height.CompareTo(y.Height) != 0) { return x.Height.CompareTo(y.Height); } else if (x.Width.CompareTo(y.Width) != 0) { return x.Width.CompareTo(y.Width); } else { return 0; } } } Public Class BoxLengthFirst Inherits Comparer(Of Box) ' Compares by Length, Height, and Width. Public Overrides Function Compare(ByVal x As Box, ByVal y As Box) As Integer If x.Length.CompareTo(y.Length) <> 0 Then Return x.Length.CompareTo(y.Length) ElseIf x.Height.CompareTo(y.Height) <> 0 Then Return x.Height.CompareTo(y.Height) ElseIf x.Width.CompareTo(y.Width) <> 0 Then Return x.Width.CompareTo(y.Width) Else Return 0 End If End Function End Class

Remarks

Implement this method to provide a customized sort order comparison for type T.

Notes to Implementers

Comparing null with any reference type is allowed and does not generate an exception. A null reference is considered to be less than any reference that is not null.

For information on culture-specific comparisons, see the System.Globalization namespace and Globalization and Localization.

Applies to

  • IComparable<T>
  • IComparable
  • StringComparer
  • Object
  • CultureInfo