클래스가 .equals 메서드를 재정의하도록 강제
-
06-07-2019 - |
문제
공통 인터페이스를 구현하는 클래스가 많이 있습니다.명령.
그리고 이 클래스는 Map으로 이동합니다.
지도가 올바르게 작동하려면 Command를 구현하는 각 클래스에서 Object.equals(Object other)
방법.
괜찮아.
하지만 나는 동등함을 강제로 무시하고 싶습니다.=> 명령을 재정의하지 않는 항목이 같음을 구현하면 컴파일 오류가 발생합니다.
그게 가능해요?
편집하다 :그런데, 해시코드 재정의도 강제로 적용해야 합니다...
해결책
아니, 당신은 할 수 없습니다. 그러나 할 수있는 일은 인터페이스 대신 추상적 인 기본 클래스를 사용하고 equals()
요약:
abstract class Command {
// put other methods from Command interface here
public abstract boolean equals(Object other);
public abstract int hashCode();
}
서브 클래스 Command
~ 해야 하다 그런 다음 자신의 평등 및 해시 코드 방법을 제공하십시오.
API 사용자가 기본 클래스를 연장하도록 강요하는 것은 일반적으로 나쁜 관행이지만이 경우 정당화 될 수 있습니다. 또한, 당신이 만든 경우 Command
인공 기본 클래스를 소개하는 대신 인터페이스 대신 추상적 인 기본 클래스 덧셈 명령 인터페이스에는 API 사용자가 잘못 될 위험이 없습니다.
다른 팁
java.lang.object 대신 추상적 인 xobject에서 객체를 확장 할 수 있습니까?
public abstract class XObject
extends Object
{
@Override
public abstract boolean equals(Object o);
}
아버지가 이미 평등과 해시 코드 방법을 과대 평가 한 후 다시 문제가 있기 때문에 손자가 있으면 초록 수업이 작동하지 않습니다.
Annotatins와 Apt를 사용해보십시오 (http://docs.oracle.com/javase/1.5.0/docs/guide/apt/gettingstarted.html) 끝내기 위해.
이는 Command가 인터페이스이거나 추상 클래스인 경우에만 가능합니다. 여기서 equals(..)는 추상으로 선언된 메서드입니다.
문제는 모든 객체의 슈퍼클래스인 Object가 이미 이 메소드를 정의하고 있다는 점이다.
런타임 시 이것이 문제임을 나타내려면 예외를 발생시켜 API 사용자가 강제로 이를 무시하도록 할 수 있습니다.그러나 적어도 내가 아는 한 컴파일 타임에는 불가능합니다.
API별 메서드를 사용하여 문제를 해결해 보세요.CommandEquals.다른 옵션은 (언급한 대로) Equals 추상 메서드를 정의하는 다른 클래스를 확장하는 것입니다.
당신은 만들 수 있습니다 boolean myEquals()
안에 interface Command
, 다음과 같이 어댑터를 만듭니다.
class MyAdapter{
Command c;
boolean equals(Object x) {
return c.myEquals((Command)x);
}
}
그럼 당신은 그냥 사용합니다 map.put(key, new MyAdapter(command))
대신에 map.put(key, command)
런타임 확인을 원한다면 다음과 같은 작업을 수행 할 수 있습니다.
interface Foo{
}
class A implements Foo {
}
class B implements Foo {
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
public static void main(String[] args) {
Class<A> clazzA = A.class;
Class<B> clazzB = B.class;
Class<Object> objectClass = Object.class;
try {
Method methodFromObject = objectClass.getMethod("equals",Object.class);
Method methodFromA = clazzA.getMethod("equals",Object.class);
Method methodFromB = clazzB.getMethod("equals",Object.class);
System.out.println("Object == A" + methodFromObject.equals(methodFromA));
System.out.println("Object == B" + methodFromObject.equals(methodFromB));
} catch (SecurityException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
첫 번째는 True를 인쇄하고 두 번째는 False를 인쇄합니다. 컴파일 시간을 원한다면 시간이 유일한 옵션은 주석을 만들고 주석 처리 도구를 사용하여 모든 주석이 붙은 클래스가 동등한 지 확인하는 것입니다.
interface A{
public boolean equal2(Object obj);
}
abstract class B implements A {
@Override
public boolean equals(Object obj) {
return equal2(obj);
}
}
class C extends B {
public boolean equal2(Object obj) {
throw new UnsupportedOperationException("Not supported yet.");
}
}
부터 equals()
상속됩니다 Object
나는 당신이 정말로 그것을 강요 할 수 없다는 것을 의심합니다. 모든 타입 자동 상속 구현이 있습니다 equals()
사용 가능.
나는 객체 클래스에서 나오는 것처럼 평등을 강요하는 것이 불가능하다고 생각하지 않습니다.
관련 메모에서, 당신은 equals를 재정의 할 때 객체 클래스에서 '해시 코드'메소드를 무시해야한다는 점에 유의하십시오. 클래스의 인스턴스를지도의 열쇠로 사용하려면 이는 매우 중요해집니다. 이 기사를 확인하십시오 :http://www.artima.com/lejava/articles/equality.html올바른 방식으로 동등한 방법에 대한 힌트를 제공합니다.
다른 답변에서 이미 설명했듯이, 당신이 시도하는 것을 강요할 수는 없습니다.
'충분히' 작동할 수 있는 한 가지 방법은 두 번째 인터페이스를 정의하는 것입니다. 이를 MappableCommand라고 합니다.
public interface MappableCommand
{
}
이 인터페이스에 대한 문서에서는 클래스 디자이너가 귀하가 명시한 요구 사항을 고려한 경우에만 클래스가 이(빈) 인터페이스를 구현해야 한다고 명시합니다.
그런 다음 지도의 값 유형을 MappableCommand로 설정하면 MappableCommand만 지도에 추가할 수 있습니다.
이는 Java의 기본 직렬화 메커니즘에 의해 직렬화될 수 있는 클래스에 대해 (빈) 직렬화 가능 인터페이스를 구현해야 하는 이유 뒤에 있는 논리와 유사합니다.
이것이 작동하지 않으면 런타임 오류가 발생하는 것에 만족해야 할 수도 있습니다.
가짜 편집:
이 요구 사항을 더 명확하게 만들고 싶다면 다음과 같이 새 인터페이스를 정의할 수 있습니다.
public interface MappableCommand
{
public void iOverrodeTheEqualsMethod();
public void seriouslyIPromiseThatIOverrodeIt();
}
다음은 다른 제안 된 솔루션의 변형입니다.
public abstract class CommandOverridingEquals implements Command {
public abstract boolean equals(Object other);
public abstract int hashcode();
}
Map<String, CommandOverridingEquals> map =
new HashMap<String, CommandOverridingEquals>();
또는 실제로 확실히 원한다면 확인 된 해시 맵을 사용하십시오. 예를 들어
Map<String, CommandOverridingEquals> map = Collections.checkedMap(
new HashMap<String, Command>(),
String.class, CommandOverridingEquals.class);
그러나 당신이 무엇을하든 당신은 이것을하는 사람을 막을 수 없습니다.
public class AntiFascistCommand extends CommandOverridingEquals {
public boolean equals(Object other) { return super.equals(other); }
public int hashcode() { return super.hashcode(); }
...
}
나는 이런 종류의 일이 트랙에서 문제를 일으킬 것이라고 생각하는 경향이 있습니다. 예를 들어, 다른 기본 클래스를 확장하고 (우연히) 재정의하는 기존 명령 클래스가 있다고 가정합니다. equals
그리고 hashcode
규정 된 방식으로. 문제는 그 수업을 사용할 수 없다는 것입니다. 대신, 나는 그들을 상환하거나 많은 포장지를 써야합니다.
IMO, 개발자를 특정 구현 패턴으로 강제하려고 시도하는 것은 나쁜 생각입니다. Javadocs에 강한 경고를하고 개발자에게 의지하는 것이 더 낫습니다. 옳은 일을하십시오.
자신의 것을 제공 할 수 있습니까? java.util.comparator
문제의지도에?