Sobreescrever(Override) métodos de uma instancia ja existente

12 respostas
mateusviccari

Bom dia, gostaria de saber se no java é possivel sobreescrever metodos de iinstancias de objetos ja existentes.
Por exemplo, na hora da criação de um produto eu posso alterar o método toString:

Produto prod = new Produto(){
            @Override
            public String toString() {
                return getProda60descr()+" xxx";
            }
        };

Porém vamos supor que eu tivesse um produto ja existente, recuperado do banco de dados usando o hibernate:

Produto p = session.get(Produto.class, 14);

Como poderia alterar o toString desse produto?

12 Respostas

Filipe_A

Olá Mateus! Acho que não é possível, porém, veio uma idéia meio doida na minha cabeça… Se você fizer a classe Produto receber um Produto em seu construtor talvez de certo… entende? Caso não funcione favor desconsiderar completamente o que disse (não cheguei a testar) :roll:

Filipe_A

Veja:

public class Produto {
	
	private Produto produto;
	
	
	public Produto() {
		// TODO Auto-generated constructor stub
	}
	
	public Produto(Produto produto) {
		// TODO Auto-generated constructor stub
		this.produto = produto;
	}
	
	public Produto getProduto(){
		return produto;
	}


}
public class Main {

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		
		Produto p = new Produto();
		
		Produto produto = new Produto(p){
			@Override
			public String toString(){
				return "Olá";
			}
		};
		
		System.out.println(produto);
		System.out.println(produto.getProduto());

	}

}

:lol:

Isto que quis dizer, acho que é inviável…

igor_ks

Pq vc nao cria um construtor com uma passagem de parametro do valor do retorno do toString(), ai no toString() vc retorna esse atributo passado por parametro no construtor

edit:

Exemplo:

public class Produto {

    private String retornoString;

    public Produto(String retornoString) {
        this.retornoString = retornoString;
    }

    public String toString() {   
        return getProda60descr()+ retornoString;   
    }   

}

//na chamada
   Produto p = new Produto("Olá");
   System.out.println(p);
Filipe_A
igor_ks:
Pq vc nao cria um construtor com uma passagem de parametro do valor do retorno do toString(), ai no toString() vc retorna esse atributo passado por parametro no construtor

edit:

Exemplo:

public class Produto {

    private String retornoString;

    public Produto(String retornoString) {
        this.retornoString = retornoString;
    }

    public String toString() {   
        return getProda60descr()+ retornoString;   
    }   

}

//na chamada
   Produto p = new Produto("Olá");
   System.out.println(p);

Bem melhor! :wink:

Se bem que como ele não poderá instanciar um novo objeto, acho que teria que ser por algum metódo setXXX ao invés do contrutor :?:

ribclauport

Veja que você não está alterando o método toString na criação de um produto! Você está criando uma classe anônima, e sobrescrevendo o método, se você quer esse tipo de comportamento deve pesquisar sobre “Instrumentação”.

E

Um exemplo de coisa que as pessoas perguntam muito é como mudar o comportamento de um objeto já existente. Normalmente você delega esse comportamento a outras classes, que são associadas (via operação TEM UM , não É UM) ao objeto em questão.

Vamos dar um exemplo: digamos que você tenha criado um jogo em que um personagem começa como bebê, depois passa a aprendiz, depois a soldado, então a guerreiro ou mago, e assim por diante.

A primeira idéia é que o objeto seja criado com uma classe que não tem habilidade nenhuma, e você vá adaptando o comportamento desse objeto à medida que ele for promovido (ou seja, ganhando novas habilidades.

Como você não pode mudar a classe de objeto em tempo de execução, uma maneira de você fazer isso é definir habilidades, e ir associando as habilidades à medida que o objeto (o personagem) for sendo promovido. Então, em vez de você dizer que “Objeto Gandalf faz mágica”, você diz que “Objeto Gandalf tem a habilidade de fazer mágica”, e chama o método “fazer mágica” da habilidade “Ser mágico”.

sergiotaborda

mateusviccari:
Bom dia, gostaria de saber se no java é possivel sobreescrever metodos de iinstancias de objetos ja existentes.
Por exemplo, na hora da criação de um produto eu posso alterar o método toString:

Produto prod = new Produto(){
            @Override
            public String toString() {
                return getProda60descr()+" xxx";
            }
        };

Porém vamos supor que eu tivesse um produto ja existente, recuperado do banco de dados usando o hibernate:

Produto p = session.get(Produto.class, 14);

Como poderia alterar o toString desse produto?

A solução é parecida com o que o Felipe disse. Vc precisa usar o padrão Decorator.
O padrão Decorator significa criar outra classe que herda de produto e contém um produto. Ai tem o método toString modificado. Todos os metodos delegam a sua chamada para os mesmos metodos no objeto original.

Vc pode criar um Decorador dinamincamente se usar bibliotecas de bytecode rewirte como a cglib que usa no binernate.

Tudo isto é possivel, mas é altamente não acontecelhado. Ainda por cima para mudar o toString que nem sequer é um metodo de negocio.
O que vc quer fazer denota que alguma coisa no seu modelo está errada. Pense em outra solução e nos diga exatamente que problema vc está tentando resolver.

ribclauport

Com o auxílio de Javassist por exemplo é possível manipular os bytecodes, veja o exemplo:

package teste;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.NotFoundException;

public class JavaSist {
	public static void main(String[] args) throws NotFoundException, CannotCompileException, IOException, SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
		metodo();
	}
	
	
	public static void metodo() throws NotFoundException, CannotCompileException, IOException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
		ClassPool pool = ClassPool.getDefault();
		CtClass cc = pool.get("teste.Rectangle");
		cc.setSuperclass(pool.get("teste.Point"));
		cc.writeFile();
		Class clazz = cc.toClass();
		System.out.println(new teste.Rectangle().getClass().getSuperclass());
	}

}

