Se instanciar um objeto de uma classe normal, por exemplo:
Pessoa p1 = new Pessoa();
E dermos um print em p1 ele retornara um endereço de memoria
Por que ao criarmos uma variavel do tipo String ele retorna o valor armazenado nela em vez de um endereço de memoria já que String é um objeto?
Isso é questão de prova né?
Nas classes que você cria, você pode escrever métodos para retornar o que você quiser que retorne, inclusive o toString.
@FabianoVidal Esta informação está errada.
Em Java não conseguimos saber o endereço de memória dos objetos, não por meios comuns pelo menos.
O que vc vê no console quando vc pede para imprimir p1
na verdade é o nome da classe seguido pelo “@” e seguido pelo hash code do objeto em hexadecimal.
Isto acontece porque quando vc faz isso:
Pessoa p1 = new Pessoa();
System.out.println(p1);
O método println()
invoca por vc o método toString()
da sua classe Pessoa
. Vc com certeza não sobrescreveu o método toString()
da classe Pessoa
. Experimente o seguinte código e veja o que acontece:
class Pessoa {
@Override
public String toString() {
return "EU SOU UMA PESSOA";
}
}
public class Program {
public static void main(String... args) {
Pessoa p1 = new Pessoa();
System.out.println(p1);
}
}
A mensagem que vai aparecer agora é “EU SOU UMA PESSOA”. Percebeu?
Se vc não sobrescrever o método toString()
da classe Pessoa
, o que será invocado será o toString()
da superclasse, que no caso é a classe Object
e olha só como é implementado nela:
Dito isso, a dúvida que fica é sobre aquele número que vc pensou que era endereço de memória e que eu disse que era o hash code.
Bom, o hash code é obtido por meio do método hashCode()
e, segundo a documentação:
https://docs.oracle.com/en/java/javase/16/docs/api/java.base/java/lang/Object.html#hashCode()
O método hashCode()
existe para ser usados por hash table que é um tipo de estrutura de dados. Vc pode (e em alguns casos, DEVE) implementar este método normalmente, lendo a documentação vc vai ver que há algumas regrinhas que vc precisa seguir.
Bom, para vc ver o que eu falei na prática, experimente o código abaixo onde eu sobrescrevi o método hashCode()
.
class Pessoa {
@Override
public int hashCode() {
return 0xABCDEF;
}
}
public class Program {
public static void main(String... args) {
Pessoa p1 = new Pessoa();
System.out.println(p1);
}
}
Viu como a saída foi “Pessoa@abcdef”? Como eu disse, não é endereço de memória.
Complementando, a implementação de Object::hashCode
é dependente da implementação da JVM e pode variar conforme a versão desta, e até mesmo da plataforma na qual ela roda (já que o método é native
, ou seja, a implementação é “delegada” a código “nativo” dependente de plataforma, geralmente escrito em C ou C++).
Interessante notar que em versões anteriores (por exemplo, no Java 8), a documentação dizia que o hashCode
poderia ser baseado no endereço de memória (apesar de não ser obrigatório):
This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the Java™ programming language
Mas nas versões mais atuais (como no link indicado acima), este trecho foi removido e não há mais menção a endereços de memória. Agora tanto faz se o valor é calculado a partir do endereço da memória, ou se algum outro método é usado. O que importa é que o valor retornado siga o que está descrito na documentação (o mesmo objeto sempre retorna o mesmo valor, etc).
Você pode ver a implementação atual do OpenJDK aqui. Consultando hoje (11/08/2021), o algoritmo atual é descrito assim:
// hashCode() generation :
//
// Possibilities:
// * MD5Digest of {obj,stw_random}
// * CRC32 of {obj,stw_random} or any linear-feedback shift register function.
// * A DES- or AES-style SBox[] mechanism
// * One of the Phi-based schemes, such as:
// 2654435761 = 2^32 * Phi (golden ratio)
// HashCodeValue = ((uintptr_t(obj) >> 3) * 2654435761) ^ GVars.stw_random ;
// * A variation of Marsaglia's shift-xor RNG scheme.
// * (obj ^ stw_random) is appealing, but can result
// in undesirable regularity in the hashCode values of adjacent objects
// (objects allocated back-to-back, in particular). This could potentially
// result in hashtable collisions and reduced hashtable efficiency.
// There are simple ways to "diffuse" the middle address bits over the
// generated hashCode values:
Ou seja, nenhuma menção ao endereço de memória.
Lembrando que esta é a implementação do OpenJDK (e consequentemente, do Oracle JDK). Porém, existem várias implementações da JVM, e pode ser que alguma delas use o endereço de memória no cálculo do hash code. Mas essa não é uma garantia, apenas uma possibilidade. O importante é que ele seja aderente à especificação da linguagem, e principalmente, que você implemente-o de forma consistente com equals
.
Olha, String até onde eu sei é um tipo primitivo! o que se cria a partir dele pode ou não ser um objeto.
Em Java String não é um tipo primitivo, variáveis String são uma referência para um objeto da classe String.
Não sei onde vc viu isso, mas como já dito acima, isso não é verdade.
Na especificação da linguagem, a seção que lista os tipos primitivos não tem nenhuma menção à classe String
.
Já a seção que lista os tipos por referência, essa sim lista a classe String
.