Como acessar os membros de um objeto que esta servindo de chave em um HashMap

19 respostas Resolvido
N

Ola, ótimo dia a todos

Eu tenho uma classe Produto com alguns membros, outra ProdutoComTamanho estendendo Produto, um CarrinhoDeCompras e uma Classe Principal
Dentro de CarrinhoDeCompras, em um HashMap<Produto, Integer> cujo nome é controle, eu adiciono Produtos como Chave e a quantidade como valores
Na classe Principal criei vários Produtos e posso acessá-los normalmente porém quando tento acessá-los via o objeto controle (HashMap) ocorre um erro de NulllPointer
Mais ou menos assim:

Na classe CarrinhoDeCompras eu tenho:

public HashMap<Produto, Integer> controle = new HashMap<>();

Na classe Principal eu tenho:

CarrinhoDeCompras carlos = new CarrinhoDeCompras();

Produto p1 = new Produto("cha", 123, 2.45);

//Em testes eu posso acessar os membros de p1 normalmente

carlos.adicionaProduto(p1, 2);

Como acessar os membros de Produtos ( p1 ) através de carlos.controle… onde controle é um HashMap com p1 com chave e uma quantidade qualquer…

19 Respostas

M

Posta o código para ver melhor.

Mas para aceesar os valores de um HashMap é só dar um get e passar a chave.

Ex:
controle.get(p1); // Isso retorna o objeto 2.
controle.get(p1).getNome; // Supondo que este 2 seja um produto você pode acessa-lo diretamente.

P
Solucao aceita

Ola

Este é um problema bem interessante. vc usa o produto como chave para evitar duplicação, certo?

antes de mais nada, vc quer fazer isso onde? no java (servlet) ou no jsp usando expression language / jstl / etc?

faz diferença pq vc precisa usar o metodo keySet pra listar todos os produtos e ai acessar o carrinho um por um.

Para vc poder usar um objeto como chave de um Map vc precisa sobreescrever os metodos equals e hashCode

Eu evitaria isso com uma outra abstração: ItemNoCarrinho que vai armazenar o produto e um inteiro com a quantidade.

seu carrinho pode então ter uma coleção de items onde vc pode escolher:

  1. um Map identificador do produto => item ( supondo que o produto tem um id vindo de um banco de dados por exemplo )
  2. um Set pra garantir uma lista não repetida onde vc armazena items ( sobre-escreve o equals para delegar p/ equals do produto - acho complexo isso )
  3. um simples List ( provavelmente vc precisa pegar pela posição e não por identificador / string / produto ) e antes de adicionar vc pesquisa se ja existe aquele produto
M

Concordo totalmente com o @peczenyj .
Porém não comentei nada sobre isso porque queria ver o código primeiro e também para não confundir o autor da pergunta.

Ao meu ver o mais simples e correto seria utilizar o id do produto como key. Uma vez que este id nunca irá repetir e você terá facilidade de identificar o produto durante os teste.

P

eu achei este carrinho algo sui generis porem VAI QUE da certo

N

Legal, Funcionou. Eu fiz:

Set ok = teste.getControle().keySet();

e pude acessar os dados via:

System.out.println(ok.toArray()[1]);
System.out.println(((Produto)ok.toArray()[1]).getCodigo());

Fiz o mais simples possível

Exigência do exercício

Me perdoe a ignorância, mas oque é “sui generis”

N

Oi, apesar de resolvida a questão, ei os códigos:

ArquivosJava.zip (2,1 KB)

Gostaria de saber sua opnião…

Obrigado

N

Valeu, mas o exercício pede que o objeto Produto/ProdutoComTamanho sejam a chave

N

Para quem se interessar, estas são as instruções do exercício:

