• Post Reply Bookmark Topic Watch Topic
  • New Topic

Question regarding this keyword in Java  RSS feed

 
Vaibhav Sagar
Ranch Hand
Posts: 35
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi, I have a confusion regarding the "this" keyword. I don't understand why the below code runs. Aren't instance variables intialised before the constructor runs?



JSE does indeed say "The keyword this may be used only in the body of an instance method, instance initializer, or constructor, or in the initializer of an instance variable of a class. If it appears anywhere else, a compile-time error occurs.". But how does it actually work out?

Thanks.
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Vaibhav Sagar wrote:Hi, I have a confusion regarding the "this" keyword. I don't understand why the below code runs. Aren't instance variables intialised before the constructor runs?



JSE does indeed say "The keyword this may be used only in the body of an instance method, instance initializer, or constructor, or in the initializer of an instance variable of a class. If it appears anywhere else, a compile-time error occurs.". But how does it actually work out?

Thanks.

According to the JLS, initialization of instance variables takes place during constructor execution, after this() / super() have been called and before any other explicit statements defined in the constructor are executed.
https://docs.oracle.com/javase/specs/jls/se8/html/jls-12.html#jls-12.5

 
Vaibhav Sagar
Ranch Hand
Posts: 35
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Got it. Thanks Steffe.
 
Campbell Ritchie
Marshal
Posts: 56529
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
What's JSE? Do you mean the JLS = Java® Language Specification?
 
Fred Kleinschmidt
Bartender
Posts: 571
9
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The 'this' keyword should never be used this way when initializing instance variables. Consider:

The problem is that the instance is not fully complete before the constructor finishes, so this.xxx() may try to reference things that are not yet initialized.
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Fred Kleinschmidt wrote:The 'this' keyword should never be used this way when initializing instance variables. [...]
The problem is that the instance is not fully complete before the constructor finishes, so this.xxx() may try to reference things that are not yet initialized.

Perhaps worthy of a further clarification...

The JLS says (section 8.6):
Instance initializers are permitted to refer to the current object via the keyword this (§15.8.3), to use the keyword super (§15.11.2, §15.12), and to use any type variables in scope.

but continues:
Use of instance variables whose declarations appear textually after the use is sometimes restricted, even though these instance variables are in scope.

So its the forward reference that is the cause of the problem here, rather than the use of this per se. If you swap over the declarations of str and str2 it would work as expected. But I take your point.

http://docs.oracle.com/javase/specs/jls/se8/html/jls-8.html#jls-8.6

 
Vaibhav Sagar
Ranch Hand
Posts: 35
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Now I figured out what exactly I am stuck at . The thing is if the instance variables are intialised before the constructor finishes, then how does the intialisation process deals with the "this" reference since the object itself is not yet created?
For e.g., if I run the following code, then I get the output as Prac@12345678 which means that the object has already been created(but the constructor is not yet complete! )-



I do understand that "this" is a reference and we can use it inside constructors(to call one constructor from the other). But I never realised that "this" would return an actual object even before the constructor completes and this is what I am confused with.

Thanks.
 
Steffe Wilson
Ranch Hand
Posts: 165
12
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Object creation isn't a "big bang" whereby a fully formed object suddenly appears out of nothing, instead there are discrete steps involved in the process.
A bare-bones object is created first when memory is allocated to it (which means that this has a value) and then various actions take place to fully form the object including the steps quoted above for setting up instance variables, running constructors, etc.
 
Campbell Ritchie
Marshal
Posts: 56529
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Which is why you should never try to use an object until the constructor completes. One way to use an object before the constructor completes is to pass the keyword this to methods; that can actually cause incomplete data to be copied from a half‑created object. I once saw an example rather like this on this forum:-I am not going to look for it and embarrass whoever wrote that. I am however going to challenge you to find the other potentially serious error in that constructor.
 
Vaibhav Sagar
Ranch Hand
Posts: 35
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Campbell,

Is the serious error a logical issue that the call "sch.registerPupil(this);" should be done after the constructor and instead of using "this" the new object's reference should had been passed? I say this because that line has no reason for being inside the constructor of Pupil(its not in anyway contributing to the intialisation of Pupil).

Code should had been this-


If that is not the error then could you please give a hint ?

Thanks.
 
Campbell Ritchie
Marshal
Posts: 56529
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That is the serious logical error I was telling you about, but not the challenge. Your solution gives the right concept for curing that problem, but needs a bit of polishing before it can compile.
The challenge was to find the other potential logical error .
 
