为什么在引用静态方法中的字段时我不能使用关键字“this”?

时间:2013-03-23 23:49:15

标签: java compiler-errors

public class Date
{

static int month; 

public static void setMonth(int x)
{ 
 this.month = x;  //compiler error
}

public static int getMonth()
{
 return month;  //compiles just fine, no error
}

}

编译时,我收到错误:非静态变量,无法从静态上下文引用。 但是,如果我删除“这个”。没有错误。 我不明白为什么当我使用关键字static明确声明月份时,月份是非静态变量。

4 个答案:

答案 0 :(得分:6)

您无法在静态上下文中使用this。这是设计 - this指的是对象而不是类。如果您遇到方法参数和字段之间可能存在名称冲突的问题,则可以改为使用类名:

public static void setMonth(int month)
{ 
 Date.month = month; 
}

另一方面,您可以考虑您的设计并重新考虑将整个班级用作单个对象的决定。

答案 1 :(得分:4)

这指的是当前实例。静态方法与实例无关;他们与班级有联系。

这个例子是个坏主意。任何了解java.util.Datejava.sql.Date的人都会感到困惑。

答案 2 :(得分:2)

考虑这种情况:

class ParaentClass {

  public static final int SOME_VALUE = 7;

  public modValue(int m) {
    // WRONG
    return this.SOME_VALUE % m;
  }

}

class ChildClass extends ParentClass { }

// . . .

(new ChildClass()).modValue(4);

在上面的代码中,当我们调用modValue时,this实际上是ChildClass的实例,而不是ParentClass的实例,所以当JVM执行方法时甚至不知道在哪个类中寻找静态字段。我想JVM可以做一些事情,比如爬过继承层次结构寻找最接近的匹配静态字段 - 但这会产生糟糕的性能。

无论如何,他们决定为static定义语义的方式是它们与一个类相关联,并且它们不能被覆盖。因此,只有通过类名(例如ParentClass.SOME_VALUE)引用它们才有意义,而不是通过引用this之类的实例来引用它们。

如果静态变量当前在范围内,则 允许忽略类名:

  public modValue(int m) {
    // CORRECT
    return ParentClass.SOME_VALUE % m;
  }

  public modValue(int m) {
    // ALSO CORRECT
    return SOME_VALUE % m;
  }

答案 3 :(得分:2)

在Java中,您可以选择在类中创建静态或非静态字段。

当一个字段是静态的时,你不需要“实例化”该类的“实例”来引用它。

在您的示例中,我可以从另一个类的同一个包中访问“month”变量(因为您没有“访问修饰符”,Java使该变量“package-private” - 隐藏到每个类除了在同一目录(Java术语中的包)中的那些,通过执行以下操作:

public class Example {
    void outputMonth() {
         System.out.println("This is the month: " + Date.month);
    }
}

但是,如果删除静态修饰符,则“月”不会简单地附加到类。它属于该类的每个“实例”。使用您当前的程序版本,我可以将“month”移动到Example类,并使用Example.month而不是month来使用Date引用它,它将以完全相同的方式工作。

要“实例化”类的“实例”,请使用“new”关键字:

public class Example {
    void instantiateAndDisplay() {
         Date newInstance = new Date();
         System.out.println("This won't be pretty, but it's a new Date: " + newInstance);
    }
 }

现在,如果从“月”中删除静态关键字,则每个日期“实例”都有自己的月份变量副本,可以单独更改。两次调用new会产生两个实例,三个调用,三个实例,等等。

如果这更清楚一点,那么编译器警告你“this”的原因是“this”是当前实例的抓包术语。由于您将该方法设为静态,因此没有实例 - 该代码附加到该类,但可以将其移动到Example类,Date可以通过调用Example.setMonth(month)来使用它;

定义“this”的原因是范围有时是模棱两可的。在你的setMonth示例中,如果从所有方法中删除了static修饰符,则可以将局部变量从“x”重命名为“month”,但如果没有这个,您所做的只是将从其自身传入的局部变量月份分配给本身,什么都不做。 “this”将“month”的范围定义为“Date类的当前实例”,然后允许您分配它,如下例所示:

public class Date {
    private int month;
    public void setMonth(int month) {
        this.month = month;
    }
    public void getMonth() {
        return month; // Note - no competing scope, so month comes from the current instance.
    }
 }

然后,您可以创建两个新的Date实例,将其月份分配给不同的值,并单独使用它们。但是,如果修饰符是静态的,则该类的所有实例以及“访问修饰符”允许的任何类都可以访问该值,其范围超出了此讨论范围。