Crie uma classe chamada Produto que deve possuir um nome, um código e um preço. Sobrescreva os métodos equals() e hashCode() de Object de forma a serem considerados iguais instancias de Produto que possuam o mesmo código.
Crie uma classe chamada ProdutoComTamanho que estenda a classe Produto. Essa classe deve possuir uma informação adicional de tamanho. Um exemplo seria o tamanho de uma roupa ou a numeração de um calçado. Método equals() e hashCode() devem ser sobrescritos de forma que um produto com mesmo código e tamanhos diferentes são considerados diferentes.
Crie uma classe CarrinhoDeCompras que armazene em um atributo interno do tipo HashMap cada produto adicionado no carrinho e sua respectiva quantidade. O método adicionaProduto() deve receber a instancia do produto e a quantidade. Caso o produto já exista no HashMap, a quantidade deve ser somada a que já existe no carrinho. Deve haver também um método removeProduto() que também recebe a instancia do produto e a quantidade a ser removida. Observe que produtos de tamanhos diferentes devem ser considerados como produtos diferentes no carrinho. O carrinho deve possuir um método que calcula o valor total da compra.
Crie testes com Unit para a classe Produto, para a classe ProdutoComTamanho e para a classe CarrinhoDeCompras. Os testes de cada classe devem ser colocados em classes separadas e devem estar em um diretório de código diferente das classes de produção.

P

O problema é o estado do Produto usado pra calcular o hashCode mudar enquanto o objeto está sendo usado como chave.

Mas vc pode criar o Produto imutável (ou garantir que o estado mutável não seja usado pra calcular o hashCode).

N

Ola, bom dia

Como eu faria isto?

Na classe produto implementei o equals e hashcode da seguinte forma:

`@Override
public int hashCode() {
	return this.codigo;
}

@Override
public boolean equals(Object obj) {
	if(this.codigo == obj.hashCode())
		return true;
	return false;
}`

e na ProdutoComTamanho:

`@Override
public int hashCode() {
	return super.getCodigo();
}

@Override
public boolean equals(Object obj) {
	if(super.getCodigo() == obj.hashCode() && this.tamanho == ((ProdutoComTamanho) obj).tamanho)
		return true;
	return false;
}`

Alias, eu realmente precisaria de:

`public int hashCode() {
	return super.getCodigo();
}`

na classe ProdutoComTamanho? Ela já ná herdaria o hashCode da superclasse?

O estado dos Objetos Produto e ProdutoComTamanho não mudam, apenas a quantidade é alterada que é “calculada” pela classe CarrinhoDeCompras…

Em uma resposta anterior está o código que ainda estou tentando fazer…

P

Se vc esta usando apenas o código pra calcular o hashCode, vc tem que garantir que código nunca vai mudar enquanto o objeto Produto existir.

Não precisa. Mas na superclasse, vc tem que retornar o hashCode do código, e não o código.

N

Apenas usando o construtor para atribuir as informações e não possibilitar que estas informações sejam alteradas já garante isso? Por exemplo, eu não fiz nenhum set para nenhum atributo

Como? eu não posso ter um HashCode que seja o valor de um atributo int código?

N

Bom dia,

Fazendo apenas oque o exercício pediu, omitindo os testes, os códigos ficaram assim:

Classe Produto:

public class Produto {

private String nome;
private int codigo;
private double valor;

public Produto(String nome, int codigo, double valor){
	this.nome = nome;
	this.codigo = codigo;
	this.valor = valor;
}

public String getNome(){
	return this.nome;
}

public int getCodigo(){
	return this.codigo;
}

public double getValor(){
	return this.valor;
}

@Override
public String toString(){
	return this.getNome();
}

@Override
public int hashCode() {
	return this.getCodigo();
}

@Override
public boolean equals(Object obj) {
	if(this.getCodigo() == obj.hashCode())
		return true;
	return false;
}

}

Classe ProdutoComTamanho:

public class ProdutoComTamanho extends Produto {

public ProdutoComTamanho(String nome, int codigo, double preco, int tamanho) {
	super(nome, codigo, preco);
	this.tamanho = tamanho;
	
}

public int getTamanho(){
	return this.tamanho;
}

@Override
public boolean equals(Object obj) {
	if(super.getCodigo() == obj.hashCode() && this.tamanho == ((ProdutoComTamanho) obj).tamanho)
		return true;
	return false;
}

}

