2014-01-07 32 views
7
public class Test { 
    int value = 100; 
    public Test() { 

    } 
} 

而且在构造函数内部或外部设置字段是否有区别?

public class Test { 
    int value; 
    public Test() { 
     value = 100; 
    } 
} 

是等价的,对不对?为什么我更喜欢做另一个呢?显然,如果构造函数需要稍后给出的参数,那么这是一个原因:

public class Test { 
    int value; 
    public Test(int value) { 
     this.value = value; 
    } 
} 

或者我可能需要做一些特殊的计算。

但是,如果我不要这样做,是否有另一个很好的理由?

+2

这些都是场,而不是属性。 – SLaks

+0

必须仔细考虑您的范围。 –

+1

字段在执行构造函数的主体之前被初始化。如果你需要在你的构造函数中泄漏'this'引用(不要,但是如果你需要的话),最好在其声明中而不是在构造函数中初始化该字段,以便获取该引用的人不会“ t看到一个完全单元化的状态。 –

回答

1

场的初始化代码复制到每个构造......如果你有多个构造函数,并希望在每个相同的值初始化的字段(甚至只是大多数),那么这将是更好的声明和覆盖初始化在构造函数中的值。

+2

或者只是使用构造函数链。 –

0

如果你没有进行任何计算或者没有采用任何参数,那么无论你是初始化还是不初始化构造函数中的那些变量,上述二者都没有区别。

如果声明他们作为第一个像你这样的声明:

public class Test { 
    int value = 100; 
    public Test() { 

    } 
} 
  • 这将是更可读的格式为你分配他们直接的价值,无需从构造查看。

  • 它会更好如果你有多个构造函数,你不必重复初始化(并且你不能忘记它们)。

0

无论什么时候创建类,构造函数都会首先被初始化。所以,当你在构造函数中声明或定义一个变量时,首先将内存分配给该变量,然后该过程将继续。

1

嗯,这取决于。

对于第二种情况,将value被填充的0with its default value,只在实例化与100重新分配。在第一种情况下,value立即给出值100。从语义上讲,这将对程序员有所帮助 - 他们会发现,这个特定的值意味着更多的东西,而不仅仅是任意的(尽管它应该是应该是一个常数值的地方)。

以编程方式,如果将某个基元设置为某个初始值,则不会有任何痛苦。这意味着有东西在那里供您使用,如果您的程序取决于有一个非负值或错误的值,乔治将工作

事情在处理对象引用时变得更加明确。举个例子,这两个类:

public class Foo { 
    List<String> elements; 
    public Foo() { 
    } 

    public Foo(String... items) { 
     elements = new ArrayList<>(); 
     for(String item : items) { 
      elements.add(item); 
     } 
    } 
} 

public class Bar { 
    List<String> elements = new ArrayList<>(); 
    public Bar() { 
    } 

    public Bar(String... items) { 
     for(String item : items) { 
      elements.add(item); 
     } 
    } 
} 

有故意无参构造函数来费尽点 - 为Foo,如果我尝试使用elements,然后我在,如果我有点麻烦不要使用适当的构造函数 - elementsnull!*我可能然后只是在我需要它的时候实例化它,但我非常想避免销毁一个潜在的新的和填充的列表。

这意味着大量的代码看起来像这样:

if(elements == null) { 
    elements = new ArrayList<>(); 
} 

...然后我担心它是线程安全的。 Sheesh,谈论一下麻烦。

随着Bar,我保证,在实例,有在elements列表的一个实例,所以我不担心它是null。**

这是称为渴望实例化。你真的不希望没有那个对象,所以为什么要等到你认为你需要它(或者懒惰实例化)?

*:default value for all reference typesnull

**:你担心的是被改写,但是这是这个问题的范围之外的问题。

4

那么这一切都取决于你打算如何使用它。我会假设你不打算让value为静态,但它只是为了内部目的。

首先让我们看看字节码。

D:\eclipse\workspace\asdf\bin>javap -c A.class 
Compiled from "A.java" 
public class A { 
    int value; 

    public A(); 
    Code: 
     0: aload_0 
     1: invokespecial #10     // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: bipush  100 
     7: putfield  #12     // Field value:I 
     10: return 
} 

D:\eclipse\workspace\asdf\bin>javap -c B.class 
Compiled from "B.java" 
public class B { 
    int value; 

    public B(); 
    Code: 
     0: aload_0 
     1: invokespecial #10     // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: bipush  100 
     7: putfield  #12     // Field value:I 
     10: return 
} 

D:\eclipse\workspace\asdf\bin> 

猜猜是什么?一模一样!为什么?因为在使用new关键字创建对象之前,您无法使用值。

oracle docs指出:

正如你所看到的,你通常可以为现场 在其声明中提供的初始值:

public class BedAndBreakfast { 
    // initialize to 10 
    public static int capacity = 10; 

    // initialize to false 
    private boolean full = false; 
} 

这种运作良好,当初始化值是可用的,初始化可以放在一行上 。但是,这种初始化形式有其局限性,因为它的简单性是 。如果初始化需要某些逻辑(例如, 错误处理或for循环填充复杂数组),则简单的 赋值是不充分的。实例变量可以在 构造函数中初始化,其中可以使用错误处理或其他逻辑。对于 为类变量提供相同的功能,Java编程 语言包括静态初始化块。

所以,现在你必须确认的是,在构造函数中做它的全部意义在于,如果你正在做的事情复杂像初始化数组,否则随时把事情做对那里当你声明的领域。

如果你要使用static那么你明显在做两件不同的事情。这几乎就像一个检查,看看是否有人创建过这个对象的实例。你的变量应该是0,直到有人创建了一个对象,然后在100之后。

0

目前在你的例子中,只有一个字段,你决定哪种初始化方式比其他方式更好。

但是,如果通过初始化很多字段(比如30或40)来增加复杂性,那么它确实会产生很大的差异。

在这种情况下,请考虑什么Joshua Bloch has to say on initializing through constructors

下面是总结,

  1. telescoping constructor pattern的作品,但它是很难写 客户端代码时,有很多参数,并且更难阅读 它。
  2. 的解决方案是,其中,代替直接在所需的对象使得 ,客户端调用一个构造(或 静态工厂)的所有必需的参数的,并得到一个 生成器对象生成器图案的一种形式。
0

我说的不是字节码,但他们可以在语义上的不同(如果你有多个构造函数),

字段将总是被初始化为100,如果你把它定义为以下,不管哪个构造函数被称为:

int field = 100; 

但除此之外,你应该初始化每个构造函数中的字段。

你的类可能只有一个构造函数,但只是想,在你的类的未来版本中是否还有其他构造函数?

0
public class Test { 
    int value = 100; 
    public Test() { 

    } 
} 

这种运作良好,当初始化值可用,你可以声明,并在同一行初始化场。但是,这种初始化形式由于其简单性而具有局限性。如果初始化需要一些逻辑(例如,错误处理或验证或条件),则简单分配是不充分的。当您使用构造函数初始化时,您可能会执行错误处理或其他逻辑。为了为类变量提供相同的功能,Java编程语言包括静态初始化块。也有另一种两种方法来初始化实例变量:

  1. 初始化语句块

    {// 初始化 }

  2. 最终方法

    class Foo{ 
        int age=initAge(); 
    
        protected int initAge(){ 
        //initialization code 
        } 
    } 
    
相关问题