Given the following class definition
public class MethodLocalAccess {
int m = 10;
String show(){
final int m = 20;
final int n = 30;
class MyClass{
int m = 40;
String someOtherMethod(){
return "" + m + n + this.m + MyClass.this.m + MethodLocalAccess.this.m;
}
}
MyClass object = new MyClass();
return object.someOtherMethod();
}
public static void main(String[] args) {
System.out.println(new MethodLocalAccess().show());
}
}
Produces output 4030404010, which is fairly established why. I want to know, if the local-variable final int m = 20; can be accessed inside the inner-class.
Other way around, fields declared in method-local inner-class having same name as that of method-local-variable, will permanently hide the latter.
What are you referring to is called variable shadowing (link).
If a declaration of a type (such as a member variable or a parameter
name) in a particular scope (such as an inner class or a method
definition) has the same name as another declaration in the enclosing
scope, then the declaration shadows the declaration of the enclosing
scope. You cannot refer to a shadowed declaration by its name alone.
Once you shadowed a variable, it is not accessible anymore without explicitly specifying its scope, if possible. The only solution in this case is to rename either outer or inner variable.
No you can't. The variable inside the function completely shadowed and you can't refer it anymore as Java doesn't have a way to refer function context.
However you can access top level variables with the context this even though they shadowed (infact you are not shadowing and creating a local variable with same name).
You can't, because it's shadowed.
You can't even with reflection, because reflection works on the type level, not on the byte-code.
You can, with additional tools, if you play with the generated byte-code.
In your case I don't think you can access the local variable m defined in the show method since you already have it declared in your inner class, therefore shadowing it.
Using constructs like ClassName.this.varName allows you to access only the members of that enclosing class. This means you can't use that type of expression to access shadowed local varibles defined in the method since they aren't members of that class.
Yes, the fields declared in method-local inner-class having same name
as that of method-local-variable, will permanently hide the latter.
We can access the local-variable final int m = 20 inside the
inner-class only if you don't have the instance variable of Myclass,
int m = 40 is absent.
Related
This is meant to be a canonical question and answer for similar questions where the issue is a result of shadowing.
I've defined two fields in my class, one of a reference type and one of a primitive type. In the class' constructor, I try to initialize them to some custom values.
When I later query for those fields' values, they come back with Java's default values for them, null for the reference type and 0 for the primitive type. Why is this happening?
Here's a reproducible example:
public class Sample {
public static void main(String[] args) throws Exception {
StringArray array = new StringArray();
System.out.println(array.getCapacity()); // prints 0
System.out.println(array.getElements()); // prints null
}
}
class StringArray {
private String[] elements;
private int capacity;
public StringArray() {
int capacity = 10;
String[] elements;
elements = new String[capacity];
}
public int getCapacity() {
return capacity;
}
public String[] getElements() {
return elements;
}
}
I expected getCapacity() to return the value 10 and getElements() to return a properly initialized array instance.
Entities (packages, types, methods, variables, etc.) defined in a Java program have names. These are used to refer to those entities in other parts of a program.
The Java language defines a scope for each name
The scope of a declaration is the region of the program within which
the entity declared by the declaration can be referred to using a
simple name, provided it is visible (§6.4.1).
In other words, scope is a compile time concept that determines where a name can be used to refer to some program entity.
The program you've posted has multiple declarations. Let's start with
private String[] elements;
private int capacity;
These are field declarations, also called instance variables, ie. a type of member declared in a class body. The Java Language Specification states
The scope of a declaration of a member m declared in or inherited by a
class type C (§8.1.6) is the entire body of C, including any nested
type declarations.
This means you can use the names elements and capacity within the body of StringArray to refer to those fields.
The two first statements in your constructor body
public StringArray() {
int capacity = 10;
String[] elements;
elements = new String[capacity];
}
are actually local variable declaration statements
A local variable declaration statement declares one or more local variable names.
Those two statements introduce two new names in your program. It just so happens that those names are the same as your fields'. In your example, the local variable declaration for capacity also contains an initializer which initializes that local variable, not the field of the same name. Your field named capacity is initialized to the default value for its type, ie. the value 0.
The case for elements is a little different. The local variable declaration statement introduces a new name, but what about the assignment expression?
elements = new String[capacity];
What entity is elements referring to?
The rules of scope state
The scope of a local variable declaration in a block (§14.4) is the
rest of the block in which the declaration appears, starting with its
own initializer and including any further declarators to the right in
the local variable declaration statement.
The block, in this case, is the constructor body. But the constructor body is part of the body of StringArray, which means field names are also in scope. So how does Java determine what you're referring to?
Java introduces the concept of Shadowing to disambiguate.
Some declarations may be shadowed in part of their scope by another
declaration of the same name, in which case a simple name cannot be
used to refer to the declared entity.
(a simple name being a single identifier, eg. elements.)
The documentation also states
A declaration d of a local variable or exception parameter named n
shadows, throughout the scope of d, (a) the declarations of any other
fields named n that are in scope at the point where d occurs, and (b)
the declarations of any other variables named n that are in scope at
the point where d occurs but are not declared in the innermost class
in which d is declared.
This means that the local variable named elements takes priority over the field named elements. The expression
elements = new String[capacity];
is therefore initializing the local variable, not the field. The field is initialized to the default value for its type, ie. the value null.
Inside your methods getCapacity and getElements, the names you use in the in their respective return statements refer to the fields since their declarations are the only ones in scope at that particular point in the program. Since the fields were initialized to 0 and null, those are the values returned.
The solution is to get rid of the local variable declarations altogether and therefore have the names refer to the instance variables, as you originally wanted. For example
public StringArray() {
capacity = 10;
elements = new String[capacity];
}
Shadowing with constructor parameters
Similar to the situation described above, you may have formal (constructor or method) parameters shadowing fields with the same name. For example
public StringArray(int capacity) {
capacity = 10;
}
Shadowing rules state
A declaration d of a field or formal parameter named n shadows,
throughout the scope of d, the declarations of any other variables
named n that are in scope at the point where d occurs.
In the example above, the declaration of the constructor parameter capacity shadows the declaration of the instance variable also named capacity. It's therefore impossible to refer to the instance variable with its simple name. In such cases, we need to refer to it with its qualified name.
A qualified name consists of a name, a "." token, and an identifier.
In this case, we can use the primary expression this as part of a field access expression to refer to the instance variable. For example
public StringArray(int capacity) {
this.capacity = 10; // to initialize the field with the value 10
// or
this.capacity = capacity; // to initialize the field with the value of the constructor argument
}
There are Shadowing rules for every kind of variable, method, and type.
My recommendation is that you use unique names wherever possible so as to avoid the behavior altogether.
int capacity = 10; in your constructor is declaring an local variable capacity which shadows the field of the class.
The remedy is to drop the int:
capacity = 10;
This will change the field value. Ditto for the other field in the class.
Didn't your IDE warn you of this shadowing?
There are two parts to using variables in java/c/c++. One is to declare the variable and the other is to use the variable (whether assigning a value or using it in a calculation).
When you declare a variable you must declare its type. So you would use
int x; // to declare the variable
x = 7; // to set its value
You do not have to re-declare a variable when using it:
int x;
int x = 7;
if the variable is in the same scope you will get a compiler error; however, as you are finding out, if the variable is in a different scope you will mask the first declaration.
Another widely accepted convention is to have some prefix (or suffix - whatever you prefer) added to class members to distinguish them from local variables.
For example class members with m_ prefix:
class StringArray {
private String[] m_elements;
private int m_capacity;
public StringArray(int capacity) {
m_capacity = capacity;
m_elements = new String[capacity];
}
public int getCapacity() {
return m_capacity;
}
public String[] getElements() {
return m_elements;
}
}
Most IDEs have already available support for this notation, below is for Eclipse
What is the difference between a member variable and a local variable?
Are they the same?
A local variable is the variable you declare in a function.
A member variable is the variable you declare in a class definiton.
A member variable is a member of a type and belongs to that type's state. A local variable is not a member of a type and represents local storage rather than the state of an instance of a given type.
This is all very abstract, however. Here is a C# example:
class Program
{
static void Main()
{
// This is a local variable. Its lifespan
// is determined by lexical scope.
Foo foo;
}
}
class Foo
{
// This is a member variable - a new instance
// of this variable will be created for each
// new instance of Foo. The lifespan of this
// variable is equal to the lifespan of "this"
// instance of Foo.
int bar;
}
There are two kinds of member variable: instance and static.
An instance variable lasts as long as the instance of the class. There will be one copy of it per instance.
A static variable lasts as long as the class. There is one copy of it for the entire class.
A local variable is declared in a method and only lasts until the method returns:
public class Example {
private int _instanceVariable = 1;
private static int _staticvariable = 2;
public void Method() {
int localVariable = 3;
}
}
// Somewhere else
Example e = new Example();
// e._instanceVariable will be 1
// e._staticVariable will be 2
// localVariable does not exist
e.Method(); // While executing, localVariable exists
// Afterwards, it's gone
public class Foo
{
private int _FooInt; // I am a member variable
public void Bar()
{
int barInt; // I am a local variable
//Bar() can see barInt and _FooInt
}
public void Baz()
{
//Baz() can only see _FooInt
}
}
A local variable is the variable you declare in a function.Its lifespan is on that Function only.
A member variable is the variable you declare in a class definition.Its lifespan is inside that class only.It is Global Variable.It can be access by any function inside that same class.
Variables declared within a method are "local variables"
Variables declared within the class not within any methods are "member variables"(global variables).
Variables declared within the class not within any methods and defined as static are "class variables".
A member variable belongs to an object... something which has state. A local variable just belongs to the symbol table of whatever scope you are in. However, they will be represented in memory much the same as the computer has no notion of a class... it just sees bits which represent instructions. Local variables and member variables can both be on the stack or heap.
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.
The compiler says illegal modifier for parameter i.
Please tell me what I'm doing wrong. Why can't I use a static variable in a Java constructor?
class Student5{
Student5() {
static int i = 0;
System.out.println(i++);
}
public static void main(String args[]){
Student5 c1 = new Student5();
Student5 c2 = new Student5();
Student5 c3 = new Student5();
}
}
Because of where you are declaring i:
Student5(){
static int i=0;
System.out.println(i++);
}
the compiler treats it as a local variable in the constructor:
Local variables cannot be declared as static. For details on what modifiers are allowed for local variables, see Section 14.4 of the Java Language Specification.
Judging from what the code appears to be trying to do, you probably want i to be a static member of Student5, not a local variable in the constructor:
class Student5{
private static int i = 0;
Student5(){
System.out.println(i++);
}
. . .
}
If you want to declare static variable then declare it outside of the constructor, at class level like this -
public class Student5{
private static int i;
}
You declaration of static occurred at your constructor which is a local variable and local variable can not be static. And that's why you are getting - illegal modifier for parameter i. And finally for initializing static variable you may use a static initialization block (though it's not mandatory) -
public class Student5{
private static int i;
static {
i = 5;
}
}
This is how the language was designed.. What if you wanted to have another int field named i in the constructor?, then which i should be considered?. Also, static fields are initialized before the constructor is called i.e, during class initilization phase. A constructor gets called only when a new instance is created.
Imagine what would happen (supposed to happen) if you load and initialize a class but not create a new instance.
Static variables are variables that can be referenced without having an instance of the class. By defining one instead of a constructor, which is called when you create an instance of the class, you are contradicting yourself. Either make it defined without having an instance (outside of the constructor and static) or make it specific to an instance (inside the constructor and not static).
You might want to rethink what you are actually trying to do and if you really need a static variable.
What is the difference between a local variable, an instance field, an input parameter, and a class field with respect to a simple Java program?
A local variable is defined within the scope of a block. It cannot be used outside of that block.
Example:
if(x > 10) {
String local = "Local value";
}
I cannot use local outside of that if block.
An instance field, or field, is a variable that's bound to the object itself. I can use it in the object without the need to use accessors, and any method contained within the object may use it.
If I wanted to use it outside of the object, and it was not public, I would have to use getters and/or setters.
Example:
public class Point {
private int xValue; // xValue is a field
public void showX() {
System.out.println("X is: " + xValue);
}
}
An input parameter, or parameter or even argument, is something that we pass into a method or constructor. It has scope with respect to the method or constructor that we pass it into.
Example:
public class Point {
private int xValue;
public Point(int x) {
xValue = x;
}
public void setX(int x) {
xValue = x;
}
}
Both x parameters are bound to different scopes.
A class field, or static field, is similar to a field, but the difference is that you do not need to have an instance of the containing object to use it.
Example:
System.out.println(Integer.MAX_VALUE);
I don't need an instance of Integer to retrieve the globally known maximum value of all ints.
Not quite.
A class field is what you think a local variable is but it is generally a static field and so is the same across all instances.
An instance field is the same as a class field, but is non static and can be different for each instance of the object.
http://docs.oracle.com/javase/tutorial/java/javaOO/classvars.html
And a local variable is a variable inside a method or block, that can only be used by that method or block.
Oh and your input parameter definition is correct, an input parameter is a field that is passed to a method as a parameter.
A class field is often called a class variable, and you can find that information here
Start by having a read through Classes and Objects
I know the local variable is a variable that is available to the class it is in, correct?
No, generally a local variable refers to a variable that only has context within the area it was declared. This typically refers to variables declared within methods and {...} blocks (like if statements)
An instance field is an Object that is created in the constructor...?
Not really, an instance field is any field, declared at the class level which is not static, therefore it's value only has meaning to an individual instance of the class
An input parameter is what is passed into a method.
Yes
But I have NO idea about a class field!
A class field and instance field are (generally) the same thing. The only difference would be if the field is declared static, then it can't be a instance field...
A local variable is local to a method.
An instance fields is the field of an instance of a class i.e. an object.
A parameter is passed to a method
A class field, I assume is a static field which is associated with the class. e.g. if you use multiple class loaders, you can have multiple classes with the same name and their own static fields.
A local variable is a variable in a method. It's scope is limited to the scope of the two parenthesis around it. {}
Example:
public void someMethod () {
int localVariable1 = 5;
if (...) {
int localVariable2 = 7;
}
}
With an instance field, I think you mean a member of a a class instance. If you take for example the class Dimension, this would be height or width.
.
An input parameter is a parameter in a method, as you guessed.
A class field is a field in a static method.