If I write the following class:
public class Example {
int j;
int k;
public Example(int j, int k) {
j = j;
k = k;
}
public static void main(String[] args) {
Example exm = new Example(1,2);
System.out.println(exm.j);
System.out.println(exm.k);
}
}
The program compiles, but when I run the program, the main method will print out two 0s. I know that in order to say that I want to initialize the instance variables in the constructor I have to write:
this.j = j;
this.k = k;
But if I don't write it, then which variable is evaluated (or considered) in the constructor (on the left and on the write hand side of the expressions)? Is is the argument or the instance variable? Does it make a difference?
Are there other cases where the use of this is obligatory?
If you don't write "this.variable" in your constructor, and if you have a local variable (including the function parameter) with the same name as your field variable in the constructor, then the local variable will be considered; the local variable shadows the field (aka class variable).
One place where "this" is the only way to go:
class OuterClass {
int field;
class InnerClass {
int field;
void modifyOuterClassField()
{
this.field = 10; // Modifies the field variable of "InnerClass"
OuterClass.this.field = 20; // Modifies the field variable of "OuterClass",
// and this weird syntax is the only way.
}
}
}
If you say just j in your constructor then the compiler will think you mean the argument in both cases. So
j = j;
simply assigns the value of the argument j to the argument j (which is a pretty pointless, but nonetheless valid statement).
So to disambiguate this you can prefix this. to make clear that you mean the member variable with the same name.
The other use of this is when you need to pass a reference to the current object to some method, such as this:
someObject.addEventListener(this);
In this example you need to refer to the current object as a whole (instead of just a member of the object).
If you don't write this, then you assign the argument to itself; the argument variables shadow the instance variables.
this is useful when you want to return the object itself
return this;
This is useful because if a class has for example Method1() and Method2(), both returning this, you are allowed to write calls like
object.Method1().Method2()
Also inside a method it can be useful to pass the object itself to another function, during a call.
Another useful approach (though seldom used) is to declare method parameters final:
The following block will not compile, thus alerting you to the error immediately:
public Example(final int j, final int k) {
j = j;
k = k;
}
In your constructor code, you are assigning variables to themselves. 'j' is the j specified in the argument for the constructor. Even if it was the class variable j defined above, then you are still saying "j = j" ... i.e. j isn't going to evaluate differently on the left and on the right.
public Example(int j, int k) {
this.j = j;
this.k = k;
}
What you are experiencing is called variable shadowing. Have a look at this overview for different kinds of variables in Java.
Generally speaking: The Java compiler uses the nearest variable it can find for an assignment. In a method it will first try to find a local variable and then enlarge the focus of its search to class and instance variables.
One habit I personally find good (others don't like it) is prefixing a member variable with m_ and using uppercase for CONSTANT_VARIABLES that don't change their value. Code where variable shadowing is used on purpose is very(!) difficult to debug and work with.
You assign the parameter to itself in your example.
More generally speaking: If you don't prepend a scope to your variable, the current scope is assumed - which is the function in your case. 'this.j' tells the jre to use the variable j within the object scope - the member variable of the object.
Just like Robert Grant said, 'this' is how you make it clear that you are referring to a member variable instead of a local variable.
To answer your follow-up question about this with method, the inner class mentioned by Srikanth is still a valid example of using this: (with method this time)
public class OuterClass
{
void f() {System.out.println("Outer f()");};
class InnerClass {
void f() {
System.out.println("Inner f()");
OuterClass.this.f();
}
}
}
You have the same situation with anonymous class:
You can refer to the outer class’s methods by:
MyOuterClass.this.yOuterInstanceMethod(),
MyOuterClass.myOuterInstanceMethod(),
or simply myOuterInstanceMethod() if there is no ambiguity.
This doesn't quite answer your question, but if you use Eclipse you might find "Assignment has no effect" setting useful. I am sure this will be in other IDEs too.
You might want to take a look at What is the advantage of having this/self pointer mandatory explicit?
Although using this is not mandatory in Java as you noticed I'm sure it will shed some light on the subject of using this in Java as well.
To avoid this, use an IDE (like Eclipse) and it will generate warnings in this case.
Also, make your fields final unless they absolutely can't be. There are a number of reasons (apart from this one) to do that.
Related
Why don't we initialize the fields as soon as we declare them in the class? Could the workflow of the code differ if we have initialized the fields as soon as we have declared them? The point is, why we don't initialize them above the constructor?
First of all: we can!
For a more in-depth answer, I will quote The Java Tutorials that says:
However, this form of initialization has limitations because of its simplicity. If initialization requires some logic (for example, error handling or a for loop to fill a complex array), simple assignment is inadequate.
Therefore, to keep a coherent and homogeneous way of writing the code that ensures the code readability, we tend to avoid initializing some fields directly and some others in the constructor (or elsewhere).
We can initialize a field when it is declared:
class Foo {
int a = 1;
}
We can initialize a field in a constructor:
class Foo {
int a;
Foo() {
a = 1;
}
}
We can even initialize a field in an initializer block:
class Foo {
int a;
{
a = 1;
}
}
Actually, the compiler converts the first and third forms into the second.
(Of course, if the field isn't final, we can also (re)assign it in a method).
If you know the initial value a needs to have when you're writing the code, and it's a simple expression, by all means write it in the first way; it's generally worth avoiding the initializer way (mostly because it's unusual, and not very pretty). And this way is great, if you have multiple constructors, but want to set the same value in all the constructors: the same initialization gets copied into all of the constructors (or, at least, the ones which don't invoke this(...)).
But if you need to set a based on something like a constructor parameter, you have to do (something like) the second way:
class Foo {
int a;
Foo(int a) {
this.a = a;
}
}
Which of the approaches you use depends on the situation.
I only initialize final fields, everything else is initialized by constructors.
class MyClass{
final static int SERIAL = 12345678;
int a, b, c, d;
MyClass(int i){
a = b = c = d = i;
}
MyClass(){
this(1);
}
}
I've checked Forward References During Field Initialization and this the answer from #assylias, but still I got no answer to the why.
Why a static block can assign the static variable declared after it but can NOT access it?
class Parent {
static {
i = 2; // valid
// can only assign new value to it instead of accessing it?
// System.out.println(i); // invalid - compile-error
}
static int i = 0;
static {
i = 3; // valid
}
}
Is it due to the fact: the value is not initialized yet, so we just explicitly inhibit you from using it? or there are something related to security I don't know?
updated
this is not a duplicate of that problem which is about
Why this doesn't happen when accessing with class name?
This question is about why we have this design? for what purpose?
Static fields are initialized based on the order they appear in the code.
So, when you assign a value to i variable you just say to the compiler: "Hey, guy, when you get to initialize this variable, set its value to...". But you can not use it until it's initialized because it simply does not exist yet.
UPDATE:
As it says in the book "The Java Language Specification" by James Gosling, Bill Joy, Guy Steele and Gilad Bracha:
These restrictions are designed to catch, at compile time, circular or
otherwise malformed initializations.
Consider this:
static {
i = 2;
j = i + 5; //should it be 7 or 15?
}
static int i = 10;
static int j;
Should j variable be 7 or 15?
If it's 7, then we have initialized i variable twice, which is not possible, since the field is static. If it's 15 then what does i = 2; mean?
This code is ambiguous, so Java Specification does not allow to do that.
After some further reading, I think Pavel is not quite accurate in this point as #Holger pointed out in the comment.
we have initialized i variable twice, which is not possible, since the field is static.
As the 12.4.2. Detailed Initialization Procedure points out
For each class or interface C, there is a unique initialization lock LC. The mapping from C to LC is left to the discretion of the Java Virtual Machine implementation.
I suppose the initialization twice is okay to the class initializer itself as long as it's just once to the invoking clients.
But the demos Pavel provided still stands its position so I basically just reuse it here but with different explanation.
static {
i = 2;
j = i + 5;
// no one knows whether "i" here initialized properly here
}
static int i = 10;
static int j;
But when you use MyClass.i directly in j = MyClass.i + 5, the compiler would know it would then be okay as 8.3.3. Forward References During Field Initialization detailed with four conditions.
Specifically, it is a compile-time error if all of the following are
true:
The declaration of a class variable in a class or interface C appears
textually after a use of the class variable;
The use is a simple name in either a class variable initializer of C
or a static 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.
And there is a detailed discussion in this answer already.
To wind it up, I think this would be for predictable behavior to add these restrictions. Once again, the other official purpose pointed out in 8.3.3. Forward References During Field Initialization.
These restrictions are designed to catch, at compile time, circular or otherwise malformed initializations.
The same is also applicable to the non-static members. You can assign values to them in instance initializer block but can not use them before initialization.
class Parent {
{
x = 3; // works fine
// System.out.println(x); // gives compilation error.
}
int x = 0;
public static void main(String[] args) {
}
}
I am learning Java, the tutorial i am following says Java does not allow the variable k (local variable to m1() in the below example) to be directly accessible from method m2() because they are created in the same method m1() and that I will get an error during compile time (unless k is declared as final). The reason they say is a local variable (k) is created during method is called and destroyed after the method execution is complete, but an object (o) is created when the object is instantiated and can still be not destroyed after method execution. So the tutorial says that if you call the method m2() or object o after method m2 is executed (I do not know how it is possible) variable k will be destroyed and will not be available. So the tutorial claims that Java will not allow such declarations. (Please feel free to correct me wherever my understanding is wrong)
But when I compile this program works fine. Am I missing something? I understand this is a bit complex from my perspective of explaining so if my question is clear so please feel free to ask me if something is not clear.
Thanks in advance for your help.
class innerclass_ex8
{
int x = 10;
static int y = 20;
public void m1()
{
int k = 30;
final int z = 50;
class inner {
public void m2()
{
System.out.println(x);
System.out.println(y);
System.out.println(k);
System.out.println(z);
}
}
inner o = new inner();
o.m2();
}
public static void main(String[] args)
{
innerclass_ex8 g = new innerclass_ex8();
g.m1();
}
}
First of all, your program compiles and works fine because you are using Java 8. If using Java 7 or lower, it won't even compile.
The reason is exactly as you cited. But I will try to explain it a bit more. Consider the following code:
public void m1() {
int k = 30;
class inner {
public void m2() {
System.out.println(k);
}
}
inner o = new inner();
k = 42; // <= Note the reassignment here.
o.m2();
}
What should the method call o.m2() print? "30" or "42"? Both outputs could reasonably be argumented. At the time the method was declared and defined, the variable k had the value 30. At the time the method was called, the variable k had the value 42.
To prevent such ambiguities, the compiler does not allow assignment to a variable that is used in such inner classes (local and anonymous). So it must be final.
In Java 8 this was relaxed a bit. Java 8 introduced the concept of effectively final. A variable that is declared and initialized and not being assigned again is considered effectively final. And the compiler allows that code without declaring the variable final.
As a matter of fact, you also get a compiler error in Java 8 when trying to compile the above code.
Concept you told about variable inside method is correct. If you compile if with Java 1.7 or less then it will throw compile error. I guess you are using java 1.8. There is a concept call final variable and effectively final variable. In java 1.8 if method variable value is assigned and not changed again then it can execute this code without throwing compile time
error.
A ton of questions have been asked on how to create getter and setter methods in java. But i have yet to see one that actually tells me how to use it.
Say i have Private int i = 1; in class A and i want to access it in class B.
I would first create a get method in class A called getIntI(); which would return the value of i.
Then in class B if i wanted to create an if statement that would need the value of i how would I get int i's value. The following is my try and calling the get method which does not work.
if(getIntI == 1)
{System.out.print.ln("int i is one");}
It is probably a really stupid question but i cant find an answer for it elsewhere.
In class A:
public int getIntI(){
return i;
}
Note: Now since your variable is single character named (just I), getter method is named getIntI since the name getI makes lesser sense. But generally, getter methods are something like get+VariableName and do not involve mentioning type. For example if I had a variable called int count, my method would be named getCount instead of getIntCount. Thats the general convention.
Also, naming variables in single char formats (like x, y etc) is discouraged because it may create confusion and management difficulty in complex programs. Though in very small programs they are fine.
Moving back to topic, if you want to access method getIntI() in class B, you will either have to inherit class A or create an object of class A reference to its method.
For class B:
Creating object
A obj = new A();
if(obj.getIntI() == 1)
// Do stuff
Inheriting class A:
public class B extends A{
... // Your stuff
if(getIntI() == 1)
// Do stuff
... // Your stuff
}
Of course there are other ways but these are simpler ones.
if class B extends class A then do only this changes,
if(getIntI() == 1)
If above inheritance was not there then do this,
if(new A().getIntI() == 1)
The problem is that you need to create a object derived from class A before you can access its variables/methods using
A a = new A();
where "a" is the name of the object. Then you can access the getter method by calling a.getIntI. You can also declare the int variable as static so that you wouldn't have to instantiate any objects. An example of class A with the static variable and getter method would be:
public class A {
private static int i = 1;
public static int getIntI() {
return i;
}
}
With this, you can call the getter method with A.getIntI().
First, if you want to access one of A's non-static methods (in this case, getIntI), you need an instance of A, or you can just declare it static.
Secondly, A method call needs a parameter list, even an empty one is needed. getIntI does not need any parameters, so you should add () at the end.
Now, you can get an instance of A somewhere and call it aObj. Andd then you can use it in the if statement:
if (aObj.getIntI == 1)
And remember to add ()!
if (aObj.getIntI() == 1)
Alternatively, you can declare i in A as static. There are two main differences between a static and a non-static variable.
You don't need an instance of the declaring class to access the static variable.
Unlike non-static variables, there is only one static variable. If you have a non-static variable i, you can create lots of instances of A and each instance will have its own i
Now let's see this in action, declare i as static:
public class A {
private static int i = 1;
public static int getIntI () { return i; }
}
Note how both i and getIntI are declared static.
Then you can use in a if statement like this:
if (A.getIntI() == 1)
Note how I use the class name A to access the method, not an instance of A.
Please take a look at this snippet:
public class A {
void method() {
System.out.print(B.j);//This is legal!
class C {
void method () {
System.out.print(j);//This is illegal!
}
}
final int j = 10;
class D {
void method() {
System.out.print(j);//This is legal!
}
}
}
}
class B {
static int j = 10;
}
We can access the 'B.j' in a place before it's definition whilst this is illegal in the case of accessing 'final int j' in class C.
Does java compiler looks at local classes as simple variables/objects? Specially, what's the rationale behind this behavior? I mean forward checking is working for the B.j but it doesn't work for the 'j' inside the class C.
I believe this is simple scoping. If you replace your inner classes with simple System.out.println() calls,
public class A {
void method() {
System.out.print(j);//This is illegal!
final int j = 10;
System.out.print(j);//This is legal!
}
}
you'll find you get the same message. The scope of local variables starts where they are declared and continues through the end of the block they're declared in.
To answer your question about the reference to B: Consider
public class A {
void method() {
System.out.print(k);//This is legal!
}
int k=17;
}
Java is not a single-pass compilation. Classes, and their exposed fields and methods, can be forward referenced. A deliberate decision was made that local variables can not be forward referenced. I'm guessing that this was to let programmers establish restricted scopes without having to use additional levels of {} block statements -- if I introduce a new variable, especially with an initialization, I don't want anyone tampering with it before that.
That's how Java local variables happen to work. This may not be a satisfying answer, but it's the best one we've got.
Setting the possibility that your code does not compile aside...
When class A is loaded by the classloader into memory, so is class B, because they're in the same file. So B.j is already allocated on the heap when method is called at runtime.
On the other hand, when you declare variables in a method, those variables are stored on the stack when the method is invoked, in the order that you write them, so here order matters.