Por que Java não utiliza encapsulamento com algumas classes?


25

Minha pergunta está relacionada a System.ine System.outclasses (pode haver outras como as da biblioteca Padrão). Por que é que? Isso não é uma prática ruim em POO? Não deve ser usado como: System.getIn()e System.getOut()? Eu sempre tive essa pergunta e espero encontrar uma boa resposta aqui.

Respostas:


36

A definição para os campos ine outdentro da Systemclasse são:

public final static PrintStream out;
public final static InputStream in;

Estas são constantes. Eles também são objetos, mas são constantes. É muito parecido com a classe Math:

public static final double E = 2.7182818284590452354;
public static final double PI = 3.14159265358979323846;

Ou na classe booleana:

public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);

Ou na classe Color:

public final static Color white     = new Color(255, 255, 255);
public final static Color black     = new Color(0, 0, 0);
public final static Color red       = new Color(255, 0, 0);

Ao acessar uma constante pública que não muda, não há uma vantagem significativa para encapsulá-la - conceitualmente ou com base no desempenho. Está lá. Isso não vai mudar.

Não há diferença real entre Color.whitee System.out.


Bem, eu não vi dessa maneira, eles são objetos constantes. Essa é uma boa explicação.
Clawdidr 12/08

1
@Clawdidr no Java de hoje, pode-se considerar usar o enumpara mantê-los ... embora enumfosse novo no Java 1.5 (não é uma opção nos 1,0 dias).

Apenas por curiosidade (não sou desenvolvedor de Java): existe uma diferença entre final statice static final? Se assim for, o que é?
Marjan Venema

1
@MarjanVenema não há diferença, apenas a ordem preferida dos modificadores. checkstyle modifier check mostra a ordem preferida. Aparentemente, quem escreveu esses dois arquivos de origem na versão jdk não concordei com o pedido. É apenas uma convenção.

:) e obrigado Michael, por reservar um tempo para responder e pelo link.
Marjan Venema

5

A verdadeira razão é que esse é um problema herdado. As System.in,out,errconstantes faziam parte do Java 1.0 ... e provavelmente muito mais atrás. Quando ficou claro que o design apresentava problemas, era tarde demais para corrigi-lo. O melhor que eles puderam fazer foi adicionar os System.setIn,setOut,setErrmétodos no Java 1.1 e depois lidar com os problemas de especificação de linguagem 1 .

Isso é semelhante à questão de por que existe um System.arraycopymétodo estático cujo nome viola as convenções de nomenclatura Java.


Quanto a saber se isso é "design inadequado" ou não, acho que é. Há situações em que o manuseio atual sem OO é um problema sério. (Pense ... como você pode executar um programa Java dentro de outro quando seus requisitos de fluxo de "E / S padrão" entrarem em conflito. Pense ... código de teste de unidade que implica a alteração dos fluxos.)

No entanto, também posso me relacionar com o argumento de que a maneira atual de fazer as coisas é mais conveniente em muitos casos.


1 - É interessante notar que as System.in,out,errvariáveis ​​recebem menção especial no JLS como tendo "semântica especial". O JLS diz que se você alterar o valor de um finalcampo, o comportamento é indefinido ... exceto no caso desses campos.


2

Eu acredito que o objeto out é imutável, o que o torna de alguma forma seguro (isso é discutível) por ser mantido em um campo estático final público.

Muitas das classes no JDK não respeitam os melhores princípios de design orientado a objetos. Uma razão para isso é o fato de terem sido escritas há quase 20 anos, quando a Orientação a Objetos estava apenas emergindo como um paradigma convencional e muitos programadores simplesmente não estavam familiarizados com elas como estão agora. Um exemplo muito bom de mau design da API é a API Date & Time, que levou 19 anos para mudar ...


3
Eu tornaria a declaração ainda mais forte, uma variável final pública (estática ou não) é exatamente tão "segura" quanto um getter e eu preferiria a imutibilidade sobre um par setter / getter. Setters são sempre uma péssima idéia (Imutável é bom - e se não puder ser imutável o método que "Sets" provavelmente também merece um pouco de lógica de negócios), se você precisar de um getter, poderá publicá-lo final, mas não é preferível fazer um dos dois - não peça dados a uma classe, peça a ela que faça algo com seus dados.
Bill K

@ BillK: Sim, também conhecida como Lei de Demeter (embora não seja uma lei, mas uma diretriz).
sleske

2

Essa resposta é ótima e verdadeira.

Eu queria acrescentar que, em alguns casos, foram feitos compromissos em prol da usabilidade.

Objetos do tipo String podem ser instanciados sem um evento new quando String não é um primitivo:

String s = "Hello";

Sendo uma string não primitiva, deve ser instanciada assim:

String s = new String("Hello");          // this also works 

Mas o compilador permite a opção mais curta e menos OO, porque String é de longe a classe mais usada na API.

Também as matrizes podem ser inicializadas de maneira não OO:

int i[] = {1,2,3};

Estranho o suficiente, um objeto é uma instância de uma classe ou uma matriz . Matrizes de significado são um tipo de classe completamente separado.

As matrizes têm um lengthcampo público que não é uma constante. Além disso, não há documentação nas matrizes de classe das quais é uma instância. (para não confundir com a classe Arrays ou java.reflect.Array).

int a = myArray.length;    // not length()

6
Há coisas diferentes - new String("Hello")sempre criará um novo objeto String. Enquanto String s = "Hello";usará o objeto internado. Compare: "Hello" == "Hello"pode ser verdade, enquanto new String("Hello") == new String("Hello")é sempre falso. Há uma mágica de otimização do tempo de compilação acontecendo no primeiro, o que não é possível new String("Hello"). Veja en.wikipedia.org/wiki/String_interning

@ MichaelT Eu adicionei alguma estranheza extra em matrizes, apenas por uma questão de completude.
Tulains Córdova

2
@Tarik eu estava objetando ao "String sendo um não primitivo, deve ser instanciado como este: String s = new String("Hello");" que está incorreto. A opção mais curta ( String s = "Hello";) está mais correta devido à internação de strings.

2
Com String, não há opção "mais correta". Ambos estão corretos. Embora, como MichaelT diz, o mais curto seja o preferido por causa da internação por String.
Andrés F.

1
@AndresF. Alterei "menos correto" para "menos OO".
Tulains Córdova
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.