2010-10-12 32 views
161

Cuando uso Java en base a mi conocimiento de C++, me encanta inicializar la variable de la siguiente manera.Debería inicializar la variable dentro del constructor o fuera del constructor

public class ME { 
    private int i; 

    public ME() { 
     this.i = 100; 
    } 
} 

Después de algún tiempo, puedo cambiar el hábito de

public class ME { 
    private int i = 100; 

    public ME() { 
    } 
} 

me encontré con el código fuente de los demás, algunos están utilizando primera convención, otros están usando segunda convención.

¿Sé qué convención recomiendan y por qué?

+2

Debe inicializar utilizando listas de inicialización en C++. De lo contrario, es la inicialización + asignación. –

+2

Este es un duplicado de http://stackoverflow.com/q/1994218/922348. Vea la respuesta aceptada para una discusión más a fondo. – rimsky

+0

Ellos ya tienen el valor predeterminado ... no es necesario volver a iniciarlos. –

Respuesta

157

Encuentro el segundo estilo (declaración + inicialización de una vez) superior. Razones:

  • Deja en claro de un vistazo cómo se inicializa la variable. Normalmente, cuando lee un programa y encuentra una variable, primero va a su declaración (a menudo automática en IDE). Con el estilo 2, verá el valor predeterminado de inmediato. Con el estilo 1, también debes mirar al constructor.
  • Si tiene más de un constructor, no tiene que repetir las inicializaciones (y no puede olvidarlas).

Por supuesto, si el valor de inicialización es diferente en diferentes constructores (o incluso calculado en el constructor), debe hacerlo en el constructor.

+11

Para solucionar el segundo problema, generalmente creo un constructor privado que contiene el código que se repetirá, y luego llamo 'this (privateConstructorArgs)' al comienzo de todos los demás constructores. – tmnol

+0

En lugar de definir y llamar a un constructor privado de todos los demás constructores, también podría definir un inicializador de instancia, que se llamará automáticamente antes de cada constructor. De esta forma, no tendrá que recordar llamar al constructor privado cuando agregue algunos nuevos constructores. – TheBaj

+0

@TheBaj, ya que la sugerencia del constructor privado se hizo para tratar de inicializar la variable a diferentes valores según el constructor llamado, ¿cómo se podría decir desde el inicializador de la instancia a qué constructor se llamó para determinar qué valor asignar? –

19

que tienden a utilizar la segunda para evitar un constructor complicada (o un ser inútil), también Realmente no considero esto como una inicialización (incluso si se trata de una inicialización), sino más bien como dando una valor por defecto.

Por ejemplo, en su segundo fragmento, puede eliminar el constructor y tener un código más claro.

6

El único problema que veo con el primer método es si está planeando agregar más constructores. Entonces estarás repitiendo el código y la capacidad de mantenimiento sufrirá.

+14

Siempre puede encadenar sus constructores. – Bernard

+0

@Bernard encadena constructor + tener herencia puede ser realmente horrible. –

+5

@Colin Hebert: Puede serlo, pero también puede ser elegante si está bien diseñado. – Bernard

3

Recomiendo inicializar variables en constructores. Es por eso que existen: para garantizar que sus objetos estén construidos (inicializados) correctamente.

De cualquier forma funcionará, y es una cuestión de estilo, pero prefiero los constructores para la inicialización de miembros.

+3

Realmente no considero que dar un valor predeterminado sea una parte de la construcción de un objeto. Pero como dices, es una cuestión de estilo. –

+0

Tienen valor predeterminado ... no es necesario iniciarlos OTRA VEZ –

2

Creo que ambos son correcta programación inteligente,

Pero creo que su primera opción es más correcto de una manera orientada a objetos, ya que en el constructor es cuando se crea el objeto, y es cuando la variable debe inicializado .

Creo que es la convención "por libro", pero está abierta a discusión.

Wikipedia

4