No codigo acima foi alterada a superclasse de Rectangle, lógico que talvez não se aplique a um proposito simples como o apresentado, mais é uma alternativa se não for possível alterar o codigo fonte para adicionar comportamentos…

mateusviccari

Primeiramente obrigado a todos que responderam… aprendi algumas coisas que nao sabia nem que era possível fazer…
O meu objetivo pra isso é meramente informativo, na verdade a duvida surgiu quando tive que criar um combobox que iria guardar varios produtos, sendo que nesse combobox não deveria ser mostrado o toString padrão do produto que retornava somente seu nome, e sim que mostrasse o nome e também a unidade de medida.

Estava pensando em fazer algo usando interfaces, funcionou e não precisei implementar quase nada, creio que pro meu caso seria o melhor jeito, algo assim:
Classe produto:

package testes;

public class Produto {
    private String nome;
    private StringReturn stringReturn;

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public StringReturn getStringReturn() {
        return stringReturn;
    }

    public void setStringReturn(StringReturn stringReturn) {
        this.stringReturn = stringReturn;
    }

    @Override
    public String toString() {
        if(stringReturn==null){//retorno padrão, caso nao exista um stringReturn especifico
            return nome;
        }else{//retorna o método da interface
            return stringReturn.getString();
        }
    }
}

Interface usada pra retornar uma string

package testes;

public interface StringReturn {
    public String getString();
}

Um exemplo de utilização:

Produto p1 = new Produto();
        p1.setNome("Abacaxi explosivo");
        System.out.println(p1);
        
        final Produto p2 = new Produto();
        p2.setStringReturn(new StringReturn() {
            @Override
            public String getString() {
                return "Esse eh o retorno personalizado do produto "+p2.getNome();
            }
        });
        p2.setNome("Laranja mecânica");
        System.out.println(p2);
        p2.setNome("Laranja elétrica");
        System.out.println(p2);

Poderia tambem ao invés de usar interface, usar classe abstrata e fazer o método construtor dela receber um objeto, ai não precisaria declarar as variaveis como final.

ribclauport

Só por curiosidade, qual framework está sendo usado para view?

mateusviccari

Não é framework não, é swing mesmo(java desktop)…

sergiotaborda

mateusviccari:
Primeiramente obrigado a todos que responderam… aprendi algumas coisas que nao sabia nem que era possível fazer…
O meu objetivo pra isso é meramente informativo, na verdade a duvida surgiu quando tive que criar um combobox que iria guardar vários produtos, sendo que nesse combobox não deveria ser mostrado o toString padrão do produto que retornava somente seu nome, e sim que mostrasse o nome e também a unidade de medida.

Eu já desconfiava. Este é um problema comum. Apresentar coisas na tela , sobretudo em combos. No swing vc tem o Model para ajudar a fazer isso do jeito certo e ai vc não precisa ficar modificando suas classes (http://docs.oracle.com/javase/7/docs/api/javax/swing/ComboBoxModel.html).

Mas tudo se resume ao padrão Decorator que falei antes. Esse é o jeito padrão e esperado por outros programadores.
Um outro conceito que é util , sobretudo em swing é o conceito de View Object. O View Object é um objeto que só a view usa. É o objeto que vc manda para o swing. Este objeto não é o mesmo que vem do banco. Normalmente ele tem mais ou menos propriedades que o do banco. E é muito util para juntar inforações que no banco estão em lugares diferentes. É um padrão util em web também.

Eis como seria um View Object padrão para usar em combos

public class ComboItem {

        private String text;
        private Object id;

        public ComboItem (Object id , String text) {
         this.id = id;
         this.text = text;
       }
 
         // gets e sets
}


// uso 

List<Produto> produtos = ... 
List<ComboItem> listaParaCombo = new ArrayList<ComboItem>(produtos.size());
for (Produto p : produtos ){
        listaParaCombo.add( new ComboItem(produto.getId(), produto.getNome() + "  (" + produto.getUnidade() + ")");
}

//agora  é só usar o listaParaCombo no combo. Prefrivelmente em uma implementação de ComboModel.

Este tipo de padrão ajuda a deixar o codigo da view a ficar desacoplado do codigo do resto do sistema e as entidades não precisa se preocupar em como são ser mostradas na tela. Isso não é responsabilidade delas.

Criado 3 de janeiro de 2013
Ultima resposta 4 de jan. de 2013
Respostas 12
Participantes 6