Java: Manipulating non-static variable from thread? - java

The relevant summary of my code is this:
public class A {
String aString;
public static void main(String[] args) {
B b = new B();
new Thread(b).start();
}
public static class B implements Runnable {
public void run() {
aString = "foo";
}
}
}
I have had a few months of Java coding experience but thread and dynamic vs. static is still rather new to me. In order for the thread to execute properly, class B must be static, or else only the thread executes, not both. My goal is to obviously have the thread execute in the background so that other code that I may have in class A can execute simultaneously. Problem is, if class B is static, I can't manipulate the string aString, as I get the exception non-static variable aString cannot be referenced from a static context.
I've looked up information on this but I have not found anything that relates to fixing this issue in threads. My question is, how can I manipulate aString within class B and still get the thread to work properly (both classes running, not just class B)?

To make your example work, you'll need something like this:
public class A {
volatile String aString;
public static void main(String[] args) throws InterruptedException {
A a = new A();
Thread t = new Thread(a.new B());
t.start();
t.join(); // wait for t to finish
System.out.println(a.aString); // prints "foo"
}
class B implements Runnable {
public void run() {
aString = "foo";
}
}
}
Resolving the static issue is the easy part - see code for how.
I hope the rest of the code helps illustrate some of the issues you need to cater for when using threads.

