How are local variables in method counted java bytecode - java

I have been learning about java byte-code recently, and i have been understanding most of it, but i am confused about how the local variable count for example is counted. I thought it would just be the total of the local variables, but this code generates 1 local variable when looking through the bytecode
public int testFail()
{
return 1;
}
But i thought it should be zero local variables because no local variable are defined.
Additionally this method also generates one local variable but it has more local variables than the previous example.
Finally this method
public static int testFail(int a, int b)
{
return a+b;
}
gnerates two local variable in the bytecode.
public static int testFail(int a)
{
return a;
}

Non-static methods use a local variable slot for this. Another complication is that longs and doubles count as 2 each. Also, depending on your compiler and settings, you may not see a one-to-one mapping between local variables in the source code and local variables in the byte code. For example, if debug information is left out, the compiler may eliminate unnecessary local variables.
Edit:
I just remembered: compilers may also re-use local variable slots. For example, given this code:
public static void test() {
for(int i = 0; i < 100; i++) {
...
}
for(int j = 0; j < 100; j++) {
}
}
the same slot can be used for i and j because their scopes don't overlap.

The reason the first one has a local variable is because it is a nonstatic method, so there is an implicit this parameter.

Related

if we declare a variable before a for loop and we are declaring same name variable in for loop statement in java. we are getting error. why? [duplicate]

