جافا جينك: المقارنة و "الالتقاط#1 من؟"
-
21-09-2019 - |
سؤال
فيما يلي رسالة خطأ:
public static List<Comparable<?>> merge(Set<List<Comparable<?>>> lists) {
List<Comparable<?>> result = new LinkedList<Comparable<?>>();
HashBiMap<List<Comparable<?>>, Integer> location = HashBiMap.create();
int totalSize;
for (List<Comparable<?>> l : lists) {
location.put(l, 0);
totalSize += l.size();
}
boolean first;
List<Comparable<?>> lowest; //the list with the lowest item to add
int index;
while (result.size() < totalSize) {
first = true;
for (List<Comparable<?>> l : lists) {
if (! l.isEmpty()) {
if (first) {
lowest = l;
}
else if (l.get(location.get(l)).compareTo(lowest.get(location.get(lowest))) <= 0) { //error here
lowest = l;
}
}
}
index = location.get(lowest);
result.add(lowest.get(index));
lowest.remove(index);
}
return result;
}
الخطأ هو:
The method compareTo(capture#1-of ?) in the type Comparable<capture#1-of ?> is not applicable for the arguments (Comparable<capture#2-of ?>)
ماذا يحدث هنا؟ لقد صنعت نوع كل شيء Comparable
حتى أتمكن من الاتصال .compareTo
وفرز هذه القائمة. هل أستخدم الأدوية الجيرية بشكل غير صحيح؟
المحلول
List<?>
تعني "قائمة أي شيء" ، لذا فإن كائنين بهذا النوع ليسا متماثلان: يمكن للمرء أن يكون قائمة String
, والآخر قائمة من BigDecimal
. من الواضح أن هذه ليست هي نفسها.
List<T>
يعني "قائمة أي شيء ولكن عندما ترى T
مرة أخرى ، هو نفسه T
".
يجب أن تخبر المترجم عندما تقصد نفس النوع في أماكن مختلفة. محاولة:
public static <T extends Comparable<? super T>> List<T> merge(Set<List<T>> lists) {
List<T> result = new LinkedList<T>();
HashBiMap<List<T>, Integer> location = HashBiMap.create();
تحرير] فماذا يفعل <T extends Comparable<? super T>> List<T>
تعني؟ الجزء الأول يحدد النوع T
مع الخصائص التالية: يجب أن تنفذ الواجهة Comparable<? super T>
(أو Comparable<X>
أين X
يتم تعريفه أيضًا من حيث T
).
? super T
يعني أن النوع الذي Comparable
الدعم يجب T
أو واحدة من أنواعها الفائقة.
تخيل للحظة هذا الميراث: Double extends Integer extends Number
. هذا غير صحيح في جافا ولكن تخيل ذلك Double
هو مجرد Integer
بالإضافة إلى جزء الكسر. في هذا السيناريو ، أ Comparable
الذي يعمل ل Number
يعمل أيضا ل Integer
و Double
لأن كلاهما يستمد من Number
. لذا Comparable<Number>
سوف ترضي super
جزء ل T
مستخدم Number
, Integer
أو Double
.
طالما أن كل من هذه الأنواع تدعم Comparable
واجهة ، وتلبية أيضا الجزء الأول من الإعلان. هذا يعني أنه يمكنك المرور Number
ل T
وسيعمل الرمز الناتج أيضًا عندما يكون هناك Integer
و Double
مثيلات في القوائم. اذا أنت Integer
ل T
, ، لا يزال بإمكانك الاستخدام Double
لكن Number
غير ممكن لأنه لا يرضي T extends Comparable
بعد الآن (ال super
جزء سيظل يعمل ، رغم ذلك).
الخطوة التالية هي فهم أن التعبير بين static
و List
يعلن فقط خصائص النوع T
الذي يستخدم لاحقًا في الكود. بهذه الطريقة ، ليس عليك تكرار هذا الإعلان الطويل مرارًا وتكرارًا. إنه جزء من سلوك الطريقة (مثل public
) وليس جزء من الكود الفعلي.