B is static, so only only exists at the class level, and can therefore not see instance variables of its parent class
public class A {
String aString; // <== instance variable
public static void main(String[] args) {
B b = new B();
new Thread(b).start();
}
public static class B implements Runnable { // <== static class
public void run() {
aString = "foo";
}
}
}
Possible fix. Make aString static too
public class A {
static String aString;
Possible fix. Make B non-static. This is where it gets a bit weird. B now only exists at the instance level of A, so you need to create an A instance first.
public class A {
String aString;
public static void main(String[] args) {
B b = new A().new B(); // <== need to create an A before a B
new Thread(b).start();
}
public class B implements Runnable {
public void run() {
aString = "foo";
}
}
}

You are asking an object instance of class B (which you create using new B() )to access a member variable of an object instance that you haven't created. In your code, there is no object of class B created.
I think that you may be thinking that running the main() method in class A is somehow instantiating an instance of class A - this is not the case.
The following will work because you are creating an instance of A and making that available to your instance of B.
public class A {
String aString;
public static void main(String[] args) {
A a = new A();
B b = new B(a);
new Thread(b).start();
}
public static class B implements Runnable {
private final A a;
public B(A a){
this.a = a;
}
public void run() {
a.aString = "foo";
}
}
}

Related

How to avoid creating object only referenced by inner class in Java?

I'm trying to create some system with inner class. My code can be summarized to something like this.
public abstract class A {
public abstract void doSomething();
}
public class B {
public final ArrayList<A> list=new ArrayList<A>();
public B(){
}
}
public class C {
private int i;
public C(B b){
b.list.add(new A(){
public void doSomething(){
i++;
}
});
b.list.add(new A(){
public void doSomething(){
System.out.println(i);
}
});
}
}
public static void main (String[] arg) {
B manager=new B();
new C(manager);
new C(manager);
new C(manager);
}
A is abstract class that will be inherited as inner class (in my original code it is listener class), B is some kind of manager class that hold list of As, and C hold data it's data should be only modified or read by it's inner class and upon initialization it add A to the class B. Code itself works fine. But problem is as there will be various kinds of C something like C2, C3 that does different thing and this leads to my code overwhelmed with thousands of unassigned object new C(manager); this make debugging extra hard and code looks really ugly. So it seems to me my approach in the first place was wrong but have no idea how to avoid this. So how should I change my approach to not have thousands of unassigned objects?
My suggestion is: try not to use constructors to do operations that depend on state (i). Use static functions, and save the state in a separate class (we call it a “context”).
import java.util.ArrayList;
public class Demo {
// A
abstract static class InnerListener {
public abstract void onEvent();
}
// B
static class ListenerManager {
public final ArrayList<InnerListener> listeners = new ArrayList<InnerListener>();
}
static class SideEffectContext {
public int i = 0;
}
// C
static class ListenerUtil {
public static void setupListeners(ListenerManager manager, SideEffectContext context) {
manager.listeners.add(new InnerListener() {
public void onEvent() {
context.i++;
}
});
manager.listeners.add(new InnerListener() {
public void onEvent() {
System.out.println(context.i);
}
});
}
}
public static void main(String[] arg) {
var manager = new ListenerManager();
var ctxA = new SideEffectContext();
var ctxShared = new SideEffectContext();
ListenerUtil.setupListeners(manager, ctxA);
ListenerUtil.setupListeners(manager, ctxShared);
ListenerUtil.setupListeners(manager, ctxShared);
}
}

Cannot get value of property from extending class

I have two Java classes, one of which inherits from other. They are somewhat like the following:
A.java:
public class A {
public String invocations[] = {"foo"};
public A() {
// do stuff
}
}
B.java:
public class B extends A {
public String invocations = {"bar", "baz"};
public B() {
super();
}
}
In this example, assuming I create an instance of B and get its invocations property, it returns {"foo"} instead of the expected {"bar", "baz"}. Why is this, and how can I get the {"bar", "baz"}?
You have one variable hiding another one. You can refer to a variable in a super class by using a cast to the type explicitly. (I am assuming you fix the syntax errors)
public class Main {
static class A {
public String[] invocations = {"foo"};
}
static class B extends A {
public String[] invocations = {"bar", "baz"};
}
public static void main(String... args) {
B b = new B();
System.out.println("((A)b).invocations=" + Arrays.toString(((A) b).invocations));
System.out.println("b.invocations=" + Arrays.toString(b.invocations));
}
}
prints
((A)b).invocations=[foo]
b.invocations=[bar, baz]

java - can a class type parameter from a static main class be passed to another class

I have 2 classes the static main class and class B. I'm trying to pass main to B, where there is a method that sets fields.
Can this be done?
If so, could you please provide examples?
public static void main(String[] args) {
ArrayList a = new ArrayList()
class b = new class()
b.update(b);
}
class a {
public void update(ArrayList a) {
//updates the encapsulated arrayList field
}
}
The error message keeps on saying that one is static and the other is non-static, but they should be pointing the same object
I'm not entirely sure what you are trying to do, but here is an example that shows that you can pass an instance of the main class into another class:
public class A {
private String str = null;
public static void main(String[] args) {
A a = new A();
B b = new B(a);
System.out.println(a.getStr());
}
public String getStr() {
return this.str;
}
public void setStr(String str) {
this.str = str;
}
}
public class B {
public B(A a) {
a.setA("hello");
}
}
Running this code will print out hello.
main is static and public, so you can call it from any other class as any other public static method: statically.
if you have a class A that contains a
public static void main(String[] args)
method, then class B can call this method like
A.main(s);
where s is String[]
your question is far from clear, so I suggest you to add more code samples to make it clear what you're really trying to do.

Can a superclass type variable refer to a subclass object?

For example:
public class A {
public class B extends A {
}
public static void main(String[] args) {
A a;
a = new B();
}
}
I searched some similar questions and they showed "yes, a superclass type variable can refer to a subclass object". But in eclipse the above code comes up with an error like "No enclosing instance of type A is accessible. Must qualify the allocation with an enclosing instance of type A (e.g. x.new A() where x is an instance of A)."
So what wrong? Thanks!
The answer is "yes" superclass can refer to a subclass, but you're asking the wrong question.
You're getting this error because B is an enclosed class of A (meaning you must have an instance of A to have an instance of B), but you're referring to it from a static method (ie not an instance of A).
Simply change B to be a static class.
public class A {
public static class B extends A { // <-- Added static keyword
}
public static void main(String[] args) {
A a;
a = new B();
}
}
No errors.
The other option is leave it an enclosed class and do this:
public class A {
public class B extends A { // leave B as an enclosed class
}
public static void main(String[] args) {
A a = new A();
a = a.new B(); // can only create a B in the context of an A
}
}
check your parantheses!! It should be:
class A {
}
public class B extends A {
public static void main(String[] args) {
A a;
a = new B();
}
}
Also you have two public classes in your code!!

using methods of other classes to "overwrite" variables

i'm relativly new to java and experimantating a bit with javafx
i want to change a variable from class A while using a method from class B
Main: thats the main class, it contains all the needed stuff(shows the primaryStage etc) it does have an constructor, so its not creating an actual "main-object"
public class Main extends Application {
Sub sub = new Sub();
int a;
// stuff
public void aMethod() {
sub.subMethod();
}
}
Sub: this class solely surpose is to change the variable a, it does not contain a constructor to create a "sub-object"
public class Sub {
//stuff
subMethod(){
int a = 5;
}
if i put the line Main main; in the Sub class, the program will give me a nullpointer exception, if i'm calling the subMethod().
ok...i guess cause i didnt actually create the main object... so far so good.
BUT... if i put in the line Main main = new Main(); the program wont even start giving me an "exception while running application" error
the strange thing though is, if i put the line Main main = new Main(); in the subMethod...
subMethod(){
Main main = new Main();
int a = 5;
}
...the damn thing actually works...(well its slow, guess because with every calling of the method its creating a new object)
why is that so?
and how is it done correctly? :)
(using methods of other classes to "overwrite" variables)
regards
Red
You should not create more than one instance of Main in your program. Probably Main is not the best place to store mutable state (class members), but if you want that, you need to pass the instance of Main to subMethod (and make a public, or provide a public setter method):
public class Main extends Application {
Sub sub = new Sub();
public int a;
// stuff
public void aMethod() {
sub.subMethod(this);
}
}
public class Sub {
//stuff
subMethod(Main main){
main.a = 5;
}
So you want a method to change the value of another class's fields. There are a few ways to do this. If you have this class
public Class A {
private int a;
...
public void setA(int a) {
this.a = a;
}
}
You can do something like this
public Class B {
private static A instance;
....
public static void setA(int a) {
instance.setA(a);
}
}
Or you can take the A in as a parameter to the set method
public Class B {
...
public static void setA(A a, int val) {
a.setA(val);
}
}
If you want direct access to the fields on A you have to make them public (this is usually not what you want to do as it gives complete access rather than just giving just the access the other classes require)
Public Class A {
public int a;
...
}
Then you can do
Public Class B {
...
public static void setVal(A a, int val) {
a.a = val;
}
}
Also if you don't have the method setA in B as static you'll have to call it on an instance of B like
B b = new B();
b.setA(a, val);
Where as if it's static you call it on the class B
B.setA(a, val);

Categories