Fred Kleinschmidt
Bartender
Posts: 571
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hint: String instances are immutable, so there is no problem with "this.name = name;"
 
Vaibhav Sagar
Ranch Hand
Posts: 35
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hmm. I think the issue is then with passing the object to another Object that can manipulate the instance variables of Prac before even the constructor completes. It might even throw an exception and we might end up with an object that never got fully created.
 
Campbell Ritchie
Marshal
Posts: 56529
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
That is the same error as you found yesterday; there is another error in that constructor which FK hinted at.
 
Vaibhav Sagar
Ranch Hand
Posts: 35
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Oh. Then I guess I am not able to find it. Might be something so obvious that I am unintentionally ignoring it or might be that I am just not aware about it .
 
Junilu Lacar
Sheriff
Posts: 11477
180
Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Aren't you guys being a little rough on newbie OP there? I don't see there being a "serious error" per se but rather a risk that is nuanced by whatever the registerPupil() method does. Is OP really there yet? If so, then maybe this thread doesn't belong in Beginning Java.
 
Fred Kleinschmidt
Bartender
Posts: 571
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The problem is not in whatever registerPupil() might do. it is in what any instance method of Pupil might do that could effect things outside of Pupil, and/or what the caller of the Pupil constructor might do afterwards that can inadvertently change the Pupil instance without even referencing that instance.
 
Vaibhav Sagar
Ranch Hand
Posts: 35
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi Fred, could please give an example to elaborate it? I am still confused
 
Campbell Ritchie
Marshal
Posts: 56529
172
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
OP had no difficulty finding the error about the escaping this reference, Junilu. But there is another potential error which we hoped he would find.Most of that code is real. Only one line is spoof. I challenge you:-
  • 1: to work out what line 7 will print.
  • 2: why this occurs.
  • 3: a solution.
  •  
    Campbell Ritchie
    Marshal
    Posts: 56529
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    And forget that the Date() constructor is deprecated. That doesn't count as part of the error, but some solutions will get rid of that constructor.
     
    Vaibhav Sagar
    Ranch Hand
    Posts: 35
    2
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Ok. I knew this one already, just didn't guess that's what was being asked about. Now I understand why the hint was about String class being immutable
    1. Line 7 will print the modified date.
    2. Because we still have a reference to the object that was passed to the constructor.
    3. Creating a new date inside the constructor or not providing a constructor that takes in a Date in the first place(instead forcing the user to use the setDateOfBirth method which in turn creates a new Date). Solution-
     
    Dave Tolls
    Ranch Foreman
    Posts: 3056
    37
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Or ditch Date entirely and use something like LocalDate from the new date API, which is immutable.
     
    Campbell Ritchie
    Marshal
    Posts: 56529
    172
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Vaibhav Sagar wrote: . . .
    1. Line 7 will print the modified date.
    More likely that the little girl is now 60 years old
    2. Because we still have a reference to the object that was passed to the constructor.
    3. Creating a new date inside the constructor or not providing a constructor that takes in a Date in the first place(instead forcing the user to use the setDateOfBirth method which in turn creates a new Date). . . .
    Spot on.
    No 3 is what Joshua Bloch calls taking a defensive copy. You cannot force the user to use the setDOB method, so that solution would leave the object in an inconsistent state, lacking an age. Your copying technique is exactly what Bloch suggests.
    Now the LocalDate class is available, Dave Tolls is right; in fact some people could have said that using Date at all is an error. As DT says, all the new date‑time classes create immutable objects, so they are thread‑safe, as well as not requiring copying.
     
    Junilu Lacar
    Sheriff
    Posts: 11477
    180
    Android Debian Eclipse IDE IntelliJ IDE Java Linux Mac Spring Ubuntu
    • Mark post as helpful
    • send pies
    • Quote
    • Report post to moderator
    Ok, so any modification, whether it be in the called method or in the caller of this method. That all has to do with breaking encapsulation though with goes back to my point that there are nuances that are probably beyond "beginner" level, despite OP being able to figure out the challenge. Besides, the issue of side effects and breaking encapsulation seems to be a digression from the original question regarding how this works in a constructor and/or instance initialization. Just sayin'. ¯\_(ツ)_/¯
     
    • Post Reply Bookmark Topic Watch Topic
    • New Topic
    Boost this thread!