Setting outer variable from anonymous inner class
Java doesn't know that doWork is going to be synchronous and that the stack frame that result is in will still be there. You need to alter something that isn't in the stack.
I think this would work
final Long[] result = new Long[1];
and then
result[0] = st.getLong(4);
in execute()
. At the end, you need to return result[0];
You might want to make a class because you don't like how it looks to use an array here, but this is the basic idea.
Modifying an outer variable within an anonymous inner class
The behavior you are referring to applies only to local variables or method/catch parameters. You can access and, potentially, modify instance members just fine
public class Example {
public void method() {
String localFoo = "local";
new Object() {
public void bar() {
foo = "bar"; // yup
System.out.println(localFoo); // sure
localFoo = "bar"; // nope
}
};
}
private String foo = "foo";
}
The anonymous Object
inner class copies the value of localFoo
for use within the println(..)
invocation. However, for foo
, it's actually "copying" the reference to the Example
instance and referencing its foo
field.
It's actually equivalent to
Example.this.foo = "bar";
How to change outer variable from anonymous inner class?
You're creating a Runnable class, but it actually never runs. You need to "start" it, by calling its start() method.
But you must also keep in mind, that when you start it inside the outerMethod(), it may not run before the Log method is called (since it will run in a separate thread) and the order in which the code is called is not guaranteed anymore.
How to use an outer variable in an anonymous inner class
In JLS 8.1.3. Inner Classes and Enclosing Instances:
When an inner class (whose declaration does not occur in a static
context) refers to an instance variable that is a member of a
lexically enclosing class, the variable of the corresponding lexically
enclosing instance is used.Any local variable, formal parameter, or exception parameter used but
not declared in an inner class must be declared final.
It means you can only use an outside final
variable or an enclosing class member in an anonymous inner class.
/*
* I suggest this solution, but not this approach,
* please be careful with multi-threading programming. :)
*/
// [...]
// private List<WMSMaterial> listMaterials; // or using a class member
// [...]
public void insertMaterial(final List<WMSMaterial> listMaterials) {
new Thread(){
public void run(){
com.ssn.acx.api.configuration.ParameterSet ps = com.ssn.acx.api.ACXObjectFactory.getConfigurationFactory().getLocalConfiguration().getParameterSet(com.ssn.acx.api.persistence.ACXPersistenceFactory.CFG_DEFAULT);
com.ssn.acx.api.persistence.ACXPersistenceFactory factory = com.ssn.acx.api.ACXObjectFactory.getPersistenceFactory(ps);
com.ssn.acx.api.persistence.ACXPersistenceSession session = factory.openSession();
com.ssn.acx.api.common.transaction.ACXTransaction tx = null;
try {
tx = session.beginTransaction("InsertMaterial");
for (WMSMaterial material : listMaterials) {
session.getPersistenceSession().insert(material);
}
tx.commit();
} finally { if (tx != null && !tx.closed()) { tx.rollback(); } session.close(); }//end of try-catch-finally block
}//end of run method
}.start(); //end of Thread Object creation
} //end of insertMaterial method
[Update]
As @AndyThomas points out in the comment, Java 8 has effectively final variable that you do not need to explicitly mark a variable as final
:
Certain variables that are not declared final are instead considered effectively final:
It is not declared final.
It never occurs as the left hand side in an assignment expression
. (Note that the local variable declarator containing the
initializer is not an assignment expression.)It never occurs as the operand of a prefix or postfix increment or
decrement operator.
JLS 4.12.4. final Variables
Access method of outer anonymous class from inner anonymous class
Since Java 8 the solution is pretty easy. Just store the method reference in a variable.
ReturnsANumber v = new ReturnsANumber() {
int theNumber() {
return 119;
}
public int getIt() {
Supplier<Integer> supplier = this::theNumber;
ReturnsANumber w = new ReturnsANumber() {
int theNumber() {
return 1;
}
public int getIt() {
return supplier.get();
}
};
return w.getIt();
}
};
Storing outer object could also do the trick. But for inherited methods only:
interface ReturnsANumber {
int theNumber();
int getIt();
}
public int getIt() {
ReturnsANumber outer = this;
ReturnsANumber w = new ReturnsANumber() {
public int theNumber() {
return 1;
}
public int getIt() {
return outer.theNumber();
}
};
return w.getIt();
}
You can store the method reference or the outer object as a field also.
Update
@Holger proposed another workaround. You can pass your outer object to a lambda:
ReturnsANumber v = new ReturnsANumber() {
...
@Override
public int getIt() {
ReturnsANumber w = Optional.of(this).map(outer ->
new ReturnsANumber() {
int theNumber() {
return 1;
}
public int getIt() {
return outer.theNumber();
}
}).get();
return w.getIt();
}
};
Modify local variable from anonymous inner class
You can't modify the local variable. But if the local variable is an object reference, you can modify the object it refers to. For example:
public static void main(String[] args) {
final AtomicReference<String> value = new AtomicReference<String>("hello");
System.out.println(value); // prints "hello"
new Runnable() {
public void run() { value.set("goodbye"); }
}.run();
System.out.println(value); // prints "goodbye"
}
Best practice to access outer class variable in static nested class anonymous method Java
A static nested class InnerClass
cannot access members of the enclosing instance, because an instance of InnerClass
may not be owned by OuterClass
. Imagine this:
public class Outer {
public String out = "out";
public static class StaticInner {
public void printEnclosing() {
System.out.println(Outer.this.out); // Let's say this compiles
}
}
}
public class Test {
public static void main(String[] args) {
StaticInner si = new StaticInner();
si.printEnclosing();
}
}
Note that an instance of Outer
was never ever made. Then how is it possible to print the value of out
?
What you need is inner class. Inner class cannot be instantiated by anyone other than the enclosing class, or its subclasses. This ensure that the only time you can instantiate the inner class is when there is already an instance of the outer class.
public class Outer {
public String out = "out";
public Inner inner = new Inner();
public class Inner {
public void printEnclosing() {
System.out.println(Outer.this.out); // "out" can be safely referenced
}
}
}
public class Test {
public static void main(String[] args) {
Inner inner = new Inner(); // Compile-time error
Outer out = new Outer();
out.inner.printEnclosing(); // This works, because you are calling method of the Inner class instance owned by Outer class.
}
}
Therefore, this is what your code should look like:
public class OuterClass extends CustomAppCompatActiivity {
private EditText city_et;
private final InnerClass inner = new InnerClass();
public class InnerClass extends DialogFragment {
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//the view to access
city_et.setText("");
getDialog().dismiss();
}
});
}
}
public InnerClass getInnerClass() {
return inner;
}
}
Update
For your concern on memory leak, I think the question is: What are the roles of InnerClass
and OuterClass
. Everytime you can create an InnerClass
instance (or a collection of InnerClass
instances) is when you have a new OuterClass
. InnerClass
needs the reference of OuterClass
in order to call setText()
.
Therefore the contract here is: InnerClass
can't exist without OuterClass
, and an InnerClass
always have an InnerClass
. InnerClass
will be garbage collected together with OuterClass
.
If the relationship between InnerClass
and OuterClass
is that InnerClass
can function without OuterClass
, and all you need is the EditText city_et
reference, then you should pass that reference in. Since InnerClass
is independent from OuterClass
now, you can use static nested class, or simply move it to another separate class.
public class OuterClass extends CustomAppCompatActiivity {
private EditText city_et;
public static class InnerClass extends DialogFragment {
private EditText city_et;
public InnerClass(EditText city_et) { // Pass a reference in
this.city_et = city_et;
}
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
okBtn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
//the view to access
city_et.setText("");
getDialog().dismiss();
}
});
}
}
}
This way, an OuterClass
instance can be garbage collected whenever it is qualified to do so, independent of InnerClass
. The only reference that cannot be garbage collected is that EditText
instance.
Update 2
EJP pointed out that "Inner class cannot be instantiated by anyone other than the enclosing class, or its subclasses" is wrong, and after checking out, he's right. On top of that, the term "inner class" is the official term for "non-static nested class."
However, you should still use a static nested class or a separate class if you think that the DialogFragment
subclass could live longer than the enclosing class.
Accessing outer class variable in inner class
Assuming your outer class is called Outer
, from the scope of the inner class(non-static), Outer.this.foo
to get at the field.
For example,
Outer.this.foo=new ArrayList<>();
where Outer is the name of the class and foo
identifies the field.
You can also grab it directly as foo=new Baz()
but it'll pick the inner field if there's a naming conflict due to shadowing.
if it's a static inner class, you need an explicit instance:
outerInstance.foo=new ArrayList<>();
or if the field to access is static, access it as usual with:
Outer.staticFoo=new ArrayList<>();
Related Topics
Noclassdeffounderror While Trying to Run My Jar with Java.Exe -Jar...What's Wrong
Building an Uberjar with Gradle
Creating an X509 Certificate in Java Without Bouncycastle
List All Files in the Folder and Also Sub Folders
How to Emit and Handle Custom Events
Using Two Values for One Switch Case Statement
How Do Format a Phone Number as a String in Java
Java Server with Multiclient Communication
Java: String Concat VS Stringbuilder - Optimised, So What Should I Do
String Variable Interpolation Java
Javafx Exception in Thread "Main" Java.Lang.Noclassdeffounderror: Javafx/Application/Application
Overriding Object.Equals VS Overloading It
Cannot Assign Requested Address Using Serversocket.Socketbind