Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why must I use the "this" keyword for forward references?

When I use the this keyword for accessing a non-static variable in a class, Java doesn't give any error. But when I don't use it, Java gives an error. Why must I use this?

I know when should normally I use this, but this example is very different from normal usages.

Example:

class Foo { //  int a = b; // gives error. why ?     int a = this.b; // no error. why ?     int b;     int c = b;      int var1 = this.var2; // very interesting     int var2 = this.var1; // very interesting } 
like image 944
Nomad Avatar asked Oct 27 '17 04:10

Nomad


People also ask

What is the this reference Why would you use it?

The this keyword refers to the current object in a method or constructor. The most common use of the this keyword is to eliminate the confusion between class attributes and parameters with the same name (because a class attribute is shadowed by a method or constructor parameter).

What does the this reference do?

The this is a keyword in Java which is used as a reference to the object of the current class, with in an instance method or a constructor. Using this you can refer the members of a class such as constructors, variables and methods.

What is meant by forward reference?

A forward reference occurs when a label is used as an operand, for example as a branch target, earlier in the code than the definition of the label. The assembler cannot know the address of the forward reference label until it reads the definition of the label.

What is meant by a forward reference in C?

Forward reference is when you declare a type but do not define it. It allows you to use the type by pointer (or reference for C++) but you cannot declare a variable. This is a way to say to the compiler that something exists. Say that you have a Plop structure defined in Plop.


2 Answers

The full description is in section 8.3.3 of the Java Language Specification: "Forward References During Field Initialization"

A forward reference (referring to a variable that is not declared yet at that point) is only an error if the following are all true:

  • The declaration of an instance variable in a class or interface C appears textually after a use of the instance variable;

  • The use is a simple name in either an instance variable initializer of C or an instance initializer of C;

  • The use is not on the left hand side of an assignment;

  • C is the innermost class or interface enclosing the use.

See the bolded text: "the use is a simple name". A simple name is a variable name without further qualification. In your code, b is a simple name, but this.b is not.

But why?

The reason is, as the cursive text in the example in the JLS states:

"The restrictions above are designed to catch, at compile time, circular or otherwise malformed initializations. "

In other words, they allow this.b because they think that a qualified reference makes it more likely that you have thought carefully about what you're doing, but simply using b probably means that you made a mistake.

That's the rationale of the designers of the Java Language. Whether that is true in practice has, to my knowledge, never been researched.

Initialization order

To expand on the above, in reference to Dukeling's comment on the question, using a qualified reference this.b will likely not give you the results you want.

I'm restricting this discussion to instance variables because the OP only referred to them. The order in which the instance variables are assigned is described in JLS 12.5 Creation of New Class Instances. You need to take into account that superclass constructors are invoked first, and that initializations code (assignments and initialization blocks) are executed in textual order.

So given

int a = this.b; int b = 2; 

you will end up with a being zero (the value of b at the time that a's initializer was executed) and b being 2.

Even weirder results can be achieved if the superclass constructor invokes a method that is overridden in the subclass and that method assigns a value to b.

So, in general, it is a good idea to believe the compiler and either reorder your fields or to fix the underlying problem in case of circular initializations.

If you need to use this.b to get around the compiler error, then you're probably writing code that will be very hard to maintain by the person after you.

like image 51
Erwin Bolwidt Avatar answered Oct 04 '22 06:10

Erwin Bolwidt


Variables are declared first and then assigned. That class is the same as this:

class Foo {     int a;     int b;     int c = b;      int var1;     int var2;      public Foo() {         a = b;          var1 = var2;         var2 = var1;     } } 

The reason you can't do int a = b; is because b is not yet defined at the time the object is created, but the object itself (i.e. this) exists with all of its member variables.

Here's a description for each:

    int a = b; // Error: b has not been defined yet     int a = this.b; // No error: 'this' has been defined ('this' is always defined in a class)     int b;      int c = b;  // No error: b has been defined on the line before   
like image 28
Jason Avatar answered Oct 04 '22 07:10

Jason