Eu estava aprendendo que a interface Marker em Java é uma interface vazia e é usada para sinalizar ao compilador ou JVM que os objetos da classe que implementam essa interface devem ser tratados de uma maneira especial, como serialização, clonagem etc.
Mas ultimamente eu aprendi que ele realmente não tem nada a ver com o compilador ou a JVM. Por exemplo, no caso Serializable
da interface do método writeObject(Object)
de ObjectOutputStream
faz algo parecido instanceOf Serializable
para detectar se os implementos classe Serializable
e mantas NotSerializableException
em conformidade. Tudo é tratado no código e isso parece ser um padrão de design, então acho que podemos definir nossas próprias interfaces de marcador.
Agora minhas dúvidas:
A definição de uma interface de marcador mencionada acima no 1º ponto está errada? Como podemos definir uma interface de marcador então?
E, em vez de usar o
instanceOf
operador, por que o método não pode ser algo parecidowriteObject(Serializable)
para que haja uma verificação do tipo em tempo de compilação em vez do tempo de execução?Como as anotações são melhores que as interfaces de marcador?
fonte
Serializable
como uma anotação não faz sentido e@NonNull
como uma interface não faz sentido. Eu diria: Anotações são marcadores + metadados. BTW: O Forefunner of Annotations foi o XDoclet, nascido em Javadoc, morto por Annotations.Respostas:
writeObject(Serializable)
com o de uma verificação do tipo em tempo de compilação - Isso evita poluir seu código com o nome da interface do marcador quando um "simplesObject
" é necessário. Por exemplo, se você criar uma classe que precise ser serializável e tenha membros de objeto, você será forçado a converter ou criar seus objetosSerializable
em tempo de compilação. Isso é inconveniente, porque a interface é desprovida de qualquer funcionalidade.fonte
writeObject
é privado, o que significa que, por exemplo, uma classe não tem que chamar a superclasse implementaçãoCloneable
não estar claro se é um tratamento de biblioteca ou JVM da instância que foi alterado.Não é possível executar
Serializable
emwriteObject
porque as crianças de classe não-serializável pode ser serializado, mas suas instâncias pode estar de volta upcasted para a classe pai. Como resultado, manter uma referência a algo não serializável (comoObject
) não significa que a instância referida não possa ser realmente serializada. Por exemplo, ema classe pai (
Object
) não é serializável e seria inicializada usando seu construtor sem parâmetros. O valor referenciado porx
,String
, é serializável ea instrução condicional seria executado.fonte
O item acima começou como uma cópia de uma postagem no blog, mas foi ligeiramente editado para gramática.
fonte
Fiz uma demonstração simples para resolver a dúvida nº 1 e 2:
Teremos uma interface móvel que será implementada pela
MobilePhone.java
classe e mais uma classeLandlinePhone.java
que não implementa a interface móvelNosso marcador Interface:
LandLinePhone.java
eMobilePhone.java
Nossa classe de exceção personalizada: package com;
Nossa classe de teste:
TestMArkerInterface.java
Agora, quando executamos a classe principal:
Portanto, qualquer classe que implemente a interface do marcador
Movable
passará no teste, caso contrário a mensagem de erro será exibida.É assim
instanceOf
que a verificação do operador é feita para Serializable , Cloneable etc.fonte
a / A interface de marcador, como o próprio nome sugere, existe apenas para notificar qualquer coisa que saiba sobre ela que uma classe declara algo. Qualquer coisa pode ser as classes JDK para a
Serializable
interface ou qualquer classe que você escreve para uma customizada.b / Se for uma interface de marcador, não deve implicar a existência de nenhum método - seria melhor incluir o método implícito na interface. Mas você pode decidir projetá-lo como quiser, se souber por que precisa
c / Há pouca diferença entre uma interface vazia e uma anotação que não usa valor ou parâmetro. Mas a diferença está aí: uma anotação pode declarar uma lista de chaves / valores que estarão acessíveis em tempo de execução.
fonte
uma. Eu sempre os vi como um padrão de design e nada de especial da JVM. Usei esse padrão em várias situações.
c. Eu acredito que usar anotações para marcar algo é uma solução melhor do que usar interfaces de marcador. Simplesmente porque as interfaces são, em primeiro lugar, destinadas a definir interfaces comuns de tipos / classes. Eles fazem parte da hierarquia de classes.
As anotações têm como objetivo fornecer meta-informações ao código, e acho que os marcadores são meta-informações. Portanto, eles são exatamente para esse caso de uso.
fonte
Não tem nada a ver (necessariamente) com a JVM e os compiladores, tem algo a ver com qualquer código que esteja interessado e que esteja testando para uma determinada interface de marcador.
É uma decisão de design e é feita por uma boa razão. Veja a resposta de Audrius Meškauskas.
Com relação a esse tópico em particular, não acho que seja uma questão de ser melhor ou pior. A interface do marcador está fazendo o que deveria fazer muito bem.
fonte
O principal objetivo das interfaces de marcador é criar tipos especiais em que os próprios tipos não têm comportamento próprio.
Aqui, o método save garante que apenas os objetos das classes que implementam a interface MarkerEntity sejam salvos, para outros tipos InvalidEntityFoundException. Portanto, aqui a interface do marcador MarkerEntity está definindo um tipo que adiciona comportamento especial às classes que o implementam.
Embora as anotações também possam ser usadas agora para marcar classes para alguns tratamentos especiais, as anotações de marcador substituem o padrão de nomenclatura e não as interfaces do Marcador.
Mas as anotações de marcador não podem substituir completamente as interfaces de marcador porque; interfaces de marcador são usadas para definir o tipo (como já explicado acima), onde as anotações de marcador não.
Origem do comentário da interface do marcador
fonte
Eu diria primeiro que Serializable e Cloneable são maus exemplos de interfaces de marcador. Claro, eles são interfaces com métodos, mas implicam métodos, como
writeObject(ObjectOutputStream)
. (O compilador criará umwriteObject(ObjectOutputStream)
método para você, se você não o substituir, e todos os objetos já o tiveremclone()
, mas o compilador criará novamente umclone()
método real para você, mas com ressalvas. Ambos são casos extremos estranhos que realmente não são bons exemplos de design.)As interfaces de marcadores são geralmente usadas para uma de duas finalidades:
1) Como um atalho para evitar um tipo excessivamente longo, o que pode acontecer com muitos genéricos. Por exemplo, digamos que você tenha esta assinatura de método:
Isso é confuso e chato de digitar e, mais importante, difícil de entender. Considere isso:
Então, seu método fica assim:
Não é apenas mais claro, mas agora você pode Javadoc na interface do Widget, e também é mais fácil procurar todas as ocorrências no seu código do Widget.
2) As interfaces de marcadores também podem ser usadas como uma maneira de contornar a falta de tipos de interseção do Java. Com uma interface de marcador, você pode exigir que algo seja de dois tipos diferentes, como em uma assinatura de método. Digamos que você tenha algum widget de interface em seu aplicativo, como descrito acima. Se você possui um método que requer um Widget que também permite iterar sobre ele (é artificial, mas trabalhe comigo aqui), sua única boa solução é criar uma interface de marcador que estenda as duas interfaces:
E no seu código:
fonte
Serializable
ouCloneable
. Você pode verificá-lo inspecionando seus arquivos de turma. Além disso, a criação de “interfaces de atalho” não é o objetivo das interfaces de marcador. E é uma prática muito ruim de codificação, pois exigiria a criação de classes de implementação adicionais para atender às interfaces adicionais. A propósito, Java tem tipos de interseção há uma década. Aprenda sobre genéricos ...Se uma interface não contém nenhum método e, ao implementá-la, se nosso objeto tiver alguma habilidade, esse tipo de interface é chamado de interface de marcador.
fonte