Why can't I use the keyword “this” when referr

2019-07-17 16:03发布

问题:

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
}

}

When compiling, I receive the error: non-static variable this cannot be referenced from a static context. However, if I remove "this." there is no error. I don't understand why it's saying month is a non-static variable when I clearly declared it using the keyword static.

回答1:

You simply can't use this in a static context. That is by design - this refers to the object not the class. If you are having problems with possible name clashes between method parameters and fields you can use the class name instead:

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

On the other hand you could think about your design and rethink the decision to use the whole class as one singleton object.



回答2:

this refers to the current instance. static methods aren't associated with instances; they're associated with the class.

This example is a bad idea. You'll confuse anyone who knows about java.util.Date and java.sql.Date.



回答3:

Consider this case:

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

In the above code, when we call modValue, this is actually an instance of ChildClass, not of ParentClass, so when the JVM is executing the method it wouldn't even know on which class to look for the static field. I suppose the JVM could do something like climb through the inheritance hierarchy looking for the closest matching static field—but that would have terrible performance.

Anyway, the way they decided to define the semantics for static is that they are associated with a class, and they can't be overridden. Therefore, it only makes sense to refer to them by class name (e.g. ParentClass.SOME_VALUE), not by a reference to an instance like this.

You are allowed to elide the class name if the static variable is currently in scope:

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

or

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


回答4:

In Java, you have a choice of making a field static or non-static within a class.

When a field is static, you don't need to "instantiate" an "instance" of that class to reference it.

In your example, I could access the "month" variable from within the same package in another class (since you don't have an "access modifier", Java makes that variable "package-private" - hidden to every class except ones in the same directory (package in Java terms)) by doing the following:

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

But, if the static modifier is removed, then "month" isn't simply attached to the class. It belongs to each "instance" of the class. With your current version of the program, I could move "month" to the Example class and have Date reference it with Example.month instead of month and it would work exactly the same way.

To "instantiate" an "instance" of a class, you use the "new" keyword:

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

Now, if the static keyword is removed from "month", each Date "instance" has its own copy of the month variable which can be changed independently. Two calls to new make two instances, three calls, three instances, and so on.

If that's a bit clearer, then the reason for the compiler warning you about "this" is that "this" is a grab bag term for the current instance. Since you made that method static, there is no instance - that code is attached to the class, but it could be moved to the Example class and Date could use it by calling Example.setMonth(month);

The reason "this" is defined is that scope is sometimes ambiguous. In your setMonth example, if you removed the static modifier from all methods, you could rename the local variable from "x" to "month", but without this, all you're doing is assigning the local variable month passed in from itself to itself, which does nothing. "this" defines the scope of "month" to mean "the current instance of the Date class" which then allows you to assign it, as shown in this example:

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.
    }
 }

You can then create two new Date instances, assign their months to different values, and use them independently. But if the modifier is static, that value is accessible to all instances of that class, and any classes allowed by the "access modifier", the scope of which is beyond this discussion.