Error: field name cannot be declared static - java

public class Application {
public static void main(String[] args) {
final class Constants {
public static String name = "globe";
}
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println(Constants.name);
}
});
thread.start();
}
}
Compilation Error: The field name cannot be declared static in a non-static inner type, unless initialized with a constant expression
Solution to this?

Java does not let you define non-final static fields inside function-local inner classes. Only top-level classes and static nested classes are allowed to have non-final static fields.
If you want a static field in your Constants class, put it at the Application class level, like this:
public class Application {
static final class Constants {
public static String name = "globe";
}
public static void main(String[] args) {
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println(Constants.name);
}
});
thread.start();
}
}

From the JLS section 8.1.3:
Inner classes may not declare static members, unless they are constant variables (§4.12.4), or a compile-time error occurs.
So you're fine if you just make the variable final:
public class Application {
public static void main(String[] args) {
final class Constants {
public static final String name = "globe";
}
Thread thread = new Thread(new Runnable() {
#Override
public void run() {
System.out.println(Constants.name);
}
});
thread.start();
}
}
Of course this won't work if you need to initialize it with a non-constant value.
Having said all of this, it's an unusual design, IMO. It's very rare to see a named local class at all, in my experience. Do you need this to be a local class? What are you trying to achieve?

Related

Can we declare a static class inside a static function in java?

What is wrong with the bellow code?
And if something is wrong, please explain in detail with all the rules of static class and functions in java.
public class inner
{
static class in
{
static void inclass()
{
static class infunclass
{
static void fun()
{
System.out.println("Infunclass");
}
}
infunclass.fun();
}
static void infun()
{
System.out.println("Infun");
inclass();
}
}
static void fun()
{
System.out.println("fun");
in.infun();
}
public static void main(String[] args)
{
fun();
}
}
Now when I remove the static keyword before the inclassfun, it showing a different error
public class inner
{
static class in
{
static void inclass()
{
class infunclass
{
static void fun()
{
System.out.println("Infunclass");
}
}
infunclass.fun();
}
static void infun()
{
System.out.println("Infun");
inclass();
}
}
static void fun()
{
System.out.println("fun");
in.infun();
}
public static void main(String[] args)
{
fun();
}
}
static void fun()
^
modifier 'static' is only allowed in constant variable declarations
Can we declare a static class inside a static function in java?
No. The JLS forbids it. The governing parts of the specification are as follows:
"The modifier static pertains only to member classes (§8.5.1), not to top level or local or anonymous classes." JLS 8.1.1
"A member class is a class whose declaration is directly enclosed in the body of another class or interface declaration (§8.1.6, §9.1.4). " JLS 8.5
A class declared directly within a method is a local class, not a member class

Invoking method of anonymous class

Java 7
First of all, I'm going to simplify the example to avoid posting unnecesary code. My specific concrete example a little bit complicated, but I' try to preserve the point.
public class Test {
public static void main(String[] args){
Test t = new Test(){ //<---------------------------------------------------------
public void m(){ // |
Test t = new Test(){// |
public void m(){// |
//Here I need to invoke the most inclosing class's m() method
}
//other actions
};
}
public void someMethod(){
//action
}
};
}
public void m(){
}
}
Is it possible to do in Java? I mean, to invoke the method of anonymous class that way?
No it's impossible because there is no reference to the anonymous classes.
This is the only possible way to call the instance m() method :
new Test(){
public void m(){
}
}.m();
By definition according to the oracle documentation here :
Anonymous classes enable you to make your code more concise. They
enable you to declare and instantiate a class at the same time. They
are like local classes except that they do not have a name. Use them
if you need to use a local class only once
So if you have to use one of the methods of your class you have to create a local one.
You cannot access the methods of the anonymous class using normal java, but you are able using reflection:
Test t = new Test{
public void m() {
System.out.println("Welcome to my class");
}
};
Class<?> c = t.getClass();
Method m = c.getDeclaredMethod("m");
// m.setaccessible(true); // if private
m.invoke(t);
Here is a way to do it:
public class Test
{
public static void main(String[] args)
{
Test t = new Test()
{
public void m() // this one will be called
{
Runnable r = new Runnable()
{
#Override
public void run()
{
m();
}
};
Test t = new Test()
{
public void m()
{
r.run();
}
};
}
};
}
public void m()
{
}
}
If the method returns a value, use Callable<V> instead.

how to invoke method of annoymous class from the main method of the outer class

I'm new to Java and is trying to learn the concept of anonymous class. Could someone please tell me how I can invoke the 'awesomeMethod' from the main method of the LocallClassExample?
public class LocalClassExample {
interface Awesome {
public void awesomeMethod();
}
class AwesomeClass {
public int finalInt= 10;
Awesome a1 = new Awesome() {
#Override
public void awesomeMethod() {
System.out.println(finalInt);
}
};
}
public static void main(String[] args) {
}
}
Consider this:
new AwesomeClass().a1.awesomeMethod();
will invoke the method awesomeMethod() on the member variable a1 (which is something Awesome) of the newly created instance of AwesomeClass.
It will get more tricky once your main is outside of your AwesomeClass - and more so once it's outside of the package. In these cases you'd have to provide a getter like
public Awesome getAwesome() {
return a1;
}
Which would when invoked still execute the method as defined in your anonymous class.
Try to use this to create inner class object as:
public static void main(String[] args) {
LocalClassExample.AwesomeClass oi = new LocalClassExample().new AwesomeClass();
oi.awesomeMethod();
}

Anonymous classes enclosing instances

