access to shadowed variable in local class - java

i'm new in java and i confused for below example
public class Test {
int testOne(){ //member method
int x=5;
class inTest // local class in member method
{
void inTestOne(int x){
System.out.print("x is "+x);
// System.out.print("this.x is "+this.x);
}
}
inTest ins=new inTest(); // create an instance of inTest local class (inner class)
ins.inTestOne(10);
return 0;
}
public static void main(String[] args) {
Test obj = new Test();
obj.testOne();
}
}
why i can't access to shadowed variable in inTestOne() method with "this" keyword in line 8

why i can't access to shadowed variable in inTestOne() method with "this" keyword in line 8
Because x is not a member variable of the class; it is a local variable. The keyword this can be used to access a member fields of the class, not local variables.
Once a variable is shadowed, you have no access to it. This is OK, because both the variable and the local inner class are yours to change; if you want to access the shadowed variable, all you need to do is renaming it (or renaming the variable that shadows it, whatever makes more sense to you).
Note: don't forget to mark the local variable final, otherwise you wouldn't be able to access it even when it is not shadowed.

this. is used to access members - a local variable is not a member, so it cannot be accessed this way when it's shadowed.

Related

If I assign a value to a variable inside a method, does it persist beyond the scope of that method?

Sorry if this is a repeat, i've tried looking for the answer to my question but could not come across the answer I'm after.
I'm very new at Java (literally started yesterday) and I am trying to understand why if I declare a variable in my class and then assign a value to it in a void method, the value associated with that variable persists beyond the method's scope. My (very) limited understanding of methods is that they have their own scope and I thought the only way to access any variable changes that had been made within a method was to return them at the end of the method. Is this not the case?
Each method in a class will inherit any attribute (variable) or any method that directly belongs to that class. Say
public class Bicycle {
public int gear;
public int speed;
// the Bicycle class has
// two methods
public void setGear(int newValue) {
gear = newValue;
}
public void speedUp(int increment) {
speed += increment;
}
}
Let's get the setGear method
public void setGear(int newValue) {
gear = newValue;
}
As you can see, I can access the 'gear' attribute because it belongs to the Bicycle class. The parameter '(int newValue)' belongs to this method exclusively, meaning I can only access this variable inside this method, like this:
public void setGear(int newValue) {
newValue = gear;
//this wouldn't make much sense logic wise, but it is
//valid code since I can use newValue only inside the setGear method
speedUp(10);
//the method 'speedUp' belongs to the bicycle class, so I can use
//it inside another method belonging to the same class
}
Alternatively, I can use the this keyword to say that I am referring class attributes, like this:
public void setGear(int gear) {
this.gear = gear;
//I am telling the method that the class attribute 'gear' will
//receive my parameter value 'gear'
//this is useful when my parameter variable name has the same
//name as my class attribute
}
Edit: forgot to give credit to the oficial oracle docs https://docs.oracle.com/javase/tutorial/java/javaOO/classes.html
The answer to this is a bit more complex.
First start to distinguish a method from a function.
A method operates on an object instantiated by calling the constructor of the class (e.g. MyClass obj = new MyClass();). From this point, your object has a state expressed by it's member variables (all variables that are not declared static in your class).
Methods (as part of the object) may change this state (unless the corresponding variables are declared final).
To be able to to so, a method inherits the scope of the class, but the variables are bound to the instance of the object, on which the method is called.
So for instance:
public class MyClass {
private int a = 0;
public void aplusplus() {a++;}
}
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
obj1.aplusplus(); // the a of obj1 is now 1
obj2.aplusplus(); // the a of obj2 is now 1
obj1.aplusplus(); // the a of obj1 is now 2
But beware! There is also a concept called hiding.
If you declare a local variable within the body of a method, it hides the class member variable. Accessing the variable by name results in accessing the local variable, instead of the member variable. This is particuallry interesting when implementing setter methods for private members, where usually the argument of the method (which is a local variable) is named exactly as the member variable. To still access the member variable, you can use this.variablename. For instance:
public class MyClass {
private int a = 0;
public void aplusplus() {a++;}
public void setA(int a) {this.a = a;}
}
You say in your question that you have declared a variable in your class. This means that any value the variable gets set to, (during method invocations), will persist across method invocations. The variable is part of this object, and as such, is referred to as an instance variable.
If you declare variables inside method definitions, they are inside the scope of the method. They are part of this.yourMethod(). These variables are said to be local to the method. You can only use these variables inside the method. The this object does not know they exist.

