Trouble understanding why I cannot modify variable outside a method? - java

public class test {
public static void main(String[] args) throws Exception {
final int num = 111;
new Thread() {
#Override
public void run() {
num = 222;
}
}.start();
}
}
I want to change the value of num however I can only do that if I set it to final which would not let me modify this. In other languages such as C we can use pointers but Java cannot?

Java has neither closure nor pointers.
A solution would be to make the num static in the class :
public class test {
static int num = 111;
public static void main(String[] args) throws Exception {
new Thread() {
#Override
public void run() {
num = 222;
}
}.start();
}
}
Another solution would be to use an object like AtomicInteger. You can't change the value of the variable but you can change the content of the value :
public class test {
public static void main(String[] args) throws Exception {
final AtomicInteger num = new AtomicInteger(111);
new Thread() {
#Override
public void run() {
num.set(222);
}
}.start();
}
}

Why this isn't allowed
main is a method. As with other programming languages, when a method returns, all of the variables declared in its body go out of scope, and accessing them has undefined behavior. Under some circumstances, the memory location where they used to be will no longer be valid.
Obviously this is a problem. If you try to change num after main has returned, you might overwrite a portion of the stack that doesn't belong to num anymore. Java's response to this difficult situation is to introduce restrictions on how you can share variables: they must be final. Java can then safely locate them in such a way that reading them will produce consistent results even after the function has returned.
The C equivalent to this problem is storing and using the address of a local variable outside of its scope, something that all C programmers are taught to never do.
To get around it, declare num as a member of test, create an instance, and pass that to it. This removes the dependancy on a local variable, and thus removes the final restriction.
public class test
{
int num = 111;
public static void main(String[] args) throws Exception
{
test t = new test();
(new Thread(t) {
test mytest;
Thread(test t)
{
mytest = t;
}
#Override
public void run() {
mytest.num = 222;
}
}).start();
}
}

Well, you can access it if you declare variable outside the function. Like this:
public class test {
private static int num = 111;
public static void main(String[] args) throws Exception {
new Thread() {
#Override
public void run() {
num = 222;
}
}.start();
}
}

You are creating new Thread() { class as inner class. You can't access outer class variables without declaring them as final.
You can't change final variable references.
There are two ways you can do this,
1) Make num as static
2) Wrap num inside an object (You can update state of the object even though you define reference as final).
NOTE: Both are not thread safe.

Yep you can't win here! You need to set it final to be able to access it, but then you will not be able to modify it. You'll need to look at a different approach.

Related

Why should one specify attribute values inside a constructor when it is simpler to specify them in the declaration?

I've just started learning about constructors and know that they're used to initialize objects. But i noticed that objects can be given initial values in the declaration (as in example 2) without having to specify them separately in a constructor.
Both examples below give the same result so what is the benefit of first declaring the attribute and then specifying the value in a constructor instead of right away in the declaration?
Example 1:
**public class Main {
int x;
public Main() {
x = 5;
}**
public static void main(String[] args) {
Main myObj = new Main();
System.out.println(myObj.x);
}
}
Example 2:
**public class Main {
int x = 5;**
public static void main(String[] args) {
Main myObj = new Main();
System.out.println(myObj.x);
}
}
In your example, where you always want to set the value to a pre-defined value, a constructor is not required. It can be initialized at the time the attribute is defined. However, in most cases, it is not so simple - value of a class attribute is usually passed in at the time an instance is created. In such cases, a constructor is a good way to initialize the attributes of a class.
public class Main {
int x;
public Main(int x) {
this.x = x;
}
public static void main(String[] args) {
Main myObj = new Main(6);
System.out.println(myObj.x);
}
}

shadowing static variable ( global variable)

Why in the next code I get pro.x=11?. it should be 22. Please somebody throws a light.
public class Pro {
static int x=11;
public static void main(String[] args) {
Pro pro=new Pro();
pro.call(5);
System.out.println(Pro.x);
System.out.println(pro.x);
}
public void call(int x){
x=22;
}
}
you are not setting the static/global variable to 22, but rather the value of the argument passed. Considering it's a primitive value, call by value is used and not call by reference.
Edit: In fact as pointed out in comments, java doesn't have have call by reference, but rather call by value of a reference.
If you just wisht to change the global variable, no argument is necessary for your function, you can do it this way:
public class Pro {
static int x=11;
public static void main(String[] args) {
Pro pro=new Pro();
pro.call();
System.out.println(Pro.x);
System.out.println(pro.x);
}
public void call(){
Pro.x=22;
}
}

Why can't I instantiate and create Object without main method? (Stack Overflow Error)

