Perché Java non utilizza l'incapsulamento con alcune classi?


25

La mia domanda è in relazione con System.ine System.outclassi (potrebbero essercene altre simili a quelle della libreria Standard). Perché? Non è una cattiva pratica in OOP? Non dovrebbe essere usato come: System.getIn()e System.getOut()? Ho sempre avuto questa domanda e spero di poter trovare una buona risposta qui.

Risposte:


36

Le definizioni per i campi ine outall'interno della Systemclasse sono:

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

Queste sono costanti. Capita anche di essere oggetti, ma sono costanti. È molto simile alla classe di matematica:

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

O nella classe booleana:

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

O nella classe Colore:

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);

Quando si accede a una costante pubblica che non cambia, non vi è alcun vantaggio significativo nell'incapsularla, concettualmente o basata sulle prestazioni. È lì. Non cambierà.

Non c'è alcuna differenza reale tra Color.whitee System.out.


Bene, non l'ho visto in questo modo, sono oggetti costanti. Questa è una spiegazione abbastanza buona.
Clawdidr,

1
@Clawdidr nella Java di oggi, si potrebbe considerare di usare il enumper tenerli ... anche se enumera nuovo con Java 1.5 (non un'opzione nei 1.0 giorni).

Solo per curiosità (non uno sviluppatore Java me stesso): c'è una differenza tra final statice static final? Se è così, che cosa è?
Marjan Venema,

1
@MarjanVenema nessuna differenza, solo ordine preferito dei modificatori. il controllo modificatore checkstyle mostra l'ordine preferito. Apparentemente, chiunque abbia scritto quei due file sorgente nella versione jdk non ho concordato l'ordine. È semplicemente una convenzione.

:) e grazie Michael, per il tempo dedicato a rispondere e per il link.
Marjan Venema,

5

La vera ragione è che si tratta di un problema precedente. Le System.in,out,errcostanti facevano parte di Java 1.0 ... e probabilmente molto più indietro. Quando era chiaro che il progetto aveva problemi, era troppo tardi per risolverlo. Il meglio che potevano fare era aggiungere i System.setIn,setOut,setErrmetodi in Java 1.1 e quindi affrontare i problemi relativi alle specifiche del linguaggio 1 .

Questo è simile al problema del perché esiste un System.arraycopymetodo statico il cui nome viola le convenzioni di denominazione Java.


Se questo è "cattivo design" o no, penso che lo sia. Ci sono situazioni in cui l'attuale gestione non OO è un problema serio. (Pensa ... come puoi eseguire un programma Java all'interno di un altro quando i loro requisiti di flusso "IO standard" sono in conflitto. Pensa ... codice di test unitario che comporta la modifica dei flussi.)

Tuttavia, posso anche riferirmi all'argomento secondo cui l'attuale modo di fare le cose è più conveniente in molti casi.


1 - È interessante notare che le System.in,out,errvariabili ricevono una menzione speciale nel JLS come "semantica speciale". JLS afferma che se si modifica il valore di un finalcampo, il comportamento non è definito ... tranne nel caso di questi campi.


2

Credo che l'oggetto out sia immutabile, il che lo rende in qualche modo sicuro (questo è discutibile) per essere tenuto in un campo statico finale pubblico.

Molte delle classi del JDK non rispettano i migliori principi di progettazione orientati agli oggetti. Uno dei motivi è il fatto che sono stati scritti quasi 20 anni fa, quando l'orientamento agli oggetti stava emergendo come un paradigma mainstream e molti programmatori semplicemente non li conoscevano come lo sono ora. Un ottimo esempio di cattiva progettazione dell'API è l'API Date & Time, che ha richiesto 19 anni per cambiare ...


3
Renderei ancora più forte l'affermazione, una variabile finale pubblica (statica o no) è esattamente "sicura" come un getter e preferirei l'immutabilità su una coppia setter / getter. I setter sono quasi sempre una cattiva idea (Immutabile è buono - e se non può essere immutabile il metodo che "Imposta" probabilmente merita anche una piccola logica aziendale), Se hai bisogno di un getter potresti anche renderlo pubblico finale, ma non è preferibile fare nessuno dei due: non chiedere a una classe i suoi dati, chiedi a una classe di fare qualcosa per i suoi dati.
Bill K,

@BillK: Sì, noto anche come Legge di Demetra (anche se non è una legge, piuttosto una linea guida).
sleske,

2

Questa risposta è grande e vera.

Volevo aggiungere che in alcuni casi sono stati fatti dei compromessi per motivi di usabilità.

Gli oggetti di tipo String possono essere istanziati senza nuovo, evento quando String non è una primitiva:

String s = "Hello";

Essendo la stringa non primitiva, dovrebbe essere istanziata in questo modo:

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

Ma il compilatore consente l'opzione OO più breve e meno, poiché String è di gran lunga la classe più utilizzata nell'API.

Inoltre, le matrici possono essere inizializzate in modo non OO:

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

Abbastanza strano, un oggetto è un'istanza di una classe o un array . Le matrici di significato sono un tipo di classe completamente separato.

Le matrici hanno un lengthcampo pubblico che non è una costante. Inoltre non c'è documentazione sugli array di classi che sono un'istanza di. (da non confondere con la classe Arrays o java.reflect.Array).

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

6
Sono cose diverse: new String("Hello")creerà sempre un nuovo oggetto String. Mentre String s = "Hello";utilizzerà l'oggetto internato. Confronta: "Hello" == "Hello"può essere vero, mentre new String("Hello") == new String("Hello")è sempre falso. C'è una magia di ottimizzazione del tempo di compilazione in corso nel primo che non è possibile con new String("Hello"). Vedi en.wikipedia.org/wiki/String_interning

@MichaelT Ho aggiunto un po 'di stranezza in più agli array, solo per completezza.
Tulains Córdova,

2
@Tarik Stavo obiettando che "essendo una stringa non primitiva, dovrei essere istanziato in questo modo: String s = new String("Hello");" che non è corretto. L'opzione più corta ( String s = "Hello";) è più corretta a causa dell'internazionale della stringa.

2
Con String, non esiste un'opzione "più corretta". Sono corretti entrambi. Tuttavia, come dice MichaelT, quello più corto è preferito a causa dell'internazionale String.
Andres F.

1
@AndresF. Ho cambiato "meno corretto" per "meno OO".
Tulains Córdova,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.