2012-09-03 7 views
6

Sono nuovo di Java. Una cosa che mi confonde è il motivo per cui alcune delle classi necessitano di new per creare un'istanza e perché alcune altre NON hanno bisogno di creare un'istanza new.Perché alcune classi non hanno bisogno della parola "Nuovo" quando si crea la sua istanza?

Ad esempio, sto guardando log4j, non ha bisogno di new.

Perché alcune altre classi hanno bisogno di nuovo? Per esempio, una classe Employee:

Employee X = new Employee (John); 
X.getwork(); 

ecc ecc

Perché non abbiamo detto, Logger logger = new Logger(...);? e perché siamo stati in grado di usarlo anche senza new, come logger.setLevel(), ecc.

+3

[Modello metodo di fabbrica] (http://en.wikipedia.org/wiki/Factory_method_pattern) – oldrinb

+0

'Logger.getLogger' chiama' nuovo Logger' internamente. C'è sempre una chiamata al costruttore da qualche parte - solo che non sempre nel * tuo * codice. – Blorgbeard

+0

WOW questo ha un sacco di risposte in breve tempo ... – Doorknob

risposta

0

Nell'esempio si devono utilizzare diversi casi: il metodo statico che restituisce un oggetto e la chiamata effettiva del costruttore.

Il metodo statico è un metodo che non ha bisogno di essere chiamato su un oggetto, qui il suo meccanismo interno può creare un'istanza di un oggetto e restituirlo per uso futuro, in questo metodo, c'è una chiamata a "nuovo" ma il oggetto potrebbe essere configurato, o recuperato da una cache prima di essere restituito. Questo è il tipo di chiamata

Logger logger = Logger.getLogger("com.foo"); 

La chiamata del costruttore effettivo (che utilizza nuovo) è il modo normale di creare un nuovo oggetto.

1

perché Logger.getLogger() restituisce un oggetto Logger. new Logger() chiama il costruttore che restituisce anche un Logger. Anche questo tipo di usi new anche perché all'interno della classe Logger è probabilmente qualcosa di simile:

public class Logger { 
    public static Logger getLogger() { 
     return new Logger("foo", "bar"); 
    } 
} 
0

Non erano tecnicamente utilizzando la classe Logger, ma stava utilizzando un metodo. Non stavi tecnicamente creando un'istanza della classe Logger, né mantenendo un riferimento ad essa direttamente come faresti con Logger logger = new Logger(). Invece, quello che stai facendo è accedere a un metodo per recuperare un'istanza restituita. Sarebbe bello vedere la definizione della classe. Tuttavia, più probabilmente quello che hai è un metodo statico all'interno della classe. E la classe è più che probabile definita con un costruttore privato. Ciò consente l'accesso ai metodi senza creare un'istanza della classe. Si può vedere una buona spiegazione di questo, e di statica in Java qui: https://stackoverflow.com/a/1844388/1026459

+0

Stava usando la classe Logger, semplicemente non chiamando il costruttore (direttamente). – Blorgbeard

+0

@Blorgbeard - Dovrei riformulare quello. –

7

L'unico modo per creare un nuovo oggetto in Java è con new [1]. Tuttavia, in alcune classi, non è possibile pronunciare direttamente new, è necessario chiamare un metodo factory, che potrebbe essere statico (come con l'esempio del logger) oppure no. L'autore di una classe lo imposta facendo in modo che i costruttori abbiano accesso diverso da public.

Si noti inoltre che l'esempio potrebbe non coinvolgere affatto un nuovo oggetto. La funzione Logger potrebbe restituire un oggetto vecchio, non uno nuovo.

Il seguente poesia di Ogden Nash sembra vagamente rilevanti:

This morning I went to the zoo 
In order to look at the gnu. 
But the old gnu was dead, 
and the new gnu, they said, 
Was too new a new gnu to view. 

[1] A meno che non sei stato coinvolto nel basso livello di riflessione, o utilizzare Object.clone()

+0

Ci sono alternative al nuovo operatore: http://stackoverflow.com/questions/95419/what-are-all-the-different-ways-to-create-an-object-in-java – maba

1

