Java: Anonymous inner class using a local variable - java

How can I get the value of userId passed to this method in my anonymous inner subclass here?
public void doStuff(String userID) {
doOtherStuff(userID, new SuccessDelegate() {
#Override
public void onSuccess() {
Log.e(TAG, "Called delegate!!!! "+ userID);
}
});
}
I get this error:
Cannot refer to a non-final variable userID inside an inner class defined in a different method
I'm pretty sure I can't assign it as final since it's a variable with an unknown value. I had heard that this syntax does preserve scope in some way, so I think there must be a syntax trick I don't quite know yet.

As everyone else here has said, local variables have to be final to be accessed by an inner class.
Here is (basically) why that is... if you write the following code (long answer, but, at the bottom, you can get the short version :-):
class Main
{
private static interface Foo
{
void bar();
}
public static void main(String[] args)
{
final int x;
Foo foo;
x = 42;
foo = new Foo()
{
public void bar()
{
System.out.println(x);
}
};
foo.bar();
}
}
the compiler translates it roughly like this:
class Main
{
private static interface Foo
{
void bar();
}
public static void main(String[] args)
{
final int x;
Foo foo;
x = 42;
class $1
implements Foo
{
public void bar()
{
System.out.println(x);
}
}
foo = new $1();
foo.bar();
}
}
and then this:
class Main
{
private static interface Foo
{
void bar();
}
public static void main(String[] args)
{
final int x;
Foo foo;
x = 42;
foo = new $1(x);
foo.bar();
}
private static class $1
implements Foo
{
private final int x;
$1(int val)
{
x = val;
}
public void bar()
{
System.out.println(x);
}
}
}
and finally to this:
class Main
{
public static void main(String[] args)
{
final int x;
Main$Foo foo;
x = 42;
foo = new Main$1(x);
foo.bar();
}
}
interface Main$Foo
{
void bar();
}
class Main$1
implements Main$Foo
{
private final int x;
Main$1(int val)
{
x = val;
}
public void bar()
{
System.out.println(x);
}
}
The important one is where it adds the constructor to $1. Imagine if you could do this:
class Main
{
private static interface Foo
{
void bar();
}
public static void main(String[] args)
{
int x;
Foo foo;
x = 42;
foo = new Foo()
{
public void bar()
{
System.out.println(x);
}
};
x = 1;
foo.bar();
}
}
You would expect that foo.bar() would print out 1 but it would actually print out 42. By requiring local variables to be final this confusing situation cannot arise.

