我在學校被分配了一個練習:我必須定義一個類ListSorter(或ArraySorter)來實作我們研究的許多排序演算法并使用它們對整數陣列進行排序。
相反,我決定嘗試制作一個*Sorter<>可以對任何型別的資料進行排序的泛型。
問題是,您甚至如何管理陣列和泛型?我發現了很多困難(甚至無法使用,List.toArray()因為如果我記得很清楚,它需要傳遞所需型別的陣列,否則回傳的陣列將是Object[]--> ClassCastException)。
這就是為什么我改用陣列排序的原因,希望它能讓我的作業更輕松……但事實并非如此。
import java.util.List;
/**
* The class ListSorter contains many implementations of famous sorting algorithms, whether their
* performances are optimal or not.
*
*/
public final class ListSorter<T extends Comparable<T>> {
/**
* Sorts a list using the Insertion Sort algorithm, in time O(n^2). Actually, if the list is already
* partially sorted, this method reaches better performances.
* @param list the list to be sorted
* @param <T> the type of the elements of the list
*/
public void insertionSort(List<T> list) {
for (var i = 1; i < list.size(); i ) {
var current = list.get(i);
int j = 0;
// Trova il posto giusto per current
while (j <= i - 1 && list.get(j).compareTo(current) <= 0)
j ;
// Scambia l'elemento corrente con l'ultimo
list.set(i, list.get(list.size() - 1));
// Fai posto per inserire current al posto giusto, shiftando gli elementi a destra
for (var k = list.size() - 1; k > j; k--) {
list.set(k, list.get(k - 1));
}
list.set(j, current);
}
}
/**
* Sorts a list using the Bubble Sort algorithm, in time O(n^2). Actually, it is far more probable
* that this method is going to reach better performances.
* @param list the list to be sorted
* @param <T> the type of the elements of the list
*/
public void bubbleSort(List<T> list) {
boolean listChanged;
do {
listChanged = false;
for (var i = 0; i < list.size() - 1; i ) {
if (list.get(i).compareTo(list.get(i 1)) > 0) {
var temp = list.get(i);
list.set(i, list.get(i 1));
list.set(i 1, temp);
listChanged = true;
}
}
} while (listChanged);
}
public void heapSort(List<T> list) {
// TODO
}
public void mergeSort(T[] array) {
mergeSort(array, 0, array.length - 1);
}
private void mergeSort(T[] array, int start, int end) {
if (start >= end)
return;
int mid = (start end) / 2;
mergeSort(array, start, mid);
mergeSort(array, mid 1, end);
merge(array, start, mid, end);
}
private void merge(
T[] array, int firstPointer, int firstTerminator, int secondTerminator) {
var auxArray = getGenericArrayInstance();
int secondPointer = firstTerminator 1;
int auxPointer = 0;
while (firstPointer <= firstTerminator && secondPointer <= secondTerminator) {
if (array[firstPointer].compareTo(array[secondPointer]) <= 0) {
auxArray[auxPointer] = array[firstPointer];
firstPointer ;
} else {
auxArray[auxPointer] = array[secondPointer];
secondPointer ;
}
auxPointer ;
}
}
// I know this may be bad practice, but I saw it here and needed to try.
// Didn't solve my problem, though, as I can't decide the length of
// the array --> IndexOutOfBoundsException
@SafeVarargs
private T[] getGenericArrayInstance(T ...dummyValues) {
return dummyValues;
}
我現在的問題是:我是否試圖在錯誤的地方使用泛型,我是否錯誤地使用了泛型,或者什么?我從來沒有和他們合作過這么深入,所以我想看看你在這些情況下能做些什么。
uj5u.com熱心網友回復:
在 Java 中,不幸的是,陣列和泛型不能很好地協同作業。這樣做的主要原因是因為陣列需要運行時型別資訊(陣列在運行時知道其元素的型別是什么),但泛型使用型別擦除(型別引數僅在編譯時存在)。后果之一是,你不能創建一個泛型型別的陣列的實體T與new T[]-問題是,什么T是,在運行時未知。
在getGenericArrayInstance你在你的問題有上述方法不是解決類似的問題:
private T[] getGenericArrayInstance(T ...dummyValues) {
return dummyValues;
}
這個方法什么都不做。它只回傳您傳遞給它的陣列。使用零引數呼叫它就像使用零長度陣列呼叫它一樣,因此在這種情況下它將回傳一個零長度陣列。
有一種方法可以創建T[]使用反射的實體。但它要求您顯式傳遞陣列元素的型別。你可以這樣寫:
import java.lang.reflect.Array;
// ...
private T[] getGenericArrayInstance(Class<T> elementType, int length) {
return (T[]) Array.newInstance(elementType, length);
}
請注意,這意味著您還必須elementType通過整個方法鏈。所以你會得到:
public void mergeSort(T[] array, Class<T> elementType) {
mergeSort(array, elementType, 0, array.length - 1);
}
private void mergeSort(T[] array, Class<T> elementType, int start, int end) {
if (start >= end) return;
int mid = (start end) / 2;
mergeSort(array, elementType, start, mid);
mergeSort(array, elementType, mid 1, end);
merge(array, elementType, start, mid, end);
}
private void merge(T[] array, Class<T> elementType, int firstPointer, int firstTerminator, int secondTerminator) {
var auxArray = getGenericArrayInstance(elementType, array.length);
// ...
}
你必須這樣稱呼它:
String[] names = {"c", "a", "b", "z", "d"};
ListSorter<String> sorter = new ListSorter<>();
// Note that you have to pass String.class here
sorter.mergeSort(names, String.class);
注意:這解決了創建T[]. 如果你解決這個問題的代碼仍然是行不通的,因為在merge方法你把排序的結果auxArray,但你不更新原始array。
(ps:我有一門關于陣列的Pluralsight 課程;在課程結束時,我會準確地解釋陣列和泛型的問題所在)。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/375636.html
上一篇:簡化泛型型別宣告