I got this situation I can't understand about shadowing. For example the following code:
class Foo {
int a = 5;
void goFoo(int a) {
// No problem naming parameter as same as instance variable
for (int a = 0; a < 5; a++) { }
// Now the compiler complains about the variable a on the for loop
// I thought that the loop block had its own scope so I could shadow
// the parameter, why the compiler didn't throw an error when i named
// the parameter same as the instance variable?
}
}
You can make a local variable shadow an instance/static variable - but you can't make one local variable (your loop counter) shadow another local variable or parameter (your parameter).
From the Java Language Specification, section 14.4.3:
If a name declared as a local variable is already declared as a field name, then that outer declaration is shadowed (§6.3.1) throughout the scope of the local variable.
Note the "field name" part - it's specifying that it has to be a field that is shadowed.
And from section 8.4.1:
The scope of a parameter of a method (§8.4.1) or constructor (§8.8.1) is the entire body of the method or constructor.
These parameter names may not be redeclared as local variables of the method, or as exception parameters of catch clauses in a try statement of the method or constructor.
(It goes on to talk about local classes and anonymous classes, but they're irrelevant in your case.)
void goFoo(int a) {
for (int a = 0; a < 5; a++) { }
}
it is similar to
void goFoo() {
int a;
for (int a = 0; a < 5; a++) { }
}
so multiple declaration of a on the same scope, it is not acceptable.
or simply it is similar to
void goFoo() {
int a;
int a;
}
Also See
java-variable-scope-shadowing
The scope of the variable depends on the hierarchy of the block as well.
ie if u use like this
void goFoo(int a) {
// No problem naming parameter as same as instance variable
for (int b = 0; b < 5; b++) { }
//Now the compiler complains about the variable a on the for loop
// i thought that the loop block had its own scope so i could shadow
// the parameter, why the compiler didnt throw an error when i named
// the parameter same as the instance variable?
int b; // you can do this.
}
That is if a variable is declared in the outer block then you can not declare the same in the block which is inner. the other way you can do it.
But you don't declare the second "a" in that new scope, as your code shows. It's in the scope of the goFoo() block itself.
The problem isn't that the loop is shadowing the class field, the name is already used by the parameter.
Two options: One is to change the loop:
for (a = 0; a < 5; a++) { }
This uses the parameter as the index variable. Not clear why you would have a parameter, but all the same...
The other option is to rename the loop variable or the parameter to something else.
It is not shadowing, it is a conflict here. Both a are in the method scope. One cannot define two variables of same name in the same scope.
In Java (unlike, say, in c++) you cannot declare a local variable when another local variable with the same name is "in scope".
You cannot do this in Java
void foo() {
int a;
{
int a; // You cannot declare 'a' here because a
// from the outer block is still in scope
// here. Local variables in Java cannot be
// shadowed by another local variable with
// the same name. Only instance variables
// can be shadowed by the local variables
// with the same name.
}
}
However c++ allows you to do this
void foo()
{
int a;
a = 10;
cout << a << endl; // prints 10 duh
{
int a; // this declaration shadows the local
// variable 'a' from the outer scope.
a = 20; // assigns 20 to the variable 'a' in
// current inner scope, like you'd expect.
cout << a << endl; // prints 20.
}
cout << a << endl; // prints 10
}

Pascal Triangle recursive program not working

Here is my code... I am a beginner and appreciate any feed back. My problem I am trying to solve is to print the pascal triangle up to the user imputed row.
public class Pascal111 {
int max;
int r,c;
public int pascal(int maxm){
max=maxm;
for(int r=0; r<max; r++){
for (int c=0; c<r; c++){
populate();}
}
return max;
}
public void populate(){
int[][] array=new int[max][max];
if (r==0){
array[0][0]=1;
}
else if(c==0){
array[0][0]=1;
}
else if(c==r){
array[r][c]=1;;
}
else
array[r][c]=(array[r-1]+array[c-1]+array[r-1]+array[c]);
}
}
I get the following error....
Error: bad operand types for binary operator '+'
first type: int[]
second type: int[]
array[r][c]=(array[r-1]+array[c-1]+array[r-1]+array[c]);
is wrong.
array is a 2-D array, thus array[X] represents a complete row (1-D array). You just can't do binary operation on 1-D arrays and put it on a single element array[r][c].
Instead replace it with
array[r][c]=(array[r-1][c-1]+array[r-1][c]);
Although I haven't looked at this closely, one mistake stands out: you have two different variables named r and two different variables named c.
Here's the relevant parts of your code:
public class Pascal111 {
int r,c; // (A)
public int pascal(int maxm) {
for (int r=0; r<max; r++){ // (B)
for (int c=0; c<r; c++){ // (B)
populate();
}
}
return max;
}
public void populate() {
if (r==0) {
... more code that accesses r and c
}
}
The declaration at (A) declares instance variables, because the declaration isn't inside a method. This means that whenever you create a Pascal111 object, this object will have fields named r and c. They are initialized to 0.
The declarations at (B), since they have int keywords on them, declare new variables. These variables are local to the pascal method, which means they can be accessed only inside that method. (Actually, they can be accessed only inside the for loops.) These variables have no connection to the instance variables. They are totally separate. As you increment these local r and c variables, the instance variables remain unchanged. That is, they are still 0.
The populate method can't access local variables declared in pascal. So when populate refers to r and c, they are referring to the instance variables. These are not the variables that get incremented in the loop, but rather the instance variables that remain 0.
One way to fix this would be to remove the int on the declarations in (B); that would cause pascal to increment the instance variables, and then populate would use those. However, that is the wrong approach.
The best way to fix these is not to use the instance variables to communicate between pascal and populate--but rather, to use parameters. That is:
for (int r=0; r<max; r++){ // (B)
for (int c=0; c<r; c++){ // (B)
populate(r, c);
}
}
and later:
public void populate(int r, int c) {
Then, when populate refers to r and c, it will refer to the parameters, which are in essence local variables. The parameters will be the r and c from pascal. (But you don't have to use the same names for the pascal variables and the populate parameters.) After you do this, you'll find that the instance variables are no longer needed at all. It's always, or almost always, wrong to have instance variables used as loop indexes anyway.
A similar error: You have array as a local variable inside populate. This means that you're creating a brand new array every time you call it to set up one array element. Then, when populate returns, array can no longer be accessed, so whatever work you've done is lost.

try catch java -- java complaining that variable may not be initialized [duplicate]

When I try to compile this:
public static Rand searchCount (int[] x)
{
int a ;
int b ;
...
for (int l= 0; l<x.length; l++)
{
if (x[l] == 0)
a++ ;
else if (x[l] == 1)
b++ ;
}
...
}
I get these errors:
Rand.java:72: variable a might not have been initialized
a++ ;
^
Rand.java:74: variable b might not have been initialized
b++ ;
^
2 errors
It seems to me that I initialized them at the top of the method. What's going wrong?
You declared them, but you didn't initialize them. Initializing them is setting them equal to a value:
int a; // This is a declaration
a = 0; // This is an initialization
int b = 1; // This is a declaration and initialization
You get the error because you haven't initialized the variables, but you increment them (e.g., a++) in the for loop.
Java primitives have default values but as one user commented below
Their default value is zero when declared as class members. Local variables don't have default values
Local variables do not get default values. Their initial values are undefined with out assigning values by some means. Before you can use local variables they must be initialized.
There is a big difference when you declare a variable at class level (as a member ie. as a field) and at method level.
If you declare a field at class level they get default values according to their type. If you declare a variable at method level or as a block (means anycode inside {}) do not get any values and remain undefined until somehow they get some starting values ie some values assigned to them.
If they were declared as fields of the class then they would be really initialized with 0.
You're a bit confused because if you write:
class Clazz {
int a;
int b;
Clazz () {
super ();
b = 0;
}
public void printA () {
sout (a + b);
}
public static void main (String[] args) {
new Clazz ().printA ();
}
}
Then this code will print "0". It's because a special constructor will be called when you create new instance of Clazz. At first super () will be called, then field a will be initialized implicitly, and then line b = 0 will be executed.
You declared them, but not initialized.
int a; // declaration, unknown value
a = 0; // initialization
int a = 0; // declaration with initialization
You declared them, but you didn't initialize them with a value. Add something like this:
int a = 0;
You declared them but did not provide them with an intial value - thus, they're unintialized. Try something like:
public static Rand searchCount (int[] x)
{
int a = 0 ;
int b = 0 ;
and the warnings should go away.
Since no other answer has cited the Java language standard, I have decided to write an answer of my own:
In Java, local variables are not, by default, initialized with a certain value (unlike, for example, the field of classes). From the language specification one (§4.12.5) can read the following:
A local variable (§14.4, §14.14) must be explicitly given a value
before it is used, by either initialization (§14.4) or assignment
(§15.26), in a way that can be verified using the rules for definite
assignment (§16 (Definite Assignment)).
Therefore, since the variables a and b are not initialized :
for (int l= 0; l<x.length; l++)
{
if (x[l] == 0)
a++ ;
else if (x[l] == 1)
b++ ;
}
the operations a++; and b++; could not produce any meaningful results, anyway. So it is logical for the compiler to notify you about it:
Rand.java:72: variable a might not have been initialized
a++ ;
^
Rand.java:74: variable b might not have been initialized
b++ ;
^
However, one needs to understand that the fact that a++; and b++; could not produce any meaningful results has nothing to do with the reason why the compiler displays an error. But rather because it is explicitly set on the Java language specification that
A local variable (§14.4, §14.14) must be explicitly given a value (...)
To showcase the aforementioned point, let us change a bit your code to:
public static Rand searchCount (int[] x)
{
if(x == null || x.length == 0)
return null;
int a ;
int b ;
...
for (int l= 0; l<x.length; l++)
{
if(l == 0)
a = l;
if(l == 1)
b = l;
}
...
}
So even though the code above can be formally proven to be valid (i.e., the variables a and b will be always assigned with the value 0 and 1, respectively) it is not the compiler job to try to analyze your application's logic, and neither does the rules of local variable initialization rely on that. The compiler checks if the variables a and b are initialized according to the local variable initialization rules, and reacts accordingly (e.g., displaying a compilation error).
You declared them at the start of the method, but you never initialized them. Initializing would be setting them equal to a value, such as:
int a = 0;
int b = 0;
Imagine what happens if x[l] is neither 0 nor 1 in the loop. In that case a and b will never be assigned to and have an undefined value.
You must initialize them both with some value, for example 0.
It's a good practice to initialize the local variables inside the method block before using it. Here is a mistake that a beginner may commit.
public static void main(String[] args){
int a;
int[] arr = {1,2,3,4,5};
for(int i=0; i<arr.length; i++){
a = arr[i];
}
System.out.println(a);
}
You may expect the console will show '5' but instead the compiler will throw 'variable a might not be initialized' error. Though one may think variable a is 'initialized' inside the for loop, the compiler does not think in that way. What if arr.length is 0? The for loop will not be run at all. Hence, the compiler will give variable a might not have been initialized to point out the potential danger and require you to initialize the variable.
To prevent this kind of error, just initialize the variable when you declare it.
int a = 0;
You haven't initialised a and b, only declared them. There is a subtle difference.
int a = 0;
int b = 0;
At least this is for C++, I presume Java is the same concept.
Set variable "a" to some value like this,
a=0;
Declaring and initialzing are both different.
Good Luck

Local method variable, unrecognized

I have a method public int bar(), where i have declared an int total(in the method body ofc). So this should be a simpel local variable, the thing is that eclipse complain about
Description Resource Path Location Type
The local variable total may not have been initialized Repository.java /proj_individual/src/repo line 35 Java Problem
general example :
public int foo(){
int total;
for(... : ...){
total += 1; // complains
}
return total;// complains
}
and my exact code:
public int getLocatars(){
int total;
for ( Map.Entry<Apartment, List<Expense>> entry : dic.entrySet() ) {
if(entry.getKey().isDebt()){
total += entry.getKey().getNrProple();
}
}
return total;
}
I have no idea what I may have done wrong, so any idea is helpful, thank you.
Your variable isn't definitely assigned a value, so you can't read it.
Imagine if your entry set is empty, or has no debt entries... what value would you want to return?
More than that, even if it does get into the inner-most part of your loop, what initial value would you expect to be added to?
Unlike static and instance fields, local variables don't have default values: you have to assign values to them before you read them. I suspect you just want:
int total = 0;
Change it from:
int total;
to:
int total = 0;
For better understanding, see: differences between declaration and initialization.

What is the scope of a Java variable in a block? [duplicate]

This question already has answers here:
Why does Java not have block-scoped variable declarations?
(6 answers)
Closed 5 years ago.
I know in C++ variables have block scope, for example, the following code works in C++:
void foo(){
int a = 0;
for (int i = 0; i < 10; ++i){
int a = 1; // Redefine a here.
}
}
But this snippet doesn't work in Java, it reports "duplicate local variable a", does it mean Java variables don't have BLOCK scope?
They have block scope. That means that you can't use them outside of the block. However Java disallows hiding a name in the outer block by a name in the inner one.
java variables do have a block scope but if you notice int a is already defined in scope
{
int a = 0;
{
{
}
}
}
all subscopes are in scope of the uppermost curly braces. Hence you get a duplicate variable error.
Section §14.4.2 says:
The scope of a local variable
declaration in a block (§14.2) is the
rest of the block in which the
declaration appears, starting with its
own initializer (§14.4) and including
any further declarators to the right
in the local variable declaration
statement.
The name of a local variable v may not
be redeclared as a local variable of
the directly enclosing method,
constructor or initializer block
within the scope of v, or a
compile-time error occurs.
The previous answers already stated the reason, but I just want to show that this is still allowed:
void foo(){
for(int i = 0; i < 10; ++i){
int a = 1;
}
int a = 0;
}
In this case the a inside the loop doesn't hide the outer a, so it's valid.
Also IMHO it should be this way in C++ too, it's less confusing and prevents accidental declaration of variable with same name.
It does, but it's nested, so the "a" you defined in foo() is available in all blocks within foo.
Here is an example of what you're looking for:
void foo(){
{
int a = 0;
// Do something with a
}
for(int i = 0; i < 10; ++i){
int a = 1; //define a here.
}
}

Categories