2012-09-03 10 views
6

Soy nuevo en Java. Una cosa me confunde es por qué algunas de las clases necesitan new para instanciar, y por qué algunas otras NO necesitan new para crear instancias.¿Por qué algunas clases no necesitan la palabra "Nuevo" al crear su instancia?

Por ejemplo, estoy buscando en log4j, no necesita new.

¿Por qué algunas otras clases necesitan algo nuevo? Por ejemplo, una clase de empleados:

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

, etc, etc

Por qué no dijimos, Logger logger = new Logger(...);? y por qué pudimos usarlo incluso sin new, como logger.setLevel(), etc.

+3

[Patrón de método de fábrica] (http://en.wikipedia.org/wiki/Factory_method_pattern) – oldrinb

+0

'Logger.getLogger' llama internamente 'nuevo registrador'. Siempre hay una llamada de constructor en alguna parte, pero no siempre en * su * código. – Blorgbeard

+0

WOW esto tiene muchas respuestas en poco tiempo ... – Doorknob

Respuesta

0

En su ejemplo, tiene que utilizar diferentes casos de uso: el método estático que devuelve un objeto y la llamada real al constructor.

El método estático es un método que no necesita ser invocado en un objeto, aquí su mecanismo interno puede crear una instancia de un objeto y devolverlo para uso futuro, en este método, hay una llamada a "nuevo" pero el objeto puede ser configurado, o recuperado de un caché antes de ser devuelto. Este es este tipo de llamada

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

La llamada real al constructor (que usa nuevo) es la forma normal de crear un objeto nuevo.

1

porque Logger.getLogger() devuelve un objeto Logger. new Logger() llama al constructor que también devuelve Logger. Esto también se utiliza tipo de new también, porque dentro de la clase Logger es probablemente algo como:

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

Usted no fue técnicamente utilizando la clase Logger, pero estaba utilizando un método. No estabas instantando técnicamente la clase Logger, ni guardando una referencia directamente a ella como lo harías con Logger logger = new Logger(). En cambio, lo que está haciendo es acceder a un método para recuperar una instancia devuelta. Sería bueno ver la definición de la clase. Sin embargo, lo más probable es que tenga un método estático dentro de la clase. Y la clase es más que probable definida con un constructor privado. Esto permite el acceso a los métodos sin instanciar la clase. Puede ver una buena explicación de esto y de estática en java aquí: https://stackoverflow.com/a/1844388/1026459

+0

Estaba usando la clase Logger, simplemente no llamaba al constructor (directamente). – Blorgbeard

+0

@Blorgbeard - Debo volver a expresar eso. –

7

La única forma de crear un nuevo objeto en Java es con new [1]. Sin embargo, en algunas clases, no está permitido decir new, debe llamar a un método de fábrica, que puede ser estático (como con el ejemplo de su registrador) o no. El autor de una clase establece esto haciendo que los constructores tengan acceso que no sea public.

También tenga en cuenta que su ejemplo puede no implicar un nuevo objeto en absoluto. Esa función Logger puede devolver un objeto viejo, no uno nuevo.

El siguiente poema de Ogden Nash parece vagamente relevante:

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 menos que usted se involucra en reflexión de bajo nivel, o utilizar Object.clone()

+0

Hay alternativas al nuevo operador: http://stackoverflow.com/questions/95419/what-are-all-the-different-ways-to-create-an-object-in-java – maba

1

Por ejemplo, algunas clases pueden evitar que usted creando más de un objeto en la aplicación. En ese caso, debe llamar a algún método para instanciar la clase, como Logger.getLogger(). El getLogger() puede tener el código como este:

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

return uniqueInstance; 

Dónde uniqueInstance es una instancia de Logger. Este es un patrón de diseño llamado Singleton. En este patrón, no puedes instanciar la clase porque su constructor es privado.

Otra forma en que no se puede instanciar una clase es cuando la clase se define como estática.

Las clases que tienen constructores públicos y no son estáticas deben crearse con la nueva palabra clave.

0

Algunas clases no se pueden crear instancias fuera de ellas (por ejemplo, la clase Math, estas clases tienen constructores no públicos). De esas clases, algunas proporcionan métodos que devuelven instancias de la clase (por ejemplo, la clase InetAddress). Estos se llaman métodos de fábrica. Son métodos static que devuelven instancias de la clase en la que se encuentran, por lo que no es necesario utilizar la palabra clave new (en su lugar, se usa dentro de los métodos de fábrica). Por ejemplo:

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

Aquí, createAnA() es el método de fábrica.

3

En este caso, estamos tratando con métodos de fábrica, como dije en my comment.

Ver la especificación API pertinente sobre Logger

Recuperar un registrador de nombre de acuerdo con el valor del parámetro de nombre. Si el registrador con nombre ya existe, se devolverá la instancia existente. De lo contrario, se crea una nueva instancia.

De manera predeterminada, los registradores no tienen un nivel establecido sino que lo heredan de su ancestro anterior con un nivel establecido. Esta es una de las características centrales de log4j.

El factory method pattern es un patrón de diseño creacional, y, según la Wikipedia, a menudo es útil en las siguientes situaciones:

El patrón de la fábrica se puede utilizar cuando:

  • La creación de un objeto impide su reutilización sin duplicación significativa de código.
  • La creación de un objeto requiere acceso a información o recursos que no deberían estar contenidos dentro de la clase de composición.
  • La administración de por vida de los objetos generados debe centralizarse para garantizar un comportamiento uniforme dentro de la aplicación.

Los tres de éstos son aplicables aquí ... quién sabe qué tipo de trabajo va a encontrar el registrador correcto? No está realmente interesado en crear un registrador nuevo cada vez que quiera usar uno ... en cambio, su enfoque es principalmente eso: a use.

La idea Wiki también tiene un relevant article,

métodos de fábrica se utilizan a veces en lugar de constructores por cualquiera de varias razones:

  • algunos idiomas (como Java) no permiten los constructores tienen nombres útiles
  • Algunos lenguajes (como Java) no permiten que los constructores tengan nombres diferentes (lo que puede ser necesario si desea utilizar la misma firma de método para dos constructores)
  • Para permitir que la misma instancia para ser reutilizado en lugar de crear cada vez que sea necesario (ver FlyweightPattern)

creo que la tercera opción es probablemente la más aplicable en este caso. Usando la creación manual de un nuevo Logger, no puede compartirlos adecuadamente. El uso de la fachada getLogger permite que esto suceda de forma transparente.

En general, el uso de métodos de fábrica es generalmente para permitir un código más claro y directo sin exponer el trabajo que no necesariamente le importa.

1

Bueno, lo que estás preguntando está más relacionado con los patrones de diseño. La clase Logger sigue el patrón singleton.

Supongamos que quiere que solo una instancia única de su clase se cree en la aplicación, entonces puede hacer que su constructor sea privado y proporcione un método estático que cree y almacene el objeto de su clase cuando se invoque por primera vez.

SingletonPattern public class {

 private static SingletonPattern instance; 

    private SingletonPattern(){} 

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

De esta manera se puede restringir su clase para crear una instancia de una sola vez.

Cuestiones relacionadas