Jeremy H.
Jeremy H.

Reputation: 69

Java: <E extends Comparable <E>>

So this program is attempted to take a command line argument like the following:

S 4 1 2 3 4 4

args[0] is the array type

args[1] is the array length

args[2...] are the values in the array

args[length-1] is a key that will be used in a linear search

public class whatTheFoo{

    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <E> void main(String[] args) {

        for(int i=0;i<args.length;i++)System.out.print(args[i]);
        System.out.println();

        int arraySize = Integer.parseInt(args[1]);
        E[] array = (E[])new Object[arraySize];
        E key = null;

        if (args[0].matches("I|i")) {
            for (int i = 2; i < args.length-1; i++) {
                array[i-2]=(E)new Integer(args[i]);
                System.out.println(array[i-2]);
            }
            key = (E) new Integer(args[args.length-1]);
            System.out.println("Key is: " + key);
        } 

    ...

        if(linearSearch(array, key)<0)
            System.out.println("Didnt find it");
        else 
            System.out.println("Found it at index: "+(linearSearch(array, key)-1));
    }

    public static <E> int linearSearch(E[]array,E key) {
        int index=-1;
        for(int i=0;i<array.length;i++) {
            if(array[i].equals(key)){
                index = (int) array[i];
            }
        }
        return index;
    }
}

This works, but when I change the linearSearch method to:

public static <E extends Comparable<E>> int linearSearch(E[]array,E key) 

I get the error message:

The method linearSearch(E[], E extends Comparable<E>) in the type Prog7b is not applicable for the arguments (E[], E)

but if I change main to:

public static <E extends Comparable<E>> void main(String[] args) {

I get:

 Exception in thread "main" I412344java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
at whatTheFoo.main(whatTheFoo.java:10)

The method has been directed to include in the method:

<E extends Comparable<E>>. 

Where am I going wrong? Thanks for reading.

-------------------------------------------------------------------

For those that may be curious, this is the end result of all the help supplied. Thanks again!

public class Prog7b {

//  @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void main(String[] args) {

        if (args[0].matches("I|i")) {
            Integer[] array = new Integer[Integer.parseInt(args[1])];
            for (int i = 2; i < args.length - 1; i++) {
                array[i - 2] = new Integer(args[i]);
            }
            Integer key = new Integer(args[args.length - 1]);
            if (linearSearch(array, key) < 0) {
                System.out.println("Didnt find it");
            } else
                System.out.println("Found it at index: " + (linearSearch(array, key) - 1));
            System.out.println("The max of the array is: " + max(array));
            print(array);
        } else if (args[0].matches("S|s")) {
            String[] array = new String[Integer.parseInt(args[1])];
            for (int i = 2; i < args.length - 1; i++) {
                array[i - 2] = new String(args[i]);
            }
            String key = new String(args[args.length - 1]);
            if (linearSearch(array, key) < 0) {
                System.out.println("Didnt find it");
            } else
                System.out.println("Found it at index: " + (linearSearch(array, key) - 1));
            System.out.println("The max of the array is: " + max(array));
            print(array);
        } else {
            Double[] array = new Double[Integer.parseInt(args[1])];
            for (int i = 2; i < args.length - 1; i++) {
                array[i - 2] = new Double(args[i]);
            }
            Double key = new Double(args[args.length - 1]);
            if (linearSearch(array, key) < 0) {
                System.out.println("Didnt find it");
            } else
                System.out.println("Found it at index: " + (linearSearch(array, key) - 1));
            System.out.println("The max of the array is: " + max(array));
            print(array);
        }
    }

    public static <E extends Comparable<E>> int linearSearch(E[] array, E key) {
        int index = 0;
        for (int i = 0; i < array.length; i++) {
            index++;
            if (array[i].equals(key)) {
                return index;
            }
        }
        return -1;
    }

    public static <E extends Comparable<E>> E max(E[] list) {
        E max = list[0];
        for (int i = 1; i < list.length; i++) {
            if (max.compareTo(list[i]) < 0) {
                max = list[i];
            }
        }
        return max;
    }

    private static <E> void print(E[] list) {
        System.out.print("[");
        for (int i = 0; i < list.length - 1; i++)
            System.out.print(list[i] + ", ");
        System.out.print(list[list.length - 1] + "]\n");
    }
}

Upvotes: 2

Views: 3505

Answers (1)

Radiodef
Radiodef

Reputation: 37855

I don't think main is supposed to be generic. (The <E> part in the method declaration declares a type variable, which makes it generic.) If main is really supposed to be generic, then you need to talk to your teacher because they are doing something weird and we can't really guess about it.

Generics are a compile-time only concept. Basically the idea is that you have some code which is actually somewhat agnostic about particular types, but still need some kind of abstract information about it.

For example, suppose we had some method that checks if an object is null:

Object requireNonNull(Object obj) {
    if (obj == null) {
        throw new NullPointerException();
    } else {
        return obj;
    }
}

This is fine. We can pass any sort of object to the method. (Integer, String, whatever.) But what if we wanted to assign the return value directly?

We want to be able to do this:

String mightBeNull = ...;
String definatelyNotNull = requireNonNull(mightBeNull);

This makes our validation code neater. (Maybe instead of checking for null, our validation is actually about 10 lines long and we don't want to repeat it all the time.)

Well, as it stands, we can't, because we will get a compile-time error for trying to assign an Object to a String.

Generics let us do this, though:

<T> T requireNonNull(T obj) {
    if (obj == null) {
        throw new NullPointerException();
    } else {
        return obj;
    }
}

The type parameter <T> says that we declare a sort of temporary type. We don't care about what it actually is, but we can say that the method returns whatever we pass to it. Whatever type obj is at the point that we call requireNonNull, the method returns that type to the caller.

So now we can do this:

String  s = requireNonNull("");
Integer i = requireNonNull(10);
Float   f = requireNonNull(2f);

And so on.

requireNonNull is actually a real method and that is how it works.

The point, though, is that generics let you write very general API which gets called by non-generic code.

For your assignment it looks like you're supposed to write a generic method linearSearch with a bounded type parameter <E extends Comparable<E>> (essentially meaning that whatever array type you pass to linearSearch, it has to be some subtype of Comparable). Then you're probably supposed to pass it different types of arrays in main, like Integer[], String[], etc. Your main method won't be generic. You'll just have an if...else if chain for each type that args[0] requires.

Upvotes: 4

Related Questions