I'm reading Joshua Blochs "Effective Java" 2nd edition. Currently I'm at item 22 which describes inner and nested classes but I can't understand what does he mean by this sentence:
Anonymous classes have enclosing instances if and only if they occur
in a nonstatic context.
Can someone give me an example of code and explain what does it exactly do ? I know that if InnerClass is a member of OuterClass its enclosing instance is OuterClass, but in terms of annonymous class it sounds strange to me.
public static void main(String[] args) {
Runnable r = new Runnable() {
#Override
public void run() {
System.out.println("hello world");
}
};
}
Here, an anonymous class instance is created from a static context. So it doesn't have any enclosing instance.
public class Foo {
public void bar() {
Runnable r = new Runnable() {
#Override
public void run() {
System.out.println("hello world");
}
};
}
private void baz() {
}
}
Here, an anonymous class instance is created from an instance method. So it has an enclosing instance. The run() method could call baz() or Foo.this.baz(), thus accessing a method from this enclosing instance.
The effect is the same as for non-anonymous inner classes. In essence, it means:
class Outer {
void bar() {
System.out.println("seems you called bar()");
}
void foo() {
(new Runnable() {
void run() {
Outer.this.bar(); // this is valid
}
}).run();
}
static void sfoo() {
(new Runnable() {
void run() {
Outer.this.bar(); // this is *not* valid
}
}).run();
}
}
Because you cannot give the static modifier to anonymous classes, the static property is always inherited from the context.

Lambda this reference in java

I want to convert an anonymous class to a lambda expression. But this anonymous class uses the this keyword.
For example, I wrote this simple Observer/Observable pattern:
import java.util.ArrayList;
import java.util.Collection;
public static class Observable {
private final Collection<Observer> notifiables = new ArrayList<>();
public Observable() { }
public void addObserver(Observer notifiable) { notifiables.add(notifiable); }
public void removeObserver(Observer notifiable) { notifiables.add(notifiable); }
public void change() {
notifiables.forEach(notifiable -> notifiable.changed(this));
}
}
public interface Observer {
void changed(Observable notifier);
}
and this sample code with an anonymous class (use the this keyword):
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(new Observer() {
#Override
public void changed(Observable notifier) {
notifier.removeObserver(this);
}
});
observable.change();
}
}
but when I convert it to a lambda expression:
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
observable.addObserver(notifier -> { notifier.removeObserver(this); });
observable.change();
}
}
I get this compilation error:
Cannot use this in a static context and in a non `static` context
public class Main {
public void main(String[] args) {
method();
}
private void method() {
Observable observable = new Observable();
observable.addObserver(notifier -> {
notifier.removeObserver(this);
});
observable.change();
}
}
The compilation error is:
The method removeObserver(Main.Observer) in the type Main.Observable is not applicable for the arguments (Main)
Is there a way to reference the lambda object with this?
You can't reference to this in a lambda expression. The semantic of this has been changed to reference the instance of the surrounding class only, from within the lambda. There is no way to reference to the lambda expression's this from inside the lambda.
The problem is that you use this in the main() method. The main method is static and there is no reference to an object that represents this.
When you use this inside an instance of an inner class you are referencing to the instance of the inner class.
A lambda expression is not an inner class, this is not referencing to the instance of the lambda expression. It is referencing to the instance of the class you define the lambda expression in. In your case it would be a instance of Main. But since your are in a static method, there is no instance.
This is what your second compilation error is telling you. You hand over an instance of Main to your method. But your method signature requires an instance of Observer.
Update:
The Java Language Specification 15.27.2 says:
Unlike code appearing in anonymous class declarations, the meaning of names and the this and super keywords appearing in a lambda body, along with the accessibility of referenced declarations, are the same as in the surrounding context (except that lambda parameters introduce new names).
The transparency of this (both explicit and implicit) in the body of a lambda expression - that is, treating it the same as in the surrounding context - allows more flexibility for implementations, and prevents the meaning of unqualified names in the body from being dependent on overload resolution.
Practically speaking, it is unusual for a lambda expression to need to talk about itself (either to call itself recursively or to invoke its other methods), while it is more common to want to use names to refer to things in the enclosing class that would otherwise be shadowed (this, toString()). If it is necessary for a lambda expression to refer to itself (as if via this), a method reference or an anonymous inner class should be used instead.
Workaround 1
Your change() method throws ConcurrentModificationException anyway.
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
final Observer[] a = new Observer[1];
final Observer o = er -> er.removeObserver(a[0]); // !!
a[0] = o;
observable.addObserver(o);
observable.change();
}
}
public class Observable {
private final java.util.Collection<Observer> n
= java.util.new ArrayList<>();
public void addObserver(Observer notifiable) {
n.add(notifiable);
}
public void removeObserver(Observer notifiable) {
n.add(notifiable);
}
public void change() {
for (final Observer o : n.toArray(new Observer[n.size()])) {
o.changed(this);
}
}
}
public interface Observer {
void changed(Observable notifier);
}
Workaround 2
I changed the changed(Observable) to changed(Observable, Observer) so that an observer can handle itself.
public class Main {
public static void main(String[] args) {
Observable observable = new Observable();
final Observer o = (er, ee) -> er.removeObserver(ee); // !!
observable.addObserver(o);
observable.change();
}
}
public class Observable {
private final java.util.Collection<Observer> n
= new java.util.ArrayList<>();
public void addObserver(Observer notifiable) {
n.add(notifiable);
}
public void removeObserver(Observer notifiable) {
n.add(notifiable);
}
public void change() {
for (final Observer o : n.toArray(new Observer[n.size()])) {
o.changed(this, o);
}
}
}
public interface Observer {
void changed(Observable notifier, Observer notifiee);
}

Categories

Resources