Fundição "dinâmica" em java
-
03-07-2019 - |
Pergunta
Hullo All,
Quer saber se há algum hackers Java que possa me indicar por que o seguinte não funciona:
public class Parent {
public Parent copy() {
Parent aCopy = new Parent();
...
return aCopy;
}
}
public class ChildN extends Parent {
...
}
public class Driver {
public static void main(String[] args) {
ChildN orig = new ChildN();
...
ChildN copy = orig.getClass().cast(orig.copy());
}
}
O código está muito feliz em compilar, mas decide lançar uma classe ClassCexception no tempo de execução d =
Editar: Whoah, respostas muito rápidas. Obrigado rapazes! Então, parece que não posso abaixar o uso desse método ... Existe outra maneira de fazer abatida no Java? Eu pensei em ter cada um ChildN
Substituição de classe copy()
, mas não estava entusiasmado em adicionar o código de caldeira extra.
Solução
(Não é possível adicionar código em um comentário, então adicionarei aqui)
Em relação ao clonável: se você estiver implementando clonável, implemente -o da seguinte forma; Muito mais limpo para ligar ...
public class Foo implements Cloneable {
public Foo clone() {
try {
return (Foo) super.clone();
} catch (CloneNotSupportedException e) {
return null; // can never happen!
}
}
Editar: eu também vi outras pessoas usarem
throw new AssertionError("This should never happen! I'm Cloneable!");
no bloco de captura.
Outras dicas
É como tentar fazer isso:
public Object copy(){
return new Object();
}
E então tente::
String s = ( String ) copy();
Sua Pai classe e Childn classe tem o mesmo relacionamento que Objeto e Corda
Para fazer funcionar, você precisaria fazer o seguinte:
public class ChildN extends Parent {
public Parent copy() {
return new ChildN();
}
}
Isto é, substitua o método "cópia" e retorne a instância correta.
EDITAR
De acordo com sua edição. Isso é realmente possível. Esta pode ser uma maneira possível:
public class Parent {
public Parent copy() {
Parent copy = this.getClass().newInstance();
//...
return copy;
}
}
Dessa forma, você não precisa substituir o método "cópia" em cada subclasse. Este é o padrão de design do protótipo.
No entanto, usando esta implementação, você deve estar ciente de duas exceções verificadas. Aqui está o programa completo que compila e funciona sem problemas.
public class Parent {
public Parent copy() throws InstantiationException, IllegalAccessException {
Parent copy = this.getClass().newInstance();
//...
return copy;
}
}
class ChildN extends Parent {}
class Driver {
public static void main(String[] args) throws InstantiationException , IllegalAccessException {
ChildN orig = new ChildN();
ChildN copy = orig.getClass().cast(orig.copy());
System.out.println( "Greetings from : " + copy );
}
}
O elenco está tentando efetivamente fazer isso:
ChildN copy = (ChildN) orig.copy();
(Está resolvendo o elenco para se apresentar no momento da execução, mas é isso que será porque orig.getClass()
vai ser ChildN.class
) No entanto, orig.copy()
não retorna uma instância do Childn, ele retorna uma instância de apenas Parent
, então não pode ser lançado para ChildN
.
Se Childn não substituir a copy () para retornar uma instância do Childn, você está tentando abaixar um objeto do tipo pai para digitar Childn
java.lang.class#elenco (objeto) lança uma classe de classe se a classe#isinstance () retornar falsa. Do javadoc para esse método:
Determina se o objeto especificado é compatível com a atribuição com o objeto representado por esta classe. Este método é o equivalente dinâmico da instância da linguagem java do operador ... especificamente, se isso
Class
Objeto representa uma classe declarada, esse método retornatrue
se o especificadoObject
O argumento é uma instância da classe representada (ou de qualquer uma de suas subclasses); ele retornafalse
por outro lado.
Como o pai não é uma subclasse do filho, o isinstance () retorna false, então o elenco () lança a exceção. Isso pode violar o princípio de menos espanto, mas está funcionando da maneira que está documentada - o elenco () só pode ser aprimorado, não abatido.
Pode ser que você simplesmente quer uma cópia/clone de seu objeto.
Nesse caso, implementar a interface Cloneable e substituir o clone (), se necessário.
public class Parent implement Cloneable {
public Object clone() throws CloneNotSupportedException {
Parent aCopy = (Parent) super.clone();
...
return aCopy;
}
}
public class ChildN extends Parent {
...
}
public class Driver {
public static void main(String[] args) {
ChildN orig = new ChildN();
...
ChildN copy = orig.getClass().cast(orig.clone());
}
}
Isso faz exatamente o que o seu "(cópia)" método tentei fazer em Java.
(Sim, você poderia fazer a fantasia de introspecção jogos também, mas esses métodos falham ou tornar-se feio assim que você não tem um público padrão-construtor.Clone funciona em qualquer caso, não importa o que os construtores que você tem.)
A razão downcasting não funciona é porque, ao lançar um objeto pai para uma criança escreva, não há nenhuma maneira que você pode chamar de criança tipo de métodos no objeto pai.Mas ele funciona de outra maneira...