Per esempio, alcune classi possono impedire di creando più di un oggetto nell'applicazione. In questo caso è necessario chiamare un metodo per istanziare la classe, come Logger.getLogger(). Il getLogger() può avere il codice come questo:

if(uniqueInstance == null) { 
    uniqueInstance = new Logger(); 
} 

return uniqueInstance; 

Dove uniqueInstance è un'istanza di Logger. Questo è un modello di design chiamato Singleton. In questo modello, non è possibile creare un'istanza della classe perché il costruttore è privato.

Un altro modo in cui non è possibile creare un'istanza di una classe è quando la classe è definita come statica.

Le classi che hanno costruttori pubblici e non sono statiche devono essere istanziate con la nuova parola chiave.

0

Alcune classi non possono essere istanziate al di fuori di se stesse (ad esempio la classe Math, queste classi hanno costruttori non pubblici). Di queste classi, alcuni forniscono metodi che restituiscono istanze della classe (ad esempio la classe InetAddress). Questi sono chiamati metodi di fabbrica. Sono i metodi static che restituiscono le istanze della classe in cui si trovano, quindi non è necessario utilizzare la parola chiave new (viene invece utilizzata all'interno dei metodi di fabbrica). Per esempio:

public class A { 
    private A() {} 
    public A createAnA() { return new A(); } 
} 

Qui, createAnA() è il metodo factory.

3

In questo caso, si tratta dei metodi di produzione , come indicato in my comment.

vedere la specifica API pertinenti sulle Logger

Recuperare un logger di nome in base al valore del parametro nome. Se il logger nominato esiste già, verrà restituita l'istanza esistente. Altrimenti, viene creata una nuova istanza.

Per impostazione predefinita, i logger non hanno un livello impostato ma lo ereditano dal loro antenato neareast con un livello impostato. Questa è una delle caratteristiche principali di log4j.

Il factory method pattern è un design pattern creazionale, e, secondo Wikipedia, è spesso utile nelle seguenti situazioni:

Il modello di fabbrica può essere utilizzata quando:

  • La creazione di un oggetto preclude il suo riutilizzo senza significativa duplicazione del codice.
  • La creazione di un oggetto richiede l'accesso a informazioni o risorse che non devono essere contenute nella classe di composizione.
  • La gestione a vita degli oggetti generati deve essere centralizzata per garantire un comportamento coerente all'interno dell'applicazione.

Tutti e tre di questi sono applicabili qui ... chissà che tipo di lavoro va in ricerca del logger corretto? Non sei davvero interessato a creare un nuovo logger ogni volta che vuoi usarne uno ... invece, il tuo obiettivo principale è proprio questo: per usa uno uno.

La scorta Wiki ha anche un relevant article,

metodi di fabbrica sono a volte utilizzati al posto dei costruttori per diverse ragioni:

  • Alcune lingue (come Java) non consentono costruttori per avere nomi utili
  • Alcuni linguaggi (come Java) non consentono ai costruttori di avere nomi diversi (che possono essere necessari se si desidera utilizzare la stessa firma di metodo per due costruttori)
  • Per consentire la stessa istanza per essere riutilizzato, invece di ricreare ogni volta che è necessario (vedi FlyweightPattern)

penso che la terza opzione è probabilmente il più applicabile qui. Utilizzando la creazione manuale di un nuovo Logger, non è possibile condividerli adeguatamente. L'utilizzo della facciata getLogger abilita questo in modo trasparente.

Tutto sommato, l'uso di metodi di produzione è in genere per consentire un codice più lineare più pulito senza esporre il lavoro che non ti interessa.

1

Bene, quello che stai chiedendo è più relativo ai modelli di progettazione. La classe Logger segue lo schema di singleton.

Si supponga di voler creare una sola istanza della classe sull'applicazione, quindi è possibile rendere privato il costruttore e fornire un metodo statico che crea e archivia l'oggetto della classe quando viene richiamato per la prima volta.

public class SingletonPattern {

 private static SingletonPattern instance; 

    private SingletonPattern(){} 

    public static synchronized SingletonPattern getInstance(){ 
     if (instance == null){ 
      instance = new SingletonPattern(); 
     } 
     return instance; 
    } 
} 

In questo modo è possibile restringere la classe da un'istanza solo una volta.