Sure you can assign it as final - just put that keyword in the declaration of the parameter:
public void doStuff(final String userID) {
...
I'm not sure what you meant about it being a variable with an unknown value; all that final means is that once a value is assigned to the variable, it cannot be re-assigned. Since you're not changing the value of the userID within your method, there's no problem making it final in this case.

In Java 8, this has changed a little bit. You can now access variables that are effectively final. Relevant snippet and example from the Oracle documentation (emphasis mine):
However, starting in Java SE 8, a local class can access local
variables and parameters of the enclosing block that are final or
effectively final.
Effectively final: A non-final variable or parameter whose value is never changed after it is initialized is effectively final.
For example, suppose that the variable numberLength is not declared final, and you
add the highlighted assignment statement in the PhoneNumber
constructor:
PhoneNumber(String phoneNumber) {
numberLength = 7; // From Kobit: this would be the highlighted line
String currentNumber = phoneNumber.replaceAll(
regularExpression, "");
if (currentNumber.length() == numberLength)
formattedPhoneNumber = currentNumber;
else
formattedPhoneNumber = null;
}
Because of this assignment statement, the variable numberLength is not
effectively final anymore. As a result, the Java compiler generates an
error message similar to "local variables referenced from an inner
class must be final or effectively final" where the inner class
PhoneNumber tries to access the numberLength variable:
if (currentNumber.length() == numberLength)
Starting in Java SE 8, if you declare the local class in a method, it
can access the method's parameters. For example, you can define the
following method in the PhoneNumber local class:
public void printOriginalNumbers() {
System.out.println("Original numbers are " + phoneNumber1 +
" and " + phoneNumber2);
}
The method printOriginalNumbers accesses the parameters
phoneNumber1 and phoneNumber2 of the method validatePhoneNumber

What's the problem with making it final as in
public void doStuff (final String userID)

declare the method
public void doStuff(final String userID)
The value needs to be final so that the compiler can be sure it doesn't change. This means the compiler can bind the value to the inner class at any time, without worrying about updates.
The value isn't changing in your code so this is a safe change.

Related

Why cant instance variable be initialised in class?

This is my code:
public class MyClass {
int x;
MyClass m1 = new MyClass();
m1.x=10;
}
Why does line m1.x=10; result in error?
if you want to assign value to the variable x,
the line initializes it should be placed in specific method like below.
did you intend to do this?
public class MyClass
{
int x;
public static void main(String[] args)
{
MyClass m1 = new MyClass();
m1.x = 10;
}
}
Use instance initialization block:
public class MyClass {
int x; // define x variable
MyClass m1 = new MyClass(); // initialize m1 variable
{
m1.x=10; // assign 10 to m1.x (this is assignment statement)
}
}
Out of block you can do only defining and initializing variables, not assignment statement.
There are two errors in your code:
MyClass m1 = new MyClass();
This is an infinite recursion.
m1.x=10;
This is a statement, and as such should be within a method or constructor, not the class body.
The problem here is the code m1.x=10;
This line shows an operation or behavior which is only permissible within a block of code.
Valid Code for this operation.
public class MyClass {
int x;
public void assignOperation() {
this.x = 10;
}
public static void main( String[] args ) {
MyClass myClass = new MyClass();
myClass.assignOperation();
System.out.println( "Assigned value is " + this.x )
}
}
Another valid example outside of a method but within the class body will be :
public class MyClass {
static int x;
static {
x = 10;
}
public static void main( String[] args ) {
System.out.println( "Assigned value is " + x )
}
}
making variable x static doesn't need us initialize an object of the class MyClass.

Calling virtual method from a constructor

Java 8
I was just a little perplexed by that we could not call virtual method from a constructor. The pitfall is that we can overload it and crash. But what if we call it from within a constructor of a final class. Like this:
public final class MyClass implements MyInterface {
private final Object[] arr;
public MyClass(){
Object[] arr;
//init arr
this.arr = arr;
//Now we have to preprocess it
preprocess();
}
#Override
public void preprocess(){
//impl
}
public int count(){
//impl
}
}
public interface MyInterface{
void preprocess();
int count();
}
Are there other pitfalls with calling virtual methods from within a constructor? Of course, I can extract preprocess into a static method and then call it from both, but it looks a little messy. I'd like to keep code as clean as possible.
You should always take care when calling methods from a constructor, because the object construction is not yet complete. This is true even for final and private methods, which cannot be overridden by subclasses.
Example:
public class Test {
public static void main(String[] args) {
new Sub().test();
}
}
class Base {
int b;
Base() {
test();
this.b = 1;
}
void test() {
System.out.println("Hello from Base. b = " + this.b);
}
}
class Sub extends Base {
int s;
Sub() {
test();
this.s = 2;
}
#Override
void test() {
System.out.println("Hello from Sub. b = " + this.b + ", s = " + this.s);
}
}
OUTPUT
Hello from Sub. b = 0, s = 0
Hello from Sub. b = 1, s = 0
Hello from Sub. b = 1, s = 2
test() is called 3 times: From Base constructor, from Sub constructor, and from main().
As you can see, even field b was not yet initialized on the first call.
So, is it illegal to do it? No.
Should you avoid it? Yes.
Just make it clear (e.g. javadoc) that the method may be called on partially initialized objects.

Java initial values?

If I were to do something such as:
public class Game
{
private boolean RUNNING = true;
Game()
{
}
public static void main(String[] args)
{
Game game = new Game();
}
}
At what point in time would RUNNING = true?
edit: for clarity, at what point in the program would running be set to true. ex: Before the constructor, after the constructor, etc.
It will be set to true before the constructor. You can use it in the constructor as true.
This code explains itself:
public class SuperClass
{
String superField = getString("superField");
public SuperClass()
{
System.out.println("SuperClass()");
}
public static String getString(String fieldName)
{
System.out.println(fieldName + " is set");
return "";
}
public static void main(String[] args)
{
new ChildClass();
}
}
class ChildClass extends SuperClass
{
String childField = getString("childField");
public ChildClass()
{
System.out.println("ChildClass()");
}
}
OUTPUT:
superField is set
SuperClass()
childField is set
ChildClass()
When the constructor is called using the new operator all non-static members of the class are initialized before the code inside the constructor is executed. You can use the debugger and step into that call and see where it goes first. Static members are initialized when the class is loaded and for the first time accessed (see this question for more detailed info about static members).
private boolean RUNNING = true;
Game() {
}
is exactly the same as
private boolean RUNNING;
Game() {
RUNNING = true;
}
Actually, the comiler will move the initialization at the beginning of the constructor. The value will then be set when instantiating an object of that class.
When you try to use local variables which not manually initialized, you will get a compile time error.
public static void main(String args[]){
int a;
System.out.pritnln(a); //error
}
But it's not the case with instance variables. This itself shows that they are ready for usage before the constructor even.
public class Example{
private int a;
public Example(){
System.out.println(a); //No error
}
public int getA(){
return a; //No error
}
}
I hope this intuition answers your question..........

Output of Java program

I am a Java beginner.
Can anyone explain why is it printing output 2?
interface Foo {
int bar();
}
public class Beta {
class A implements Foo {
public int bar() {
return 1;
}
}
public int fubar(final Foo foo) {
return foo.bar();
}
public void testFoo()// 2
{
class A implements Foo {
public int bar() {
return 2;
}
}
System.out.println(fubar(new A()));
}
public static void main(String[] args) {
new Beta().testFoo();
}
}
That is because you redefined Class A here:
class A implements Foo {
public int bar() {
return 2;
}
}
System.out.println(fubar(new A()));
So when you do return foo.bar(); you return 2
Because the innermost definition of A is in the testFoo() method, and its method bar() return 2.
You may also find the answer to my question from today interesting.
When you say, System.out.println(fubar(new A()));
the class A created is the one defined inside testFoo().
There are many places in java where you can hide a broader name with a more local name. This is true of parameters vs member variables, class names etc. In your case, you are hiding Beta.A with the A you defined in the method.

Inheritance in Java

Consider the following code in Python:
class A(object):
CLASS_ATTRIBUTE = 42
def f(self):
return "CLASS_ATTRIBUTE: %d" % self.CLASS_ATTRIBUTE
class B(A):
CLASS_ATTRIBUTE = 44
Now A().f() and B().f() return "CLASS_ATTRIBUTE: 42" and "CLASS_ATTRIBUTE: 44" respectively.
How can I achieve a similar effect in Java? I want a CLASS_ATTRIBUTE field to be initialized statically and redefined in the inherited class but the f method should be only defined in the base class.
Is there a particular reason you want the attribute to be static? In Java the typical way you'd do this is to have A contain a protected variable that you then set in the constructors of the 2 classes:
public class A
{
protected int CLASS_ATTRIBUTE;
public A()
{
CLASS_ATTRIBUTE = 42;
}
public String f()
{
return "CLASS_ATTRIBUTE: " + CLASS_ATTRIBUTE;
}
}
public class B extends A
{
public B()
{
CLASS_ATTRIBUTE = 44;
}
}
Alternatively (and probably more consistent with Java design patterns) you'd declare a function that you can override to return the value instead of using a member variable.
Short answer: you cant solve it like this in Java. You'll have to solve it in another way.
In Java you can't override or "redeclare" fields in subclasses, and you can't override static methods.
It can be solved using an ugly reflection-hack (should be avoided though):
public class Main {
public static void main(String... args) {
A a = new A();
B b = new B();
System.out.println(a.f()); // Prints 42.
System.out.println(a.fReflection()); // Prints 42.
System.out.println(b.f()); // Prints 42.
System.out.println(b.fReflection()); // Prints 44.
}
}
class A {
static int CLASS_ATTRIBUTE = 42;
public int f() {
return CLASS_ATTRIBUTE;
}
public int fReflection() {
try {
return getClass().getDeclaredField("CLASS_ATTRIBUTE").getInt(null);
} catch (Exception wontHappen) {
return -1;
}
}
}
class B extends A {
// Compiles, but will not "override" A.CLASS_ATTRIBUTE.
static int CLASS_ATTRIBUTE = 44;
}
You can't do this directly with only a variable, because in Java variables cannot override (they only shadow the super classes variables).
You need to use a protected "getter" method, which can then be overridden by the subclass:
class A
{
private int attribute=42;
...
protected int getAttribute() {
return attribute;
}
}
class B
extends A
{
private int attribute=44;
...
protected int getAttribute() {
return attribute;
}
}
But note there's a special consideration to calling methods from an object's constructor, in that it allows object code to run before object construction is complete.
I'm not sure if you meant "statically" literally or not, but here's a brief example of how inheritance at it's most basic form looks in Java. Note that using a getter method to access the variable is a better idea for several reasons -- this is just an example.
public class Dog {
protected String whatISay = "Woof!";
public void speak(){
System.out.println(whatISay);
}
}
public class Poodle extends Dog {
public Poodle(){
whatISay = "Yap!";
}
}
public class Main {
public static void main(String[] args){
Poodle fluffy = new Poodle();
fluffy.speak();
Dog dog = new Dog();
dog.speak();
}
}
Yap!
Woof!
This way of doing it introduces as little intrusion as I could think of. setAttribute() could be named something like setDefaultValue() if that's clearer.
public class A
{
protected int attribute;
public A()
{
setAttribute();
}
public String f()
{
return "CLASS_ATTRIBUTE: " + attribute;
}
protected void setAttribute()
{
attribute = 42;
}
}
public class B extends A
{
#Override
protected void setAttribute()
{
attribute = 44;
}
}
public class Main
{
public static void main(String[] args)
{
A a = new A();
B b = new B();
System.out.println("A: " + a.f());
System.out.println("B: " + b.f());
}
}

Categories

Resources