主类范围中不允许方法调用

时间:2013-05-23 18:18:04

标签: java

为什么我允许在类范围中实例化字段但不允许在这些字段上调用方法?

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);
}
}

我经常发现例如使用一些默认值启动列表是有意义的,如果我的类中有多个构造函数,我必须在构造函数中添加默认值或使用代码中标记为下面的丑陋方式。 “丑陋”的方式适用于列表,但对于需要我的类的默认状态的其他对象(对象构造函数未提供的状态)我必须使用私有帮助器方法。我想知道为什么我不能在课堂上这样做,不一定是一个巨大的不便,但我很好奇为什么。

3 个答案:

答案 0 :(得分:6)

  

为什么我不能这样做?

直接的答案是:因为在Java语言规范中这样指定:

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

instance initializer。这只是一个代码块,它在创建类的实例时执行,它可以包含任何真正的java代码。

另一方面,

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

initializer for instance variables

如果你问“为什么语言规范不允许在类范围内执行java代码而不将其放入初始化程序块”,我会说,从技术上说它是可能的,但是这样的代码将很难读取和维护 - 您最终可以将实例变量声明与任何其他Java代码混合。使用实例初始化程序时,正好有一个代码块,在创建对象时就像普通方法一样执行。

请注意,加载类时还会执行static initializers - 语法为:

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

如果您能够将任何java代码与实例变量声明混合,则需要另一种语法来决定是否在类或实例初始化期间执行代码。

答案 1 :(得分:1)

您的实现使用称为实例初始化程序的东西。据我所知,Java的创建者使其更容易阅读。分离变量声明和初始化可以使类的开头的声明更容易阅读。

答案 2 :(得分:0)

为什么你不能在下面的块中调用addObject()?

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);
}
}