2

Why am I allowed to instantiate fields in the class scope but not allowed to call methods on those fields?

public class MethodInFieldTest {
List<Object> list = new ArrayList<>();

// compilation error
// list.add(new Object());

// Compiles just fine, how I usually do it
{
    list.add(new Object());
}

// compilation error
// addObject();

public void addObject() {
    list.add(new Object());
}


//usual way of handling this
//constructor one
public MethodInFieldTest(... stuff) {
    list.add(new Object());
}

//constructor two
public MethodInFieldTest(..) {
    list.add(new Object());
}

//etc

//...

//ugly way of doing it
//  List<Object> list = new ArrayList<>(Arrays.asList(new Object[]{new Object(), new Object()}));

public static void main(String[] args) {
    System.out.println(new MethodInFieldTest().list);
}
}

I often find it makes sense to for instance start a list with some default values and if I have multiple constructors in my class I have to add the default values in the constructors or use the ugly way marked below in the code. The "ugly" way works for lists but for other objects that need a default state for my class (a state not provided by the objects constructor) I have to use private helper methods. I wonder why I can't just do it in the class field, not necessarily a huge inconvenience but I am curious as to why.

4

3 回答 3

6

Why can't I do it?

The straight answer is: because it is specified like this in the Java Language Specification:

{
    list.add(new Object());
}

is an instance initializer. This is simply a code block which is executed when an instance of the class is created, and it can contain any real java code.

On the other hand,

List<Object> list = new ArrayList<>();

is an initializer for instance variables.

If you are asking "why does the language spec not allow to execute java code at the class scope without putting it into the initializer block", I would say, technically it would be possible, but such code would be very hard to read and maintain - you would end up with the possibility to mix instance variable declarations with any other Java code. With the instance initializer, there is exactly one code block which gets executed, just like a normal method, when the object is created.

Note that there are also static initializers which are executed when the class is loaded - their syntax is:

static {
    // Java code
    // ...
}

If you would be able to mix any java code with instance variable declarations, you would need yet another syntax to decide whether the code shall be executed during class- or instance initialization.

于 2013-05-23T18:25:43.367 回答
1

Your implementation uses something called an instance initializer. As far as I can tell, the creators of Java made it that way to make it easier to read. Separating the variable declarations and the initializations can make the declarations at the beginning of the class easier to read through.

于 2013-05-23T18:30:05.667 回答
0

Why cant you call addObject() within the block like below?

public class MethodInFieldTest {
List<Object> list = new ArrayList<>();

// compilation error
// list.add(new Object());

// Compiles just fine, how I usually do it
{
    //list.add(new Object());
    addObject();

}

// compilation error
// addObject();

public void addObject() {
    list.add(new Object());
}


//usual way of handling this
//constructor one
public MethodInFieldTest(... stuff) {
    //list.add(new Object());
}

//constructor two
public MethodInFieldTest(..) {
    //list.add(new Object());
}

//etc

//...

//ugly way of doing it
//  List<Object> list = new ArrayList<>(Arrays.asList(new Object[]{new Object(), new Object()}));

public static void main(String[] args) {
    System.out.println(new MethodInFieldTest().list);
}
}
于 2013-05-23T18:41:59.433 回答