Java static variables and local variables [duplicate]

This question already has answers here:
Why is it not possible to shadow a local variable in a loop?
(7 answers)
Closed 5 years ago.
I am new in Java and came across one OCJA-1.8 sample question where I am having some doubt. I need clarification on this behavior of JVM.
public class Test{
static int x=1;//**This is static class level variable**
public static void main(String[] args){
int[] nums={1,2,3,4,5};
for(int x:nums){ // Local variable declared for for-each loop.
System.out.println(x);
}
}
}
Why the JVM have not thrown the error as duplicate variable, For the variable which is declared inside for each loop 'int x'. As static variable has class level scope ?
The local variable hides the original static field somewhat, but it is not inaccessible:
Test.x
And for non-static fields:
this.x // not in this case
So it is allowed, and in effect one often sees:
public class Pt {
private final int x;
public Pt(int x) {
this.x = x;
}
}
Which prevents the need to introduce some convention (_x, mX).
What is not allowed:
void f() {
int x = 42;
if (true) {
int x = 13; // COMPILER ERROR
...
}
}
As this is bad style, causing confusion.
The inner variable declaration of x override the static one.
If you need to access the static variable you can access it with Test.x
The duplicate variable compilation error happens for two variables with the same name declared in the same scope : fields or method declaration scope.
In your example, each variable is declared in a distinct scope.
As a consequence, as you refer x in the method declaring x, by default it refers to the variable with the nearer scope available (the x local variable) that so shadows the other variable (the x field variable).
To reference the shadowed variable :
if it is a static field (your case), prefix it with the class name declaring it : Test.x
if it is an instance field, prefix it with the this keyword : this.x
When you have a local variable same as static variable, static variable of the class is shadowed by the local variable.
It doesn't throw an error because Java has the concept of shadowing. In essence, the variable with the lowest scope is used.
The static field is still accessible, you just need to fully qualify it:
for(int x:nums){
System.out.println(x); // Local x
System.out.println(Test.x); // static x
}
This can be confusing to a reader of your code and so should be avoided in most cases. If you find yourself with a field and local variable named identically, there's probably something up and you should re-evaluate how you've named your variables.
In your specific case, x is not a descriptive name and both variables would benefit from better, more descriptive names.
In certain cases, such as within a constructor or setter method, it's beneficial to have local variables and fields with the same names, and this is where shadowing is a useful feature.

Why instance initializers require *final* for outer variables in Java?

What semantics would the second example violate if it had access to the outer variable?
class A {
void f() {
int outer = 1;
// Access non-final outer variable through helper method
new A() {
int inner;
void init(int inner) {
this.inner = inner;
}
}.init(outer); // OK
// Access non-final outer variable through instance initializer
new A() {
{
// int inner = outer; // Does not compile
}
};
outer = 2;
}
}
It has nothing to do with instance initializers, but rather with the fact that you are capturing an outer local variable. If you captured the outer local variable in your helper method, it would equally not work:
new A() {
int inner;
void init() {
this.inner = outer;
}
}.init();
When you capture an outer local variable in a local or anonymous class, that outer local variable must be final (in Java 7 or before) or effectively final (in Java 8+). Your variable outer is not final, and (after your most recent edit) is not effectively final (which means it would still compile if it were declared as final), because you assign to it later.
Captured local variables are required to be final or effectively final due to the way Java implements capturing. In Java, when an object of a local or anonymous class is created, any local variables it captures are assigned (as if by =) into a separate independent copy inside the object (because the object may outlive the local scope where it was created). The variable state is not "shared" between the original local scope and the object(s) that capture it, even though they have the same name and only one variable was declared. Therefore, if you could assign to the variable, changes to one copy of the variable would not be reflected in the other copies, and it would be inconsistent. To prevent this, they prevent you from assigning to any version of the variable, by requiring that it be effectively final.