Classe CarrinhoDeCompras:

import java.util.HashMap;

public class CarrinhoDeCompras {

private HashMap<Produto, Integer> controle = new HashMap<>();

public void adicionaProduto(Produto produto, int quantidade){
	if( this.getControle().containsKey(produto)){
		this.getControle().put(produto, this.getControle().get(produto) + quantidade);
	} else {
		this.getControle().put(produto, quantidade);
	}
}

private HashMap<Produto, Integer> getControle(){
	return this.controle;
}

public void removeProduto(Produto produto, int quantidade){
	if( this.getControle().containsKey(produto) && this.getControle().get(produto) > quantidade){
		this.getControle().put(produto, this.getControle().get(produto) - quantidade);
	} else if( this.getControle().containsKey(produto) && this.getControle().get(produto) <= quantidade){
		this.getControle().remove(produto);
	}
}

public double valorTotal(){
	double valorTotal = 0;
	for(Produto temp : this.getControle().keySet()){
		valorTotal += temp.getValor() * this.getControle().get(temp);
	};
	return valorTotal;
}

}

Classe Principal:

public class Principal {

public static void main(String[] args) {
	
	CarrinhoDeCompras carrinhoCarlos = new CarrinhoDeCompras();
	
	//Produtos -> nome, código, valor
	
	Produto p1 = new Produto("cha", 123, 2.45);
	Produto p2 = new Produto("café", 321, 9.85);
	Produto p3 = new Produto("biscoito", 465, 1.50);
	Produto p4 = new Produto("oleo", 389, 2.00);
	Produto p5 = new Produto("macarrao", 134, 2.90);
	
	//ProdutoComTamanho -> nome, código, valor, tamanho 
	
	ProdutoComTamanho pt1 = new ProdutoComTamanho("camisa", 675, 20.50, 40);
	ProdutoComTamanho pt3 = new ProdutoComTamanho("camisa", 675, 20.50, 40);
	ProdutoComTamanho pt2 = new ProdutoComTamanho("calca", 685, 20.50, 40);
	ProdutoComTamanho pt4 = new ProdutoComTamanho("calca", 685, 20.50, 42);
	
	//Inclusão dos produtos no carrinho -> Produto/ProdutoComTamanho, quantidade
	
	carrinhoCarlos.adicionaProduto(p1, 1);
	carrinhoCarlos.adicionaProduto(p2, 2);
	carrinhoCarlos.adicionaProduto(p3, 1);
	carrinhoCarlos.adicionaProduto(p4, 4);
	carrinhoCarlos.adicionaProduto(p5, 2);
	carrinhoCarlos.adicionaProduto(pt1, 2);
	carrinhoCarlos.adicionaProduto(pt2, 2);
	carrinhoCarlos.adicionaProduto(pt3, 5);
	carrinhoCarlos.adicionaProduto(pt4, 2);
	
	System.out.println(carrinhoCarlos.valorTotal());
}

}

Ou baixem o projeto do eclipse:

heranca.zip (6,9 KB)

Gostaria de feedbacks, opiniões, críticas, etc

Sem mais. Obrigado

P

Eu achei que código era uma string. Neste caso você pode retornar o próprio código se ele for int.

N

Feedback gente… eu preciso de feedback…

S

Você implementou de forma estranha seus métodos hashCode e equals

Dê uma olhada nestes exemplos:

N

Oi, boa tarde.

Como cada produto deverá possuir um código único para ele, achei mais prático ele também servir para hashCode

Bom… faltou uma verificada no parâmetro, mas é simples assim, como o hashCode é o Código ( getCodigo) se os dois são iguais, são objetos do mesmo tipo. Neste caso…

S

Eu faria dessa forma o equals:

@Override
public boolean equals(Object obj) {
    if (obj instanceof Produto) {
        Produto that = (Produto) obj;
        return this.getCodigo() == that.getCodigo();
    }
    return false;
}
N

Obrigado. Seguirei seu exemplo.

Criado 28 de dezembro de 2016
Ultima resposta 20 de jan. de 2017
Respostas 19
Participantes 5