My Code:
(causes a Stack Overflow Error)
public class Overloads {
String uniqueID;
Overloads ov2=new Overloads();
public static void main(String[] args) {
System.out.println("IN MAIN");
}
public void setUniqueID(String theID) {
// II lots of validation code, and then:
uniqueID = theID;
System.out.println(uniqueID);
}
}
This Code Works Fine:
public class Overloads {
String uniqueID;
public static void main(String[] args) {
Overloads ov2=new Overloads();
System.out.println("IN MAIN");
}
public void setUniqueID(String theID) {
// II lots of validation code, and then:
uniqueID = theID;
System.out.println(uniqueID);
}
}
The presence of main method is not relevant here. The scope in which you have declared the variables, however, is very important.
Have you walked through what happens in the first version of the code?
Create new instance of Overloads
-> ov2 = Create new instance of Overloads
-> ov2 = Create new instance of Overloads
-> ov2 = Create new instance of Overloads
and so on. The variable ov2 is in scope of the class, thus it is initialized whenever an instance of the class is instantiated. This will never terminate until you run out of memory and get the stack overflow. Run it with a debugger for a clearer view.
The second version of the code only instantiates one instace of Overloads, in the scope of the main method. Thus creating one instance does not lead to the newly created instance creating new instance and so on..
You can do like this
public class Overloads {
String uniqueID;
static Overloads ov2 = new Overloads();
public static void main(String[] args) {
System.out.println("IN MAIN");
}
public void setUniqueID(String theID) {
// II lots of validation code, and then:
uniqueID = theID;
System.out.println(uniqueID);
}
}
this will create shared instance of Overloads, instantiation will be done only once, when class loaded

What is the difference between ClassName.m() and (new ClassName()).m() m() is a static method

What is the difference between ClassName.m() and (new ClassName()).m() m() is a static method.
The difference is that in your second example you are creating an unnecessary object in memory.
It is still calling the same static method for the ClassName class.
It is recommended to use ClassName.m() to avoid unnecessary object creation and to provide context to the developers indicating that a static method is indeed being called.
Three things:
The second has an extra call, which means it might change the outcome. This may be bad, may not, but it is something to consider. See example on how this can work.
The second creates an extra object. That's bad.
The second implies you're calling a method on an object, not on the class itself, which confuses people who read it. That's also bad. See example for how this can be very bad!
Consider the following, reason 1:
class ClassName {
static int nextId;
static int m() { return nextId; }
int id;
ClassName() { id = nextId; nextId++; }
/**
C:\junk>java ClassName
2
2
3
*/
public static void main(String[] args) {
new ClassName();
new ClassName();
System.out.println(ClassName.m());
System.out.println(ClassName.m());
System.out.println((new ClassName()).m());
}
}
Consider the following, adding on to reason 2, as alluded to by #emory:
class ClassName {
// perhaps ClassName has some caching mechanism?
static final List<ClassName> badStructure = new LinkedList<ClassName>();
ClassName() {
// Note this also gives outside threads access to this object
// before it is fully constructed! Generally bad...
badStructure.add(this);
}
public static void main(String[] args) {
ClassName c1 = new ClassName(); // create a ClassName object
c1 = null; // normally it would get GC'd but a ref exist in badStructure! :-(
}
}
Consider the following, reason 3:
class BadSleep implements Runnable {
int i = 0;
public void run() {
while(true) {
i++;
}
}
public static void main(String[] args) throws Exception {
Thread t = new Thread(new BadSleep());
t.start();
// okay t is running - let's pause it for a second
t.sleep(1000); // oh snap! Doesn't pause t, it pauses main! Ugh!
}
}
From an external observer's perspective, there's no difference. Both ways result in a call to the method which can only do the exact same thing in either case. You should never do the second one, though, as it just doesn't make sense to create an object in that case.
If m() is a static method, it's generally correct practice to use ClassName.m() since m() is a method of ClassName, not an object of ClassName.

Java: Can't access variable?

So i'm having a bit of a problem trying to compare two strings declared in the Main class. I've messed around with it and i really can't get it to work! The problem is in the if() statement where i compare the variables...
public class Main {
public String oldContent = "";
public String newContent = "";
public static void main(String[] args) throws InterruptedException {
Main downloadPage = new Main();
downloadPage.downloadPage();
oldContent = newContent;
for (;;) {
downloadPage.downloadPage();
if (!oldContent.equals(newContent)) { // Problem
System.out.println("updated!");
break;
}
Thread.currentThread().sleep(3000);
}
}
private void downloadPage() {
// Code to download a page and put the content in newContent.
}
}
the variables are instance members, whereas the for happens in a static method.
try moving the actual function to an instance method (not static), or conversely make the data members static as well.
You may use name of the object you have created (downloadPage ) to access to the parameters:
in the main finction use following instead of parameter names only:
downloadPage.oldContent
downloadPage.newContent
The variables are inside the Main object:
public static void main(String[] args) throws InterruptedException {
Main downloadPage = new Main();
downloadPage.downloadPage(); // Access them like you accessed the method
downloadPage.oldContent = downloadPage.newContent;
for (;;) {
downloadPage.downloadPage();
if (!downloadPage.oldContent.equals(downloadPage.newContent)) {
System.out.println("updated!");
break;
}
Thread.currentThread().sleep(3000);
}
}
Do consider using getters and setters instead of exposing the fields.
See non static/ static variable error

Categories

Resources