Pergunta

Eu tenho um monte de classe que implementam uma interface comum: Command.

E esse bando de classe vai para um mapa.

Para obter o Mapa funcionando corretamente, eu preciso a cada classe que implementa comandos para substituir o método Object.equals(Object other).

É bom.

Mas eu whould gostaria de forçar o substituindo de iguais. => Tenha um erro de compilação quando algo que implementar comando não faça override é igual.

É possível?

Editar: BTW, eu também precisará forçar a substituição de hashcode ...

Foi útil?

Solução

Não, você não pode. O que você pode fazer, no entanto, é usar uma classe base abstrata, em vez de uma interface, e fazer equals() resumo:

abstract class Command {
   // put other methods from Command interface here

   public abstract boolean equals(Object other);
   public abstract int hashCode();
}

As subclasses de Command deve , em seguida, fornecer os seus próprios métodos equals e hashCode.

Em geral, é má prática para usuários vigor API para estender uma classe base, mas pode ser justificada neste caso. Além disso, se você fizer Command uma classe base abstrata, em vez de uma interface, em vez de introduzir uma classe base artificial em além para a interface de comando, então não há risco dos usuários da API começá-lo errado.

Outras dicas

Você pode estender seus objetos a partir de um XObject abstrato ao invés de java.lang.Object?

public abstract class XObject
 extends Object
{
@Override
public abstract boolean equals(Object o);
}

Classes abstratas não vai funcionar se você tem um neto desde o seu pai já overrided ambos os métodos equals e hashCode e então você tem o seu problema mais uma vez.

Tente usar annotatins e APT ( http: // docs.oracle.com/javase/1.5.0/docs/guide/apt/GettingStarted.html ) para fazê-lo.

Isso só seria possível se o comando foi uma interface ou uma classe abstrata, onde iguais (..) é um método declarado como abstrato.

O problema é que Object, que é a superclasse de todos os objetos, já define este método.

Se você quiser indicar que este é um problema (em tempo de execução), você pode lançar uma exceção, para forçar os usuários de sua API para substituí-lo. Mas não é possível em tempo de compilação, pelo menos ao meu conhecimento.

Tente trabalhar em torno dele, por ter um método específico da API, por exemplo, CommandEquals. A outra opção é (como mencionado) estender outra classe que define um iguala o método abstrato.

Você pode criar boolean myEquals() em interface Command, e criar Adapter assim:

class MyAdapter{
  Command c;
  boolean equals(Object x) {
    return c.myEquals((Command)x);
  }
}

Então você só usar map.put(key, new MyAdapter(command)) vez de map.put(key, command)

Bem, se você quer uma verificação de tempo de execução que você pode fazer algo como:

    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();
    }
}

Será imprimir verdadeiro para o primeiro e falso para o segundo. Se você quer compilar aparência de tempo como a única opção é criar uma ferramenta de anotação e processamento de anotação usar para verificar que todas as classes anotadas sobrepõe iguais.

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.");
    }
}

Desde equals() é herdada de Object eu duvido que você realmente não pode forçar que, uma vez que para todas tipo não é uma implementação automática herdou de equals() disponível.

Eu não acho que é possível para forçar substituindo de iguais, uma vez que vem da classe Object.

Em uma nota relacionada, nota que você precisa substituir o método 'hashCode' da classe Object sempre que você substituir iguais. Isto torna-se espeically importante se você estiver indo para usar instâncias de suas classes como chaves de um mapa. Confira este artigo: http://www.artima.com/lejava/articles/equality.html que fornece algumas dicas sobre como substituir iguais de forma correta

Como as outras respostas já expliquei, não, você não pode forçar o tipo de coisa que você está tentando.

Uma coisa que pode funcionar 'o suficiente' é definir uma segunda interface, chamar este MappableCommand.

public interface MappableCommand 
{

}

Na sua documentação para esta interface indicam que uma classe só deve implementar essa interface (Vazio) se o designer de classe considerou os requisitos que você indicou.

Em seguida, você pode definir o tipo de valor de seu mapa para MappableCommand, e apenas MappableCommands poderão ser adicionadas ao mapa.

Este é semelhante à lógica por trás porque um precisa para implementar a (em branco) interface Serializable para as classes que podem ser serializados por mecanismos de serialização padrão do Java.

Se isto não funcionar, então você pode ter que se contentar com jogando um erro de tempo de execução;

Falso Edit:

Se você quiser fazer este requisito mais óbvio que você poderia definir a nova interface desta forma

public interface MappableCommand 
{

    public void iOverrodeTheEqualsMethod();

    public void seriouslyIPromiseThatIOverrodeIt();

}

Aqui está uma variação de algumas das outras soluções propostas:

public abstract class CommandOverridingEquals implements Command {
    public abstract boolean equals(Object other);
    public abstract int hashcode();
}

Map<String, CommandOverridingEquals> map = 
    new HashMap<String, CommandOverridingEquals>();

Ou se você realmente quer ter certeza, use uma hashmap verificada; por exemplo.

Map<String, CommandOverridingEquals> map = Collections.checkedMap(
    new HashMap<String, Command>(),
    String.class, CommandOverridingEquals.class);

Mas não importa o que você faz Você não pode parar alguém fazer isso:

public class AntiFascistCommand extends CommandOverridingEquals {
    public boolean equals(Object other) { return super.equals(other); }
    public int hashcode() { return super.hashcode(); }
    ...
}

I tendem a pensar que esse tipo de coisa vai causar problemas na pista. Por exemplo, suponha que eu tenho um monte de aulas de comando existentes que se estendem alguma outra classe base, e (aliás) override equals e hashcode na forma prescrita. O problema é que eu não posso usar essas classes. Em vez disso, eu sou forçado a reimplementar-los ou escrever um monte de wrappers.

IMO, é uma má idéia para tentar forçar o desenvolvedor em um padrão de execução particular. Seria melhor colocar algumas advertências fortes no Javadocs e contar com os desenvolvedores para fazer a coisa certa .

É possível que você forneça seu próprio java.util.comparator ao mapa em questão?

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top