Assign a static variable before declaring

I'm learning Java and write the simple code below:
public class Test {
private int a = b;
private final static int b = 10;
public int getA() {
return a;
}
}
public class Hello {
public static void main(String[] args) {
Test test = new Test();
System.out.println(test.getA());
}
}
The result: 10. Well done! It run successfully and have no error.
Can anyone please explain why I can assign a static variable before declaring it?
The assignment
private int a = b;
takes place when you create a new instance of Test (just before the constructor is called).
The declaration and initialization of the static variable b, takes place before the instance is created, when the class is loaded.
The order of the statements doesn't matter, since static variables are always initialized first.
Javavariables are initialised this order:
Static variables of the superclasses if any
static variables of the current class.
Static variables, and static blocks in the order that they are
declared
Instance variables of the superclasses
All instance variables of the current class.
Instance variables, and instance level initialisation blocks, in
declaration order
Therefore "b" is intialized before the "a".
Hope this helps.
Static variables are bound to a class - which of course always exists before instances of the class. Thus, you can freely assign it to instance fields.
The order of declaring variables doesn't really matter in your code as in reality the static variable is going to be initialized before non-static ones.
The code you wrote works well because
private final static int b = 10;
is a class variable (static field). Those type of variables are initialised for first.
Then is executed the line
private int a = b;
which initialise the instance variable (field) a.
In short, it doesn't matter the order in which those variables are declared in your code. Class variables are always declared before instance variables.

Inner class and local variables

Why do I need to declare a local variable as final if my Inner class defined within the method needs to use it ?
Example :
class MyOuter2 {
private String x = "Outer2";
void doStuff() {
final String y = "Hello World";
final class MyInner {
String z = y;
public void seeOuter() {
System.out.println("Outer x is "+x);
System.out.println("Local variable is "+y);
MyInner mi = new MyInner();
mi.seeOuter();
}
}
}
}
Why the String y needs to be a final constant ? How does it impact ?
Local variables always live on the stack, the moment method is over all local variables are gone.
But your inner class objects might be on heap even after the method is over (Say an instance variable holds on to the reference), so in that case it cannot access your local variables since they are gone, unless you mark them as final
The answer is the two are in different scopes. So that variable could change before the inner class accesses it. Making it final prevents that.
It's because the inner class inside a function actually makes a copy of the local variable because local variable may be destroyed after the function call while the instance of the local class still exists. To make the two copies of the local variable always have the same value(to make them seem identical), you have to declare the variable as final.
I think this is to prevent that the programmer would make mistakes. This way, the compiler reminds the programmer that the variable will not be accessible anymore when you leave that method. This is critical with looping. Imagine this code:
public void doStuff()
{
InnerClass cls[] = new InnerClass[100];
for (int i = 0; i < 100; ++i)
{
cls[i] = new InnerClass()
{
void doIt()
{
System.out.println(i);
}
};
}
}
When the doIt() method is called, what will be printed? i changed while looping.
To prevent that confusion, you have to copy the variable to a local variable or create the variable final, but then you will be unable to loop.
Your inner class is final and so you shouldn't be able to modify anything from inside your final entity.
According to Java memory model use of final variable guarantees that the final variable are always initialized.
We get error when we try to use local variable without initialization.
using final guarantees the inner class that local variable which is been used is initialized.

Categories

Resources