Si inicializa en la parte superior o en el constructor que no hace mucha diferencia .Pero en algún caso inicializar en el constructor tiene sentido.

class String 
{ 
    char[] arr/*=char [20]*/; //Here initializing char[] over here will not make sense. 
    String() 
    { 
     this.arr=new char[0]; 
    } 
    String(char[] arr) 
    { 
     this.arr=arr; 
    } 
} 

Así que dependiendo de la situación en algún momento tendrá que inicializar en la parte superior y, a veces en un constructor.

otra opción de FYI para la inicialización sin necesidad de utilizar un constructor:

class Foo 
{ 
    int i; 
    static int k; 

    //instance initializer block 
    { 
     //run's every time a new object is created 
     i=20; 
    } 

    //static initializer block 
    static{ 
     //run's only one time when the class is loaded 
     k=18; 
    }  
} 
2

Tanto las opciones puede ser correcto dependiendo de su situación.

Un ejemplo muy simple sería: Si tiene múltiples constructores, todos inicializan la variable de la misma manera (int x = 2 para cada uno de ellos). Tiene sentido inicializar la variable en la declaración para evitar la redundancia.

También tiene sentido considerar las variables finales en tal situación. Si conoce el valor que tendrá una variable final en la declaración, tiene sentido inicializarla fuera de los constructores.Sin embargo, si desea que los usuarios de su clase inicialicen la variable final a través de un constructor, demore la inicialización hasta el constructor.

+0

+1 para las variables finales. Me encantan las clases immmutable :-). – sleske

4

Una cosa, independientemente de cómo inicialice el campo, el uso del calificador final, si es posible, garantizará la visibilidad del valor del campo en un entorno de subprocesos múltiples.

+1

¿De verdad? Creo que la palabra clave final no tiene impacto en la visibilidad cuando hablamos de campos de instancia. Una historia diferente sería campos temporales (definidos dentro de un método), entonces estaría de acuerdo contigo. Pero por favor dé un ejemplo si me falta algo. – bvdb

+0

Esto está bien, pero ¿qué tiene esto que ver exactamente con la pregunta? La pregunta a su respuesta sería: "¿Cómo debo declarar mis campos y por qué?" – nbro

0

Yo diría que depende por defecto. Por ejemplo

public Bar 
{ 
    ArrayList<Foo> foos; 
} 

Me gustaría hacer un new ArrayList fuera del constructor, si yo siempre asumo foos no puede ser nulo. Si Bar es un objeto válido, sin importar si foos es nulo o no, lo pondré en el constructor.

Puede estar en desacuerdo y decir que es el trabajo de los constructores poner el objeto en un estado válido. Sin embargo, si claramente todos los constructores deberían hacer exactamente lo mismo (inicializar foos), ¿por qué duplicar ese código?

14

Tengo la práctica (hábito) de casi siempre inicializar en el contructor por dos razones, una en mi opinión se agrega a readablitiy (limpiador), y dos hay más control lógico en el constructor que en una línea. Incluso si inicialmente la variable de instancia no requiere lógica, tenerla en el constructor le da más flexibilidad para agregar lógica en el futuro si es necesario.

En cuanto a la preocupación mencionada anteriormente sobre constructores múltiples, eso se resuelve fácilmente teniendo un constructor no-arg que inicializa todas las variables de instancia que se inician igual para todos los constructores y luego cada constructor llama this() en la primera línea . Eso resuelve sus problemas de reduncancia.

1

Puede depender de lo que está inicializando, por ejemplo, no puede usar la inicialización de campo si se trata de una excepción marcada. Por ejemplo, los siguientes:

public class Foo { 
    FileInputStream fis = new FileInputStream("/tmp"); // throws FileNotFoundException 
} 

causará un error en tiempo de compilación, a menos de que también incluyen un constructor declarando que excepción revisada, o ampliación de una superclase, que hace, por ejemplo:

public Foo() throws FileNotFoundException {} 
Cuestiones relacionadas