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

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?

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:

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…

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

[quote=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:

[code]
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§;
[/code][/quote]

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 :?:

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”.

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”.

[quote=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?[/quote]

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.

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…

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.

1 curtida

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

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

[quote=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.
[/quote]

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.