#java
#java
Вопрос:
Я хочу переопределить метод equals () в универсальном классе, и для этого я должен привести объект к моей паре универсальных типов.
Я добавил @SuppressWarnings («непроверенный»), чтобы «отключить» предупреждения, но проблема все еще существует. Методы GetType() и getClass() также не работают с универсальными типами, поэтому об использовании T.GetType() не может быть и речи.
public class Pair<T, U> {
private T first;
private U second;
public Pair(T _first, U _second)
{
first = _first;
second = _second;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
//Problem ahead!!!
Pair<T, U> other = (Pair<T, U>) obj;
...
}
}
Есть ли какая-либо общая хорошая практика или «трюк», чтобы сделать это правильно и безопасно?
Комментарии:
1. Универсальные типы удаляются во время компиляции и не присутствуют во время выполнения, поэтому их «проверка» невозможна.
2. Ну, вы могли бы просто так
first.equals(other.first)
(еслиfirst
значение не равно null) и позволить емуequals()
обрабатывать проверки типов. Таким образом, если у вас естьPair<String, String>
и вы передаетеPair<Integer, Integer>
, у вас будетString.equals(Integer)
который вернет false.
Ответ №1:
Вы можете привести obj
к Pair<?, ?>
и вызвать equals
first
и second
:
Pair<?, ?> other = (Pair<?, ?>) obj;
return other.first.equals(first) amp;amp; other.first.equals(second);
Таким образом, проверки типов будут выполняться с помощью T.equals
and U.equals
, независимо от того, что такое T
и U
.
Ответ №2:
Вы могли бы написать свой equals
метод следующим образом:
@Override
public boolean equals(Object object) {
boolean equal = false;
if(this == object){
equal = true;
} else if(object instanceof Pair<?, ?>) {
// Check that object is an instance of Pair<?, ?>, this will also null check.
// Then just case object to Pair<?, ?> like.
Pair<?, ?> pair = (Pair<?, ?>) object;
if(((this.first == null amp;amp; pair.first == null) || (this.first != null amp;amp; this.first.equals(pair.first))) amp;amp;
((this.second == null amp;amp; pair.second == null) || (this.second != null amp;amp; this.second.equals(pair.second)))){
equal = true;
}
}
return equal;
?
Между <>
является своего рода подстановочным знаком, на самом деле он классифицируется как неограниченный подстановочный знак; это означает, что тип класса не был указан.
object instanceof Pair<?, ?>
Проверит две вещи, сначала он проверит, что объект не равен null, что создает null
безопасность для вас, а затем он проверит, что объект имеет тип Pair<?, ?>
.
Вы можете прочитать о подстановочных знаках здесь
Согласно, ntalbs
если вы переопределяете equals
, не забудьте также переопределить hashCode
.
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashcode;
result = result * prime (this.first == null ? 0 : this.first.hashCode());
result = result * prime (this.second == null ? 0 : this.second.hashCode());
return resu<
}
Почему я должен переопределять, hashCode
когда я переопределяю equals
?
Вы должны переопределить hashCode() в каждом классе, который переопределяет equals() . Невыполнение этого требования приведет к нарушению общего контракта для Object.hashCode(), что не позволит вашему классу должным образом функционировать в сочетании со всеми коллекциями на основе хэша, включая HashMap, HashSet и Hashtable.
Ответ №3:
Прежде всего, имейте в виду, что универсальные классы активны только во время компиляции. Они представляют собой дополнительный уровень проверки во время компиляции, чтобы убедиться, что вы не злоупотребляете контейнерами или функциями, которые могут принимать разные типы.
Также помните, что equals()
это всегда существовало с первого выпуска Java, в то время как универсальные классы были введены в Java 1.5. Поэтому естественно, что для этого конкретного метода вам придется выполнить некоторое приведение типов.
После приведения объекта вы в любом случае будете проверять каждый отдельный элемент Pair
, поэтому, если они другого типа, они также не пройдут проверку на равенство.
Ответ №4:
Вы можете использовать instanceof
для проверки типа вашего объекта и последующего его безопасного приведения.
if(obj instanceof Pair){
Pair other = (Pair) obj;
}
Ответ №5:
Поскольку универсальный тип стирается во время компиляции, вы не можете проверить тип во время выполнения. Итак, вы должны привести его к Pair<?,?>
.
Если вы используете JDK 7 или более позднюю версию, вы также можете использовать Objects.equals(..)
в своем equals
методе. Это упростит код, поскольку вам не нужно беспокоиться о том, является ли first
или second
null
.
Pair<?, ?> pair = (Pair<?, ?>) obj;
return Objects.equals(first, pair.first) amp;amp;
Objects.equals(second, pair.second);
Кроме того, не забудьте реализовать, hashCode
если вы добавили equals
метод в свой класс.
@Override
public int hashCode() {
return Objects.hash(first, second);
}
Ответ №6:
package com.journaldev.generics;
public class GenericsMethods {
//Java Generic Method
public static <T> boolean isEqual(GenericsType<T> g1, GenericsType<T> g2){
return g1.get().equals(g2.get());
}
public static void main(String args[]){
GenericsType<String> g1 = new GenericsType<>();
g1.set("Test");
GenericsType<String> g2 = new GenericsType<>();
g2.set("Test");
boolean isEqual = GenericsMethods.<String>isEqual(g1, g2);
//above statement can be written simply as
isEqual = GenericsMethods.isEqual(g1, g2);
//This feature, known as type inference, allows you to invoke a generic method as an ordinary method, without specifying a type between angle brackets.
//Compiler will infer the type that is needed
}
}
Комментарии:
1. Пожалуйста, отредактируйте свой ответ и добавьте к нему объяснение, чтобы он мог понять, почему