I've been trying to understand the difference between nested, local, anonymous classes and I'm confused about a few things, but mostly why you cannot do this:
class OuterClass {
InnerClass innerClass = new InnerClass() {
//DO SOMETHING
};
}
w/o doing this...
class OuterClass {
class InnerClass {
}
InnerClass innerClass = new InnerClass() {
//DO SOMETHING
};
}
or this...
class OuterClass {
InnerClass innerClass = new InnerClass() {
//DO SOMETHING
};
}
class InnerClass {
}
How is this at all different from this really?
class OuterClass {
InnerClass innerClass = new InnerClass();
innerClass.innerClassMethod();
}
class InnerClass {
public void innerClassMethod() {
}
}
And why is it called anonymous? I dont understand that. Reading this link here I understand the logistical differences (i.e. no name, only 1 instantiation, only accessible where defined, etc. But it's really not a class so why is it called a class? It's actually, from what I can see an instantiation of a class. I see you can have other methods as well from the class it is derived from, but how are you allowed to have completely different methods than the base class w/o having to use #Override?
Everywhere you have written 'DO SOMETHING' you are actually creating a new class that inherits from whatever type is behind the 'new' Keyword...
This temporary class has no name of its own, hence anonymous.
It ends with ; because it is actually just a parameter of the outer class.
As Silvio pointed out in the comments all classes extend some class, even if it just the Object class.
You can't do this:
class OuterClass {
InnerClass innerClass = new InnerClass() {
//DO SOMETHING
};
}
Because InnerClass does not exist yet to inherit from.
Two points about that what you're doing there with InnerClass innerClass = new InnerClass() {};
First you're using the class InnerClass as a template that you extend by another anonymous class, instantiate that and save that reference to the variable innerClass.
So InnerClass has to be defined.
And because there is no available named class definition for the object named innerclass, this is why it's anonymous.
Second, your comment //DO SOMETHING in there is wrong. The only thing you can do in there is to override already existing methods. Yes, you can also add new methods, but you cannot call the from the outside directly.
InnerClass could be a normal class, an abstract class, or an interface.
Defining class InnerClass {} inside another class would be a nested class. The way you do it it is dependent on the state of the OuterClass.
This could also be static, i.e. decoupled from any instance that Outerclass and its generica parameters would have.
Your third example is a normal (additional) class definition inside a file. But because Java Language Specification defines that there can not be two top-level public classes in one file, this second class definition cannot be public. Because JLS also states that the one top-level public class inside a file has to have the same name as the file it's defined in.
And to answer your last question, in reference to what I said about 'not being able to acces other methods': In your last example you explicitly define the method innerClassMethod() in a names class, and so it can be accessed.
Related
I'm reading about some articles[1][2] online about nested interface in Java, I understand that
interface A {
...
interface B { // this is static by default
...
}
}
But I'm not sure that
class C {
...
interface D { // Is this static by default? Why?
...
}
}
In short, is that "a nested interface is always static" true?
[1] https://beginnersbook.com/2016/03/nested-or-inner-interfaces-in-java/
[2] https://www.programcreek.com/2013/08/inner-interface-in-java/
a non-static inner class is just syntax sugar. A non-static inner class is exactly the same as a standard 'outer' class, with one exception: It has an invisible field of the type of your outer class which is declared final. ALL constructors of your inner class have as first parameter the instance of the outer to which this field must be set.. and then there's a biiig sack of syntax sugar thrown all over this to also hide those.
But that's really how it works, and you can use javap to confirm it. So, given:
public class Outer { public class Inner {} }
versus:
public class Outer {}
class Desugared {
private final Outer outer;
public Desugared(Outer outer) { this.outer = outer; }
}
these things are the same except for syntax:
Outer o = new Outer();
o.new Outer.Inner();
is the same as:
Outer o = new Outer();
new Desugared(o);
etcetera.
Here's the thing: interfaces do not have fields.
Given that they don't, they cannot have this hidden field. And therefore they cannot be 'non-static'. They are therefore implicitly 'static' (they do not have an instance of the outer class implicitly available to them), and you can't change that.
Yes, your "in short" is always true. Quoting directly from the language spec:
A member interface is implicitly static(§9.1.1). It is permitted for the declaration of a member interface to redundantly specify the static modifier.
where "member interface" is defined shortly before:
A member interface is an interface whose declaration is directly enclosed in the body of another class or interface declaration (§8.1.6, §9.1.4).
Classes might be instantiated, interfaces can not be instantiated.
Meaning: when you have an inner class, you might or might not want to create an instance of that inner class with an "outer" object or not.
Assume you have:
class X {
... class Y {
then both someInstanceOfX.new Y() and new X.Y() might make sense.
But when you have an inner interface, the only use of that interface would be with some other class going implements C.D. There is no meaningful way to access C.D that would suggest that D should not be static.
Just as your second link says:
Because an interface can not be instantiated, the inner interface only makes sense if it is static.
In the book 'Java OCP 8 Programmer II Study Guide', it is said that
an anonymous inner class is a local inner class
and
a local inner class is a nested class defined within a method
However, I am able to define an anonymous inner class outside a method:
public class Outer {
Foo ex = new Foo {
#Override
public void bar() {
System.out.println("This is my bar implementation");
}
}
}
void TestClass {
public static void main(String[] args) {
Outer outer = new Outer();
outer.ex.bar();
}
}
Is the book wrong in saying that an anonymous inner class is a local inner class as it doesn't have to be local (within a method) or is the example I provided not an anonymous inner class (as it is assigned to a named variable)?
Thanks
ex is not a local class. anything that a local class cannot be anonymous and vice-versa (to the best of my knowledge)
Quoting from Oracle's Java OO tutorial on Anonymous Classes :
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.
Couple of lines below ..
While local classes are class declarations, anonymous classes are expressions, which means that you define the class in another expression
As I have recently started programming, I was a little stuck in this area of coding.
There is a programming lesson named nested classes. But when I want to use it, it actually does not do what the homework wants. Here is an example of what I need to achieve:
public class Zoo {
...
public static class monkey {
...
}
}
and in the main
Zoo zoo1 = new Zoo();
...
zoo1.monkey.setage(int);
...
But there is a problem here that whenever I want to call monkey from zoo1, the debugger says that it's not possible.(Remember that I want to do this without creating an instance of monkey)
Thanks in advance
Update: I am just wondering if it's a kinda language limitation, then how the oracle itself could do that rather easily with system.out.printf?
You can not access the monkey class via an instance of Zoo, it would not actually make any sense to do that. If you want to access static methods of monkey from the main you can just use the example below
public class Zoo {
public static void main(String[] args) {
// Example 1
monkey.setage(3);
// Example 2
Zoo.monkey.setage(3);
}
public static class monkey {
private static int age;
public static void setage(int age) {
monkey.age = age;
}
}
}
But what are you actually trying to accomplish?
monkey looks static to me. They should be public instead of Public, though.
I would say that setage() is not a static method. If that's the case, and if age is a property of a monkey, than it wouldn't make sense to call it statically -- whose age would you be setting?
The problem though is that you can't seem to be able to access the static inner class through a variable of the outer class type.
So it should be Zoo.monkey instead of zoo1.monkey.
If you just want to control scoping or naming, you can use packages.
For example, you could have the following:
package com.example.application.feature;
public class MyClass {
public void f() {
System.out.println("Hello");
}
}
in a source file called com/example/application/feature/MyClass.java.
Edit: I didn't see you note "(Remember that I want to do this without creating an instance of monkey)"
sometimes before asking, searching might help you to save some time.Direct Quotion from this address: http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html
Inner Classes
As with instance methods and variables, an inner class is associated
with an instance of its enclosing class and has direct access to that
object's methods and fields. Also, because an inner class is
associated with an instance, it cannot define any static members
itself.
Objects that are instances of an inner class exist within an instance
of the outer class. Consider the following classes:
class OuterClass {
...
class InnerClass {
...
} }
An instance of InnerClass can exist only within an instance of
OuterClass and has direct access to the methods and fields of its
enclosing instance. The next figure illustrates this idea.
An Instance of InnerClass Exists Within an Instance of OuterClass
To instantiate an inner class, you must first instantiate the outer
class. Then, create the inner object within the outer object with this
syntax:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Additionally, there are two special kinds of inner classes: local
classes and anonymous classes (also called anonymous inner classes).
Both of these will be discussed briefly in the next section.
How can I load a class that is already on the class path, instantiate it, and also instantiate any inner classes defined within it?
EG:
public class TestClass {
public class InnerClass { }
}
Inner classes cannot exist outside the parent class. You need to construct the parent class first. Without reflection this would look like:
InnerClass innerClass = new TestClass().new InnerClass();
In reflection, you need to pass the parent class in during construction of the inner class.
Object testClass = Class.forName("com.example.TestClass").newInstance();
for (Class<?> cls : testClass.getClass().getDeclaredClasses()) {
// You would like to exclude static nested classes
// since they require another approach.
if (!Modifier.isStatic(cls.getModifiers())) {
Object innerClass = cls
.getDeclaredConstructor(new Class[] { testClass.getClass() })
.newInstance(new Object[] { testClass });
}
}
As a side note, given that your primary question has been answered - often people will declare inner classes as in your example above, without giving a thought to whether they can be static inner classes instead.
In my experience, the vast majority of (non-anonymous) inner classes can be static, as they don't need to access their parent class' instance members. Declaring the inner class as static in this case is both more efficient (as the runtime doesn't need to define a new class for each parent instance), less confusing (since new TestClass().new InnerClass().getClass() != new TestClass().new InnerClass().getClass()) and easier to instantiate if you don't have an appropriate instance of TestClass handy.
So if this applies to you, you could (and arguably should) declare you inner class thusly:
public class TestClass {
public static class InnerClass { }
}
and then you can simply instantiate it as new TestClass.InnerClass().
(If you need to access member fields from within InnerClass, then just ignore all this of course!)
Class.forName("your classname").newInstance().
The inner classes will be instantiated only if the constructor instantiates them.
I have seen Java code that says something like:
SomeClass.this.someMethod(someArg);
Blah(AnotherClass.class);
Blah(YAClass.this);
What do "this" and "class" mean here? I am used to them as keywords to refer to the current object and to define a class, but this is different. My Java book and online searches have not yielded any explanation.
SomeClass.this/YAClass.this - the this reference of an inner class' enclosing SomeClass/YAClass class.
class SomeClass {
private InnerClass {
public void foo() {
SomeClass outerThis = SomeClass.this;
[...]
}
}
}
(You need to be very careful which this you get particularly when dealing with operations that could be applied to any Object reference. A common case is syncronising on this in an inner class, when the code should be synchronising on the outer instance (a better approach in this case is to use an explicit lock object).)
AnotherClass.class - the java.lang.Class object for the AnotherClass class. Prior to Java 1.5 this was implemented using Class.forName (initialising the class); from 1.5 the ldc bytecode has been extended for direct support.
Class<AnotherClass> clazz = AnotherClass.class;
Both were introduced in Java 1.1.
A quick example for inner class, to complete the other answers:
class SomeClass {
public void someMethod() {
System.out.println("Hello, I have someMethod");
}
public void otherMethod() {
addListener(new MyListener() {
public void someMethod () {
System.out.println("I too, have someMethod");
}
public void listen() {
// I will call someMethod of SomeClass:
SomeClass.this.someMethod();
}
});
}
}
The .class syntax refers to a particular instance of the Class class.
The .this syntax is usually used from within inner classes to refer to the enclosing instance of the top-level class. If you used just this from within an inner class it would refer to the instance of the inner class and not the enclosing class.
.class refers to the Class object corresponding to your instance's class. Java keeps one Class around in memory per referenced type.
Here is the Javadoc for Class: http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html
The only time I have seen SomeClass.this used is when you are dealing with nested classes, and need to refer to the instance of the outer class from the inner class. See here for an example: http://juixe.com/techknow/index.php/2009/04/07/java-nested-inner-class-this/