Write a Java program to define a generic method that counts the number of elements in an array T [ ] that are greater than a specified element elem.
I have written my code as:
public class GenericMethods<E extends Comparable<E>> {
public static < E > void printArray( E[] inputArray ) {
// Display array elements
for(E element : inputArray) {
System.out.printf("%s ", element);
}
System.out.println();
}
public static < E > void countArray( E[] inputArray, int elem) {
int i=0;
for(E element : inputArray){
if(elem>element)
i++;
}
System.out.println(i);
}
public static void main(String args[]) {
Scanner sc = new Scanner(System.in);
Integer[] intArray = { 1, 2, 3, 4, 5 };
System.out.println("\nArray contains:");
printArray(intArray);
int elem=0;
System.out.println("Enter the specified number: ");
elem = sc.nextInt();
countArray(intArray, elem);
}
}
I get the following errors:
error: bad operand types for binary operator '>'
if(elem>element)
^
first type: int
second type: E
where E is a type-variable:
E extends Object declared in method countArray(E[],int)
1 error
One way is to require that your generic type parameter E is a Number.
Then you can use Number's intValue() method to convert each element of the array to an int, which can be compared to elem.
public static <E extends Number> void countArray(E[] inputArray, int elem) {
int i = 0;
for (E element : inputArray) {
if(elem > element.intValue ())
i++;
}
System.out.println(i);
}
you cant use > operator on object
you can do as Eran said or ensure E implements Comparable and use compareTo()
<E extends Comparable>
if(element.compareTo(new Integer(elem))<0)
Related
I am getting complie time error if type is Integer for static method.
public static <T> int countGreaterThan(T[] anArray, T elem) {
int count = 0;
for (T e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
then I replaced T everywhere with Integer still no problem.
public static <Integer> int countGreaterThan(Integer[] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
But once I change change Integer to different type Like R compilation error gone.
public static <R> int countGreaterThan(Integer[] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray)
if (e > elem) // no Compilation error
++count;
return count;
}
what is impact of Static method type to this > operator here?
In your case <Integer> is not the type java.lang.Integer but only the name of the type argument and shadows the actual wanted type. At this point, it could as well be <T>, <VAL> or <POTATO>.
In your case this would be equivalent to the following code
public static <POTATO> int countGreaterThan(POTATO[] anArray, POTATO elem) {
int count = 0;
for (POTATO e : anArray)
if (e > elem) // compiler error
++count;
return count;
}
Since POTATO can be any type, the compiler dosen't know how to compare it to another element. The compiler doesn't know how to interpret e > elem.
When you change the type argument to something different than Integer, the code would become
public static <R> int countGreaterThan(Integer[] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray)
if (e > elem)
++count;
return count;
}
Here the type argument doesn't shadow the java.lang.Integer arguments anymore and the compiler knows how to interpret the comparison.
Edit: I posted this answer before your edit, which changed the context of your question.
You are shadowing Integer, the correct generic type to do this is the rather inscrutable T extends Comparable<? super T> like
public static <T extends Comparable<? super T>> int countGreaterThan(T[] anArray,
T elem) {
int count = 0;
for (T e : anArray) {
if (e.compareTo(elem) > 0) {
++count;
}
}
return count;
}
(and please use braces so flow control is clear). Also, if you're using Java 8+, it could be done with a Stream like
long count = Stream.of(anArray).filter(x -> x.compareTo(elem) > 0).count();
What you are doing with <Integer> is declaring a new type and calling it Integer. Note that this is NOT the same as java.lang.Integer, and is thus not eligible for comparing in this way.
By naming your new type R, you are allowing java.lang.Integer to be inferred when declaring variables of type Integer.
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");
}
}
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.
Hi I'm very new to Java and in this code, I think I'm not creating the Bag correctly in the Main? Please help thanks!
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable;
at mid.Bag.(Bag.java:12)
at mid.Bag.main(Bag.java:91)
public class Bag<T extends Comparable<T>> implements Iterable<T> {
private int MAX_ITEMS = 10; // initial array size
private int size;
private T[] data;
public Bag( ) {
data = (T []) new Object[MAX_ITEMS];
size = 0;
}
public void add(T newItem) {
// check if it's full, then extend (array resizing)
if (size == data.length) {
T[ ] temp = (T [ ] ) new Object[data.length*2];
for (int i = 0; i < size; ++i)
temp[i] = data[i];
// reassign data to point to temp
data = temp;
}
// then do the assignment
data[size++] = newItem; // assign newItem in the next-available slot
}
public Iterator<T> iterator() {
return new BagIterator();
}
/***************************
* nested class BagIterator
***************************/
class BagIterator implements Iterator<T> {
// instance member
private int index;
// (0) constructor
public BagIterator() {
index = 0;
}
// (1)
public boolean hasNext() {
return (index < size); // size in the outer Bag<E>
}
// (2)
public T next() {
/*
T temp = data[index]; // save the element value
index++; // increment index
return temp;
*/
return data[index++];
}
public static void main(String[ ] args) {
Bag<String> bag1=new Bag<String>();
bag1.add("good");
bag1.add("fortune");
bag1.add("billionarie");
for (String x: bag1)
System.out.println(x);
}
Yes, you're creating an Object[] and then trying to cast it to T[], which the compiler is converting to a cast to Comparable[] (using the raw Comparable type) due to your constraint on T.
Arrays and generics don't work terribly nicely together, basically.
It would probably be simpler to make your data field just an Object[] and cast individual values where necessary.
Here:
data = (T []) new Object[MAX_ITEMS];
you are constructing an Object array and trying to cast it to T[]. But you have declared that T inherits from Comparable. So use:
data = (T []) new Comparable[MAX_ITEMS];
You can probably rewrite your constructor as well:
public Bag(Class<T> c, int s) {
// Use Array native method to create array of a type only known at run time
#SuppressWarnings("unchecked")
final T[] dataArray = (T[]) Array.newInstance(c, s);
this.data = dataArray;
}
Then you can use it like:
Bag<String> bag1 = new Bag<>(String.class,10);
That should also work, IMO. The instances of T must be comparable in any case.
class main{
public static void main(String[] args){
int[] array = new int[3];
array[0]=3;
array[1]=2;
array[2]=1;
System.out.println(<Integer>countGreaterThan(array,1));
}
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;
}
}
I got this examle in Java Documentation. When i write extends Comparable, how can i tell the compiler what is type?
I think i should instantiate T in <T extends Comparable<T>>, but how?
Just change the int to Integer and remove that ugly <Integer> inside your print statement.
Integer[] array = new Integer[3];
array[0] = 3;
array[1] = 2;
array[2] = 1;
System.out.println(countGreaterThan(array, 1));
I would arrange this so you can use varargs
static <T extends Comparable<T>> int countGreaterThan(T elem, T... anArray) {
int count = 0;
for (T e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
}
System.out.println(countGreaterThan(1, 3,2,1));
class main {
public static void main(String[] args){
Integer[] array = new Integer[3];
array[0]=3;
array[1]=2;
array[2]=1;
System.out.println(countGreaterThan(array,1));
}
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;
}
}
Integer[] array = new Integer[3];
array[0]=3;
array[1]=2;
array[2]=1;
System.out.println(countGreaterThan(array,1));
Is this what you are looking for?
I am trying to understand generics and I purposely want to generate a classcastexception, however, i instead get an arraystoreexception on the first attempt.
static <E> E reduce(List<E> list, Function<E> f, E initVal) {
E[] snapshot = (E[]) list.toArray();
Object[] o = snapshot;
o[0] = new Long(1);
E result = initVal;
for (E e : snapshot)
result = f.apply(result, e);
return result;
}
private static final Function<Integer> SUM = new Function<Integer>(){
public Integer apply(Integer i1, Integer i2) {
return i1 + i2;
}
};
public static void main(String[] args) {
List<Integer> intList = Arrays.asList(2, 7);
System.out.println(reduce(intList, SUM, 0));
}
On the second attempt.. I correctly get a ClassCastException using this...
public static void main(String[] args) {
List<Integer> intList1 = Arrays.asList(2, 7);
List<Integer> intList = new ArrayList<Integer>(intList1);
System.out.println(reduce(intList, SUM, 0));
}
What is the difference?
It appears to me that the List instance produced by Arrays.asList() does not properly implement the contract of the toArray() method. From List.toArray() javadoc:
Note that toArray(new Object[0]) is identical in function to toArray().
However note the following test:
public static void main(String... args) {
System.out.println(Arrays.asList(2, 7).toArray());
System.out.println(Arrays.asList(2, 7).toArray(new Object[0]));
}
and output:
[Ljava.lang.Integer;#3e25a5
[Ljava.lang.Object;#19821f
Note that according to the javadoc, toArray() should produce an array of type Object[], but Arrays.<E>asList().toArray() instead produces an array of type E[].
The reason you get an ArrayStoreException is because your array is of type Integer[] when it should be of type Object[].
I don't know why you're creating an array. Just do this:
static <E> E reduce(List<E> list, Function<E> f, E initVal) {
for (E e : list)
initVal = f.apply(initVal, e);
return initVal;
}
See: KISS principle