String é um objeto?

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.

1 curtida

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

3 curtidas

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.

3 curtidas

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.