Why doesn't autoboxing work in this case with generics? [duplicate] - java

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Java: Array of primitive data types does not autobox
I've been doing some Java lately (mostly as a recap on what I did at university as my current job doesn't involve any Java at all) and one thing that never got introduced to us properly is Generics.
I've been doing the Generics tutorial on the Oracle Java website and I've been stumped by the following example that I modified a bit:
public static <Integer extends Comparable<Integer>> int countGreaterThan(Integer [] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
And I use this method to compare an Integer array with the following Integer:
Integer [] numarr = {1, 2, 3, 4 , 5};
Integer num = new Integer(5);
int count = Util.countGreaterThan(arrnum, num);
This seems to work fine, however if I pass a primitive array and a primitive int, it doesn't:
int [] arrnum = {1, 2, 3, 4 , 5};
int othernum = 3;
int count = Util.countGreaterThan(arrnum, othernum);
The compiler complains with:
method countGreaterThan in class Generics.Util
cannot be applied to given types;
required: Integer[],Integer
found: int[],int
reason: no instance(s) of type variable(s)
Integer exist so that argument type int conforms to formal parameter type Integer
The tutorials seemed to be pretty adamant that Java will always autobox/unbox objects and primitives as necessary and yet it won't do it in this particular case, what am I missing?
Also what could be a good way to generalise this comparing method as much as possible? If I used T instead of Integer, then it would look for a T object, rather than whatever I pass to it.
I apologise if the post is confusing and if I seem pretty ignorant about the stuff I talk about above, it's just that I've been working primarily as a perl programmer (and not as particularly experienced one either) and generalising there seems as less of an issue (due to the lack of type enforcement).
Thanks in advance!

The code below seems to work as far as I can see:
public static <Integer extends Comparable<Integer>> int countGreaterThan(Integer [] anArray, Integer elem) {
int count = 0;
for (Integer e : anArray) {
if (e.compareTo(elem) > 0)
++count;
return count;
}
although I get a warning "The type parameter Integer is hiding the type Integer". See #ErichSchreiner's answer for an explanation of why auto-boxing won't work here.
A good generalisation of your method would be:
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;
}
All you really care about is that anArray has the same type of elements as elem is, and that it is comparable to it's own type.

Your declaration of countGreaterThan() hides the built-in type Integer. To clarify, consider the slightly modified version:
public static <I extends Comparable<I>> int countGreaterThan(I [] anArray, I elem) {
int count = 0;
for (I e : anArray)
if (e.compareTo(elem) > 0)
++count;
return count;
}
Now it should become apparent that your second attempt at calling can not work as there can be no autoboxing done. For generics to work, you need to supply objects, not primitives.

Related

(Java) Return generic T array index as int after passed into an int function?

I had this 4-part Pset for a class (submission deadline already passed), but I've been dying on problem 1 and the next set Pset is going to be open later this week. I've read the HW chapters, gone to office hours (they can help the concept with but can't help with implementing code) and rewatched lectures, but I can't find how I'm supposed to do this.
This is the part that I can't change (import java.util.* is included above it):
public static <T extends Comparable<T>> int findMax(T[] arr)
So it's an int function that passes a type T array and is supposed to return an int index. I tried a number of ways to try iterating using for & while loops, but the problem is I can't figure out how to do it.
This code below is modified from programmer/blogger Deepesh Darshan's post on finding max values using generics, as it was really similar to one of mine that used a for loop. the "return -1;" is in case no code was added.
int maxPoint = arr[0];
for(T arrScan : arr){
if(arrScan.compareTo(maxPoint) > 0 ) {
maxPoint = arrScan;
}
return maxPoint;
}
return -1;
}
One issue is his solution uses T the whole way through and mine can't.
public static <T extends Comparable<T>> T max(T... elements)
My code above gives the following errors:
GenericMethods.java:16: error: incompatible types: T cannot be converted to int
int maxPoint = arr[0];
^
where T is a type-variable:
T extends Comparable<T> declared in method <T>findMax(T[])
GenericMethods.java:18: error: incompatible types: int cannot be converted to T
if(arrScan.compareTo(maxPoint) > 0 ) {
^
where T is a type-variable:
T extends Comparable<T> declared in method <T>findMax(T[])
GenericMethods.java:19: error: incompatible types: T cannot be converted to int
maxPoint = arrScan;
^
where T is a type-variable:
T extends Comparable<T> declared in method <T>findMax(T[])
Note: Some messages have been simplified; recompile with -Xdiags:verbose to get full output
3 errors
I know it's because I'd need to make maxPoint "T", not "int", but that just kicks the conversion error down to the return value.
Is there some reading or advice someone could point me to on how to find the max index with the given restrictions without causing conversion errors? I can't seem to find any on GFG, W3 or any of the places suggested to me.
You need to track the index instead of the element:
int max = 0;
for (int i = 1; i < arr.length; i++) {
if (arr[i].compareTo(arr[max]) > 0) {
max = i;
}
}
return max;

Converting from Integer wrapper class to int primitive class

I've been trying to convert an Integer Wrapper class to int primitive class. I haven't yet found a proper way to make the code compile. I'm using Intellij IDEA, Java 11 Amazon Coretto, but I need to run it on a computer that runs java 8.
Here's the original code below:
static class Line<Integer> extends ArrayList<Integer> implements Comparable<Line<Integer>> {
#Override
public int compareTo(Line<Integer> other) {
int len = Math.min(this.size(), other.size());
for (int i = 0; i < len; i++) {;
if ((int) this.get(i) != (int) other.get(i)) {
if ((int this.get(i) < (int) this.get(i)) {
return -1;
} else if ((int) this.get(i) > (int)this.get(i)) {
return 1;
} else {}
}
}
...
note that the Line is inserted to an ArrayList.
Originally I used forced casting on all the Integer objects so it'll be like (int) this.get(i). It worked on my local terminal and my Intellij wasn't bothered about it, but unfortunately not the other computer. It couldn't compile there
I thought it was because of the forced casting, since the other computer returned
Main.java:159: error: incompatible types: Integer cannot be converted to int
if ((int) this.get(i) != (int) other.get(i)) {
^
where Integer is a type-variable:
Integer extends Object declared in class Line
so I deleted them all and thought I could let the machine unbox the Integer wrapper on its own. It still didn't compile.
If the code is left like what's written above (no forced casting), it will return "Operator '<' not applicable for 'Integer', 'Integer'"
So I used the .compareTo() method. Compile error.
Then I tried to assign them to an int variable. Intellij IDEA was screaming at me that it required int but found Integer instead. So I force-casted, like so
int thisLine = (int) this.get(i);
int otherLine = (int) other.get(i);
if (thisLine != otherLine) {
if (thisLine < otherLine) {
return -1;
} else if (thisLine > otherLine) {
return 1;
} else {}
Nope, didn't work. Removing the cast also didn't work.
I looked up the Javadocs (https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html#intValue--) this time about the Integer class and found a promising little method called intValue(). Problem is? Intellij cannot resolve that method (oddly, VSCode does not consider this an error). I used it like this
int thisLine = this.get(i).intValue();
int otherLine = other.get(i).intValue();
if (this.get(i) != other.get(i)) {
if (thisLine < otherLine) {
return -1;
} else if (thisLine > otherLine) {
return 1;
and sure enough, another compile error on that stubborn computer.
I'm running out of options. I'm seriously considering creating a new custom class just so I can store int values in an ArrayList without having to deal with all this Java backwards incompatibility nonsense.
Anyone here know a consistent method for converting an Integer wrapper object to an int primitive object in Java?
This is the clue in the error message that explains it:
where Integer is a type-variable:
Integer extends Object declared in class Line
Integer is not java.lang.Integer but a type variable with a confusing name...
You declared the type variable here:
static class Line<Integer> extends ArrayList<Integer> implements Comparable<Line<Integer>>
It's as if you declared it like this:
static class Line<T> extends ArrayList<T> implements Comparable<Line<T>>
but by naming the type variable Integer instead of T, and then you try to cast objects of the type T to int later on.
Fix it by not declaring a type parameter named Integer, you don't need that here:
static class Line extends ArrayList<Integer> implements Comparable<Line<Integer>>
You shouldn't have to cast an Integer to an int at all. Integer class has .compareTo methods which compare two integers.
A 0 means value1 is equal to value2. -1 is value1 is less than value2 and a 1 is value1 is greater than value2.
Try the following:
public int compareTo(Line<Integer> other) {
//get the smallest length
int len = this.size() <= other.size() ? this.size() : other.size();
for (int i = 0; i < len; i++) {
int compare = this.get(i).compareTo(other.get(i));
if (compare != 0) { //if compare is not zero they are not the same value
return compare;
}
}
//If we get here, everything in both lists are the same up to "len"
return 0;
}
The compareTo() method is a method of Integer class under java. lang
package. ... It returns the result of the value 0 if Integer is equal
to the argument Integer, a value less than 0 if Integer is less than
the argument Integer and a value greater than 0 if Integer is greater
than the argument Integer.
In you class "Integer" is not a java.lang.Integer but a Generic class that is the reason

What will be the return statement of a method, which creates an array of size n, with return type Integer[]?

I'm having trouble understanding how to return an array of user defined size in a method which return type is Integer[]. The class which contains this method extends an interface, if that makes any difference here (I don't think it does, but correct me if I'm wrong).
When trying to return a, java tells me the type is incompatible. I'm not sure if the problem lies in my method body, or if there's a particular way to phrase the return statement since the return type is Integer[]. I need to return the array without assigning a value to size, as size will be assigned a value in the main method. Please advise and explain what I'm doing wrong here. Thanks in advance!
#Override
public Integer[] generateTestDataBinary(int size) {
Comparable[] a = new Comparable[size];
for (int i = 0; i < size; i++) {
if (size <= size/2) {
a[i] = 0;
}
else {
a[i] = 1;
}
}
return a;
}
This array will be used to test the time complexity of different sorting algorithms. I have to create two more arrays after this one, each one slightly different than the last, so I need to know how to implement this method in order to finish the program. Please let me know if more code is needed to understand the context of the problem.
An Integer[] is Comparable[], but a Comparable[] is not an Integer[].
Change your type from Comparable[] to Integer[].
See java.lang.Comparable's API doc:
All Known Implementing Classes:
..., Integer, ...
and java.lang.Integer's API doc:
All Implemented Interfaces:
..., Comparable
That means an Integer is a Comparable but a Comparable is not an Integer. You cannot assign a value of a super-type (Comparable) to a variable of a sub-type (Integer). Likewise, you cannot return a value of a super-type (Comparable) from a method of a sub-type (Integer) be it an array or not:
Type mismatch: cannot convert from Comparable[] to Integer[]
The reason is: A super-type doesn't know anything about the extensions of its sub-type(s) (remember the class declaration syntax class <sub-type> extends <super-type>). Hence, assigning an object with less information (the super-type) to an object variable that is supposed to hold and has according space for more information (the sub-type) would lead to undefined areas.
So, the following compile:
public Integer[] generateTestDataBinary(int size) {
Integer[] a = new Integer[size];
// ...
return a;
}
public Comparable<Integer>[] generateTestDataBinary(int size) {
Integer[] a = new Integer[size];
// ...
return a;
}
public Comparable<Integer>[] generateTestDataBinary(int size) {
Comparable<Integer>[] a = new Comparable[size];
// ...
return a;
}

method(E[]) is not applicable to the arguments(int[]) [duplicate]

This question already has answers here:
Can a primitive value be considered an object in java?
(4 answers)
Closed 6 years ago.
I'm trying to implement my sort method, which takes a generic E[] as an argument, upon my int[]. I receive the error:
The method sort(E[]) in the type HeapSort is not applicable for the arguments (int[]).
My code is as follows:
public <E extends Comparable<E>> void sort(E[] array){
//my code
}
public static void main(String[] args){
int[] arr = new int[30];
for(int rep = 0; rep < arr.length; rep++){
arr[rep] =(int )(Math.random() * 100 + 0);
}
System.out.println("The unsorted Array: ");
System.out.println(sort(arr).toString());
}
Any ideas as to why I get this error? All help appreciated! Thank you!
A primitive type can't replace a generic type parameter (and even if it could, it couldn't satisfy your extends Comparable<E> type bound, since primitive types don't extend any class and don't implement any interface).
You can replace your int[] with an Integer[] and it will work.
Beside that error, sort(arr) doesn't return anything, so you can't execute toString on it.
You can replace it with :
new HeapSort ().sort(arr); // you must create an instance of the class that contains
// the sort method in order to call it
System.out.println(Arrays.toString(arr));
lets look at what you wrote there.
public <E extends Comparable<E>> void sort(E[] array)
this is a method called sort. it has generic parameter with a constraint. The constraint is that whatever the generic parameter you have put in, it must implement Comparable.
int doesn't implement Comparable, in fact int doesn't implement anything.
Java generics don't work with primitive types at all. Generic constraints only limit you farther.

Generic method to find largest in 2D array

So guys I have to write a generic method to find the maximum element in a 2-D array then I have to test using integers, strings, and objects.
I'm a little sleep deprived so I apologize for what is probably a very very simple fix.
I have my generic method:
public class Generic {
public static <T extends Comparable<T>> T Max(T[][]stuff) {
T max = stuff[0][0];
for (int i = 0; i < stuff.length; i++)
for(int j = 0; j <stuff.length; i++)
if (stuff[i][j].compareTo(max) > 0)
max = stuff[i][j];
return max;
}
}
and simply trying to test with integers first
public class GenericTester {
public static void main(String[] args) {
Integer[][] myArray = { {0,1,2,3}, {3,2,1,0}, {3,5,6,1}, {3,8,3,4} };
System.out.println(Generic.Max(myArray));
}
}
Ok I fixed the previous error, dumb mistake, but yes now I am getting The method Max(T[][]) in the type Generic is not applicable for the arguments (int[][])
what would be the best fix for this problem?
Thanks for any and all help
Presumably you need Generic.Max(myArray) or else you need to
import static Generic.Max;
at the top of GenericTester.java.
Generics will not work with primitive types, so T cannot be bound to int. Note, in particular, that int does not extend Comparable<int>. You will need to use an Integer[][] array instead of int and similarly for the other primitive types.
EDIT In addition to the above, your loops need some work. First, the increment on the inner loop is wrong (this is why you are seeing an ArrayIndexOutOfBoundsException). Second, your code requires that the matrix is square and full (since you use stuff.length for the inner loop limit). Here's how I would write them (using enhanced for loop syntax):
public class Generic {
public static <T extends Comparable<T>> T Max(T[][]stuff) {
T max = stuff[0][0];
for (T[] row : stuff) {
for (T elt : row) {
if (elt.compareTo(max) > 0) {
max = elt;
}
}
}
return max;
}
}
For a truly general method, you would want to check that stuff[0][0] exists.

Categories