Por que as strings são imutáveis ​​em alguns idiomas?

9

String é uma classe imutável em Java. Uma classe imutável é simplesmente uma classe cujas instâncias não podem ser modificadas. Por que a linguagem de programação Java escolhe tornar objetos da classe String imutáveis?

Tupledev
fonte
2
@PJTraill Não parece inevitável. Literais de strings em outras linguagens não são imutáveis ​​em, digamos, C, e objetos de outras classes em Java não são imutáveis.
David Richerby
2
Esta é uma pergunta sobre o design da linguagem de programação. Parece no tópico, para mim.
David Richerby
2
@DavidRicherby, Literais de string são imutáveis ​​em C (em termos de C90: se o programa tentar modificar um literal de string de qualquer forma, o comportamento será indefinido. Algumas versões anteriores o aceitaram devido à falta de const no idioma, e o fizeram às vezes o que o programador esperava, mas acho que nunca foi suportado) Acho que todo mundo aprendeu com o erro no início do FORTRAN, que permitiu alterar literais. Ter literais criando um novo objeto mutável, cujo valor inicial é o mesmo que o literal, por outro lado, se não for algo doentio.
APROGRAMMER #
1
O @AProgrammer Plenty foi escrito sobre o motivo pelo qual o Java foi projetado da maneira que era: eu ficaria surpreso se não houvesse autoridade sobre as decisões de design em torno da classe String. Mas, mesmo que os designers de linguagem nunca tenham dito por que o String é imutável, isso não torna a pergunta fora de tópico ou até ruim: significa apenas que, infelizmente, a única resposta adequada é "Não sabemos".
David Richerby
1
@DavidRicherby Seria melhor se a pergunta fosse independente de idioma. Este pode ser respondido citando uma declaração de um desenvolvedor Java; queremos respostas que expliquem conceitos.
Raphael

Respostas:

9

Esse problema está fortemente ligado à noção do que significa ser uma instância de uma classe. Em termos estritamente orientados a objetos, uma classe tem um invariante associado: um predicado que sempre é verdadeiro ao sair de um método (público) da classe. Essa noção é central para garantir que a herança seja bem definida, por exemplo (faz parte do Princípio de Substituição de Liskov ).

Um dos problemas mais perniciosos do Java é que é difícil impedir que o código do cliente quebre invariantes de classe.

Por exemplo, considere a seguinte classe 'ZipCode':

class ZipCode {
    private String zipCode;

    public ZipCode(String value){
        if(!isValidZipCode(value))
            throw new IllegalArgumentException();
        zipCode = value;
        assert(invariant());
    }

    public String get() { return zipCode; }

    public boolean invariant() {
        return isValidZipCode( zipCode );
    }
}

Se String não fosse imutável, seria possível para um usuário do ZipCode chamar 'get' e alterar os caracteres a qualquer momento subsequente, quebrando assim o invariável e destruindo a integridade conceitual oferecida pelo encapsulamento do conceito do ZipCode.

Como esse tipo de integridade é essencial para garantir a validade de grandes sistemas, essa resposta à sua pergunta realmente implica em:

"Por que o Java não suporta um analógico do C ++ const, ou pelo menos oferece versões imutáveis ​​de mais de suas classes de bibliotecas?"

NietzscheanAI
fonte
7

Coisas como strings e datas são naturalmente valores. Em termos de C ++, esperamos que eles tenham um construtor de cópias, um operador de atribuição e um operador de igualdade, mas nunca esperamos usar o endereço deles. Portanto, não esperamos que eles sejam alocados individualmente no heap. Métodos virtuais não fazem sentido.

Objetos de domínio são naturalmente referências. Os C ++ não têm construtor de cópias, operador de atribuição ou operador de igualdade (eles são iguais apenas se forem idênticos). Podemos pegar o endereço deles e esperamos que eles sejam alocados em heap. Métodos são geralmente virtuais.

Java não possui classes de valor, apenas classes de referência. Os valores são falsificados com objetos imutáveis. Isso é verdade para seqüências de caracteres, mas não, infelizmente, para datas. A mutabilidade das datas Java causou problemas frequentes e agora está obsoleta. Valores mutáveis ​​não podem ser usados ​​como base para um hash, por exemplo.

Miniatura
fonte
Bem, valores mutáveis podem ser usados ​​para o hash, mas é melhor não modificá-los depois, se você confiar no código de hash!
gnasher729
6

O Java foi projetado para permitir a execução de subseções do código de um programa em ambientes com restrições de segurança. A maneira como esse requisito foi implementado foi definir um "SecurityManager" em um thread que tenha acesso aos parâmetros de certas operações críticas (por exemplo, abrir um arquivo) e perguntar se a operação deve ou não ser executada. Se o Java Strings fosse mutável, um programa poderia contornar essas restrições criando dois threads, um que executava uma operação de arquivo aberto que seria permitida enquanto o outro modificava a string em que armazenava o nome do arquivo em um que não seria permitido. Existe a possibilidade de o gerenciador de segurança ler a string original, aceitar a operação, que será transmitida para o código de abertura do arquivo que precederia a abertura do segundo arquivo (não permitido).

  • cordas imutáveis
  • executando cópia defensiva de qualquer sequência crítica de segurança antes de verificar sua aceitabilidade.

A última possibilidade tornaria todas essas operações mais lentas e seria mais provável que a implementação contivesse bugs; portanto, o uso de strings imutáveis ​​foi a decisão mais sensata.

De maneira mais geral, objetos imutáveis ​​são úteis porque permitem o compartilhamento sem a necessidade de fazer cópias defensivas (o que pode ser necessário mesmo em códigos não críticos à segurança para evitar erros quando os dados de origem são alterados); portanto, mesmo sem esse requisito, a decisão ainda seria razoável.

Jules
fonte
1
Fico feliz que alguém tenha apontado isso, porque James Gosling foi completamente claro sobre essa decisão de design. O Java foi projetado para que você possa executar o código não confiável enviado a você por uma rede (por exemplo, em um navegador da web ou em um decodificador digital). O principal motivo para tornar as seqüências imutáveis ​​foi facilitar para os fornecedores ou gerentes de site (e os implementadores da biblioteca padrão Java!) Implementar suas próprias políticas de segurança personalizadas. Seqüências imutáveis ​​efetivamente fecham um vetor de ataque em potencial por design.
Pseudônimo