تجاوز طريقة "يساوي":كيفية معرفة نوع المعلمة؟
-
06-07-2019 - |
سؤال
أحاول التجاوز equals
طريقة لفئة ذات معلمات.
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Tuple))
return false;
Tuple<E> other = (Tuple<E>) obj; //unchecked cast
if (!a0.equals(other.a0) && !a0.equals(other.a1)) {
return false;
}
if (!a1.equals(other.a1) && !a1.equals(other.a0)) {
return false;
}
return true;
}
كيف يمكنني التأكد من ذلك <E>
التابع other
الكائن هو نفسه this
?
المحلول
ويمكنك القيام بذلك عن طريق الاحتفاظ إشارة إلى نوع Class<E>
. ومع ذلك، في رأيي، يجب أن يكون <م> الاختبارات المساواة حول القيم الكائنات تمثل بدلا من أنواع ملموسة الحصول أعرب القيم م>.
والمثال الكلاسيكي على ذلك هو API مجموعات على سبيل المثال. new ArrayList<String>().equals(new LinkedList<Object>())
يعود true
. في حين أن هذه لديها أنواع مختلفة تماما، إلا أنها تمثل نفس القيمة، وهي "مجموعة فارغة".
وشخصيا، ينبغي اثنين Tuple
s التي تمثل نفس البيانات (مثل ("a", "b")
) لا يكون على قدم المساواة، لأنه واحد من نوع Tuple<String>
حين أن الآخر هو Tuple<Object>
؟
نصائح أخرى
ولأن المحو لا يمكنك. حول أفضل ما يمكن القيام به هو مخزن في فئة الصفوف (tuple) نوع كنت تخطط لالصفوف (tuple) إلى عقد في عضو الميدان "java.lang.Class". ثم هل يمكن مقارنة تلك المجالات للتأكد من الطبقة الصفوف (tuple) تحتجز نفس أنواع.
وانظر أيضا هذا الموضوع:
ما يعادل ++ C زوج
وسيكون من المفيد لو قمت بنشر المزيد عن صفك. أنا أفكر المدلى بها دون رادع أو رقمك من الحقول التي تساوي يعني أنه ينبغي أن يكون الصفوف (tuple)
وتحرير: هنا هي فئة زوج مفيدة يمكنني استخدام بانتظام (يمكنك التكيف مع الطبقة الصفوف (tuple) إذا لزم الأمر). ملاحظة مشابهة إلى اقتراحات من قبل الآخرين هذه الفئة يتيح فقط أعضاء احتواء تبت في مسألة المساواة. حالة استخدامك هو ما يجب تحديد ما إذا كانت المساواة ويستند حقا على نوع من أعضاء احتواء.
/**
* Adapted from http://forums.sun.com/thread.jspa?threadID=5132045
*
*
* @author Tim Harsch
*
* @param <L>
* @param <R>
*/
public class Pair<L, R> {
private final L left;
private final R right;
public R getRight() {
return right;
} // end getter
public L getLeft() {
return left;
} // end getter
public Pair(final L left, final R right) {
this.left = left;
this.right = right;
} // end constructor
public static <A, B> Pair<A, B> create(A left, B right) {
return new Pair<A, B>(left, right);
} // end factory method
@Override
public final boolean equals(Object o) {
if (!(o instanceof Pair<?,?>))
return false;
final Pair<?, ?> other = (Pair<?, ?>) o;
return equal(getLeft(), other.getLeft()) && equal(getRight(), other.getRight());
} // end method
public static final boolean equal(Object o1, Object o2) {
if (o1 == null) {
return o2 == null;
}
return o1.equals(o2);
} // end method
@Override
public int hashCode() {
int hLeft = getLeft() == null ? 0 : getLeft().hashCode();
int hRight = getRight() == null ? 0 : getRight().hashCode();
return hLeft + (37 * hRight);
} // end method
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append('<');
if( left == null ) {
sb.append("null");
} else {
sb.append(left.toString());
} // end if
sb.append(',');
if( right == null ) {
sb.append("null");
} else {
sb.append(right.toString());
} // end if
sb.append('>');
return sb.toString();
} // end method
} // end class
وركضت للتو في هذه المشكلة بنفسي، وفي حالتي -particular-، لم أكن بحاجة إلى معرفة نوع E.
وعلى سبيل المثال:
public class Example<E> {
E value;
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Example<?> other = (Example<?>) obj;
if (value == null) {
if (other.value != null)
return false;
} else if (!value.equals(other.value))
return false;
return true;
}
}
في رمز أعلاه، لا يوجد يلقي دون رادع بسبب استخدام Example<?>
. نوع البدل المعلمة '؟ ينقذ اليوم.
للأسف، لا يمكنك القيام بذلك في وقت الترجمة؛لقد اختفت المعلومات.هذه هي عواقب نوع المحو.البديل هو تخزين المعلمة كـ a Class
المثال، ثم ابحث عنه لاحقًا.
يتم مسح الأدوية في وقت الترجمة ، كنت في الأساس لا يمكن. في وقت التشغيل، وذهب أي معلمة نوع، وبقدر ما يتعلق الأمر JVM، فإنها هي نفسها تماما من جميع النواحي.
والطريقة للتغلب على ذلك هو لتخزين حقل Class
الذي يمثل نوع، وإنشاء الكائن مع هذا النوع في منشئ.
وعينة المنشئ:
public class Tuple < E > {
public Tuple(Class<E> c) {
//store the class
}
}
وأو هل يمكن استخدام المصنع:
public static <E> Tuple <E> getTuple(Class<E> type) {
// Create and return the tuple,
// just store that type variable in it
// for future use in equals.
}
والاقتراحات للاحتفاظ إشارة إلى نوع E
مع كائن Class
يبدو <م> غير فعال م> (وهذا هو الكثير من إشارات لا معنى لها لClass
تناول الذاكرة) والعبث لمشكلتك.
وانها ليست عموما صحيح أن Foo<Bar>
andFoo<Baz>
يجب أن يكون غير متكافئ. لذلك لا تحتاج E
. و، في رمز كتبته، حتى أنك لا تحتاج إلى ترجمة. ببساطة يلقي إلى Tuple<?>
، لأن ذلك هو حقا كل ما تعرفه عن Tuple
في تلك المرحلة. لا يزال يجمع وجميع.
إذا تم تمريرها لك Tuple
s مع البيانات من نوعين مختلفين بعنف، لن equals
تلك العناصر، وسوف طريقتك عودة false
، كما تريد. (تأمل واحدة - يعتمد على تلك الأنواع تنفيذ equals
عاقل)
خارج الموضوع - هل تدرك أنه وفقًا لتطبيقك، فإن Tuple(a0, a1) يساوي Tuple(a1, a1)؟أظن أن هذا ليس ما تريده ...
وفيما يتعلق بالموضوع، كما قال آخرون، فإن المحو يجعل هذا الأمر مستحيلاً.ولكن يجب عليك إعادة النظر في سبب رغبتك في ذلك - فالتحقق من المساواة يحدث فقط في وقت التشغيل، و الأدوية العامة هي وقت الترجمة فقط.من الناحية المفاهيمية، أ عامل لديه معلمات عامة، ولكن هدف لا.وبالتالي، عند مقارنة تساوي الكائنات، فإن المعلمات العامة لا تهم على الإطلاق؛لا يمكنك اتخاذ أي إجراء مناسب بناءً عليها في وقت التشغيل على أي حال.
تعد المساواة في الكائنات، والتباين المشترك/المتغير للمعلمة العامة، من الاهتمامات المتعامدة.
وأنا أتفق مع التعليقات الواردة أعلاه، لماذا الطبقة E تحتاج إلى أن تكون على قدم المساواة؟ وكيف تريد لعلاج الفئات الفرعية من E؟
وعلى أي حال، بالنظر إلى أن هنا هو نموذج التعليمات البرمجية التي قد تساعدك:
public class Example<T> {
T t;
public Example(T t) {
this.t = t;
}
public static void main(String[] args) {
final String s = "string";
final Integer i = 1;
final Number n = 1;
final Example<String> exampleString = new Example<String>(s);
final Example<Integer> exampleInteger = new Example<Integer>(i);
final Example<Number> exampleNumber = new Example<Number>(n);
System.out.println("exampleString subclass " + exampleString.t.getClass());
System.out.println("exmapleIntger subclass " + exampleInteger.t.getClass());
System.out.println("exmapleNumber subclass " + exampleNumber.t.getClass());
System.out.println("Integer equals Number = " +
exampleInteger.t.equals(exampleNumber.t));
}
}
ويمكنك الاتصال t.getClass () للحصول على معلومات فئة عن نوع T (على افتراض أنه ليس لاغيا، بالطبع).
وآمل أن يساعد هذا.
واستخدام التفكير. http://tutorials.jenkov.com/java-reflection/generics.html