I have written sorting methods for an array of comparables, insertion, merge, and selection, I've done this by altering code I had before from sorting an int array, and I just changed things from int to Comparable. However, When I was doing it for int arrays, I knew very well how to actually use the method, for example this is my my selection sort for ints:
public void selectionSort(int[] list){
for (int i=0;i<list.length;i++){
for (int si=i;si<list.length;si++){
if (list[si]<list[i]){
int temp=list[i];
list[i]=list[si];
list[si]=temp;
}
}
}
}
and this is the code which ends up using this method:
public static void main(String[] args) {
Scanner in=new Scanner(System.in);
int numItems,searchNum,location;
Sorts sort=new Sorts();
int[]test;
System.out.print("Enter the number of elements: ");
numItems=in.nextInt();
test=new int[numItems];
for (int i=0;i<test.length;i++){
test[i]=(int)(100*Math.random());
}
System.out.println("Unsorted: ");
displayArray(test);
sort.selectionSort(test);
System.out.println("Sorted: ");
displayArray(test);
and everything works fine, but for my comparable selection sort, I have this code:
public static void selectionSort(Comparable[] list){
for (int i=0;i<list.length;i++){
for (int si=i;si<list.length;si++){
if (list[si].compareTo(list[i])<0){
Comparable temp=list[i];
list[i]=list[si];
list[si]=temp;
}
}
}
}
but when I get to writing the code to test out this method, I just have no idea how to approach it, I don't know how I can make an array of Comparable interfaces, the concept is just so confusing for me and I can't find a way to make it work.
Integer, for instance, implements Comparable, so it's legal to write:
Comparable[] list = new Comparable[3];
list[0] = Integer.valueOf(3);
list[1] = Integer.valueOf(2);
list[2] = Integer.valueOf(3);
You can see all the implementors of Comparable in the standard JDK by looking at the JavaDoc.
The trouble is (and you should see some compiler warnings about this), you can't both specify the generic parameter for Comparable and make an array of the parameterized object, that is, it's not legal to write:
Comparable<Integer>[] list = new Comparable<Integer>[3];
Even if it were legal to write that, you'd run into a new issue, since you need the concrete type to use in the Comparable<T> test. Comparable<T> requires a comparison to an object of type T (the method is int compareTo(T o)). In essence, your code only works because it's unparameterized (T is implicitly Object, everything extends Object), but you're losing some compile-time safety checks along the way.
It might make more sense to parameterize your input by an array of generic parameterized Comparable objects rather than as an array of Comparable. Writing this using generics is a little bit tricky, the method prototype would look something like:
public static void <T extends Comparable<T>> selectionSort(T[] list) {
// legal to call list[k].compareTo, because `T` is guaranteed to be `Comparable`
}
Notably, this will work for any non-primitive object type T that implements Comparable<T>, such as an Integer[] or Double[], but not an int[].
Related
I can't seem to find exactly how to do this anywhere. I am writing a class that takes a comparator as a parameter/argument for the constructor of a class. I want to use that to order items in a list. But I'm not sure what to do with the comparator in the new class.
I have imported java.util.Comparator
In the class declaration I said "impements Comparator<T>"
I have written (Comparator<T> c) as the argument for the constructor of the class.
I have never used a comparator this way--I've used it as an inner class and that is it so I'm not sure how to make the compare method work in this class when I take the comparator in as an argument to the constructor.
The only things I've done that are the three bulleted items above. Anytime I try to do something with comparator I am taking in as an argument, I get an error message.
Here is the code for the constructor:
public class SortedList<T> implements Comparator<T>
//value, position and array are instance variables
//I am switching array to a List to deal with generics
private int position;
private Integer[] array;
public SortedList(Comparator<T> c){
this.position = 0;
this.array = new Integer[25];
}
public void sort(Integer num){
boolean valid = false;
int i = 0;
while(!valid && i < array.length-1){
if(num.compareTo(array[i] > 0)){
array[i+1] = array[i];
array[i] = num;
}else{
i++;
}
}
The error messages I have been getting are:
Cannot find symbol - method compareTo
I would like to be able to compare any two objects, not just integers, that was why I wanted to take a comparator as a parameter.
It's not clear from your question, but the only collection-ish construct in your snippet is an array of integer objects. Thus, the only sane thing to sort here is that array.
You'd need a Comparator<Integer> to sort that, not a Comparator<T>.
Once you have that, to sort that array, all you need to do is..
Arrays.sort(array, c);
Your SortedList<T> class must not implement the Comparator<T> interface, because this class is not used for comparing objects. However, it will use a given Comparator<T> instance to sort its entries. This means the classes and methods should have the following definitions:
public class SortedList<T> {
// ...
}
The class does not implement the Comparator<T> interface anymore.
private T[] array;
The array field should be of type T[] since this SortedList<T> object is used to sort/hold objects of type T, not Integer objects.
public SortedList(Comparator<T> c){
// ...
this.comparator = c;
}
That's correct. The constructor receives a Comparator<T> instance. You should store this reference to a field so you can later use it in your sort() method.
public void sort(){
// ...
}
The Integer argument on the sort() method doesn't make any sense, so delete it. Now you can use the stored Comparator<T> instance in your sort() method and call its compare() method to compare two objects from your stored array. A code fragment might look like this:
// ...
if (this.comparator.compare(this.array[i], this.array[i+1])) {
// it should be on the left
} else {
// it should be on the right
}
// ...
I am trying to write a method that will find the difference between elements of two arrays of the same length and here is what I did until now:
public static <T extends Object> T method(T[] array,T[] array1){
T[]difference;
difference = new T[array.length]; //error :generic array creation
for(int i=0;i<array.length;i++){
difference[i]=array[i]-array1[i]; //error:bad operand types for binary operator
}
return (T)difference;
}
but it constantly returns to me a message that i wrote next to the line of the code that it refers to
There are two problems with your code:
Java doesn't support generic array creation. You can get round this by creating an array of Objects and then casting.
The bigger problem is that java doesn't support operator overloading, and subtraction (i.e. -) is only supported by primitive types. This is compouded by the fact that generics doesn't support primitive types, which makes what you're trying to do impossible on its own.
To get round these problems, you'd need to do a number of things:
Don't use primitives, but you can used boxed types instead (so instead of int you'd use Integer, etc.).
You need to tell your function how to find the difference between two objects of the required type. You can achieve this by defining a 'Subtractor' interface.
I'd also suggest using lists instead of arrays, as these handle generics much more nicely. You can easily convert between lists and arrays afterwards if needed.
So, as a skeleton of a solution, here's what I'd propose:
Define a generic interface for finding differences:
interface Subtractor<T> {
T subtract(T a, T b);
}
Rewrite your method to use lists, and to take a subtractor as an argument:
public static <T> List<T> difference(
List<? extends T> listA, List<? extends T> listB, Subtractor<T> subtractor) {
int resultSize = Math.min(listA.size(), listB.size());
List<T> result = new ArrayList<>(resultSize);
for(int i=0; i<resultSize; ++i) {
result.add(subtractor.subtract(listA.get(i), listB.get(i)));
}
return result;
}
Define subtractor implementations for the types you want to be able to use the method with:
class IntSubtractor implements Subtractor<Integer> {
#Override
Integer subtract(Integer a, Integer b) {
return Integer.valueOf(a.intValue() - b.intValue());
}
}
Use your method. You can use Arrays.asList for turning arrays into lists, but you can't use arrays of primitives unfortunately.
Integer[] a = new Integer[]{5,6,7,8};
Integer[] b = new Integer[]{1,2,3,4};
Integer[] c = difference(Arrays.asList(a), Arrays.asList(b), new IntSubtractor())
.toArray(new Integer[4]);
I assume that your array values are numbers. It is difficult to provide a general solution. But I would say this might work for your case:
public static <T extends Number> Number[] method(T[] array, T[] array1){
Number[]difference = new Number[array.length];
for(int i=0; i< array.length; i++){
difference[i]= Double.valueOf(array[i].doubleValue() - array1[i].doubleValue());
}
return difference;
}
Assuming that I have the following class
public class A <T>{
private T [] datas;
// more code here ...
}
And I desire to take advantage of the constructor to initialize the array. Suppose that I have the following constructor
public A(T element){....}
Java does not allow me to use something like
datas = new T[10]
And it will complain that I cannot create a generic array of T
But I can still use a work around like:
#SuppressWarnings("unchecked")
public A(T element){
List<T> datasList = new ArrayList<T>();
datasList.add(element);
datas =(T[]) datasList.toArray();
}
I have a warning from the compiler that's why I had to add the #SuppressWarnings, but my point is related to the following comment from the toArray method documentation (Please take a look at the picture)
It talks about the returned array being safe. So does that means it is safe to use this method? If not why? And what would be a better way to do such an initialisation in a constructor? I would like to also consider the case of a variable list of T elements in an overloaded constructor like
public A(T... elements){....}.
You can create an instance of a generic array using the following:
public A(T element){
int length = 10;
datas = (T[])Array.newInstance(element.getClass(), length);
}
However, there's a problem if element would be a subclass of T, e.g. if you'd call it like this:
A<Number> numberA = new A<>( Integer.valueOf(1) );
Here T would be Number but the class of element would be Integer.
To mitigate that you could pass a vararg array of type T, e.g. like this:
//firstElement only exists to force the caller to provide at least one element
//if you don't want this then just use the varargs array
A(T firstElement, T... furtherElements){
int length = 10;
Class<?> elementClass = furtherElements.getClass().getComponentType();
datas = (T[])Array.newInstance( elementClass, length);
}
Since varargs always result in an array (even of length 0) you'll get an array of type T and can get the component type of that.
So in the case above numberA.datas would be a Number[] array and not an Integer[] array.
You can pass generics, but you can't call new T (or new T[ ]).
Keep in mind that generics are gone after compilation, so it actually only helps when writing the code. Knowing it's gone during runtime, it's also obvious that new T( ) can't be called as generic, T is removed in runtime.
It's safe to do, because you create that list in full control, accepting only objects of your generic type.
A nicer way (imho) is to create a static method as it is purely input-->output. You have to declare your generics before the method return type:
public < T > T[ ] toArray(T... objects) { ... }
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.
I've been relearning Java after a long time, and I'm trying out writing some sorting algorithms. The (rather outdated) textbook I have uses the Comparable interface to sort objects. Since Comparables are now generic types, doing this gives me a lot of warnings about raw types when compiling. After some research, it looks like I can do something like, for example:
public class Sorting
{
public static <T extends Comparable<T>> void quickSort(T[] list, int start, int end)
{
/*...*/
while((list[left].compareTo(list[pivot]) < 0) && (left != right)) // for example
left++;
/*...*/
}
}
The problem with this is that the naive way of calling this method does not work:
public class SortingTest
{
public static void main(String[] args)
{
// Produces an error, cannot create arrays of generic types
Comparable<Integer>[] list = new Comparable<Integer>[100];
/* fill the array somehow */
Sorting.quickSort(list, 0, 99);
}
}
It is illegal to create an array of generic types in Java. The problem only gets worse if I try to implement a merge sort, since that requires creating arrays of Comparable types inside the merge sort method itself.
Is there any way to handle this situation elegantly?
Note that T extends Comparable<T>. It doesn't have to be Comparable<T>.
So you could, for example, create an array of Integers, because Integer implements Comparable<Integer>.
Integer[] list = new Integer[100];
/* fill the array somehow */
Sorting.quickSort(list, 0, 99);
You have to make an array of Object and then cast to an array of T. Note that this will create a compiler warning.