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明确声明月份时,月份是非静态变量。
答案 0 :(得分:6)
您无法在静态上下文中使用this
。这是设计 - this
指的是对象而不是类。如果您遇到方法参数和字段之间可能存在名称冲突的问题,则可以改为使用类名:
public static void setMonth(int month)
{
Date.month = month;
}
另一方面,您可以考虑您的设计并重新考虑将整个班级用作单个对象的决定。
答案 1 :(得分:4)
这指的是当前实例。静态方法与实例无关;他们与班级有联系。
这个例子是个坏主意。任何了解java.util.Date
和java.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实例,将其月份分配给不同的值,并单独使用它们。但是,如果修饰符是静态的,则该类的所有实例以及“访问修饰符”允许的任何类都可以访问该值,其范围超出了此讨论范围。