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/
Related
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
Is there a way to capture the type of an anonymous class?
In the following example, how can i invoke the method g2 of the anonymous class? can't think of a specific case that it would be absolutely useful. and i'm aware that anonymous classes are for "on-the-fly" use. however, wondering.
If i can't invoke it, what's the use of being able to define it (if any-- other than being a helper to other methods of the anonymous class itself) in the anonymous class?
// http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
public class SomeClass {
abstract class HelloWorld { abstract public void greet(); }
public void sayHello() {
class EnglishGreeting extends HelloWorld { // local class
String name = "world";
public void greet() { System.out.println("Heya " ); }
public void gg() { System.out.println("do this as well.. ");} }
HelloWorld englishGreeting = new EnglishGreeting();
HelloWorld frenchGreeting = new HelloWorld() { // anonymous class
public void g2() { System.out.println("do this too.. ");}
public void greet() { System.out.println("Salute "); }
};
englishGreeting.greet();
((EnglishGreeting)englishGreeting).gg();
frenchGreeting.greet();
// ((frenchGreeting.getClass())frenchGreeting).g2(); // gives a checked error
}
public static void main(String... args) {
SomeClass myApp = new SomeClass();
myApp.sayHello();
}
}
Note: saw Can't call anonymous class method & Anonymous Inner Classes Inside Methods along with some other relevant discussions.
TIA.
//==============================================
EDIT:
the below worked-- one step closer to it for whatever its worth. not looking up its reference type when the method is invoked right on the new object.
HelloWorld frenchGreeting = new HelloWorld() {
public HelloWorld g2() { System.out.println("do this too.. "); return this; }
public void greet() { System.out.println("Salute "); }
}.g2();
You can only call it directly, e.g.
new HelloWorld() {
// ...
}.g2();
However, notice that you can't assign the variable and call it directly, and you can't call it elsewhere in the method. Still, this is the closest thing I could think of to answering your question.
no, you cannot call g2. actually, anonymous class in java serves as a short hand to implement an instance of an interface only used in one place. with specified interface, the method you want to be called should be specifically defined by that interface.
the reason to allow you define non-interface method is because designers considered the case when you want to implement helper method.
i think anonymous interface is widely used.
Is there a way to capture the type of an anonymous class?
No. You can only access it for reflection.
If i can't invoke it, what's the use of being able to define it (if any-- other than being a helper to other methods of the anonymous class itself) in the anonymous class?
Since they can only be referenced from within the anonymous type itself, they are of no use outside of it. So, as you say, they may be used to organize the logic within the class, but that's about it. The only exception is the edge case that #bcsb1001 describes, in which you invoke the method directly on the anonymous object creation expression (and not the variable to which it is assigned).
the below worked...
That's because the type of the expression new HelloWorld() { ... } is the type of the anonymous class. Since the creation expression has the actual anonymous class type, you can use it to access any members it declares. However, since the class is anonymous, it has no name, so you cannot declare a variable of the concrete anonymous type. The closest you can get is declaring a variable of HelloWorld. Since the variable is declared as HelloWorld, you can only use it to access members declared on HelloWorld or one of its supertypes.
If Java added support for inferred types in declarations, you could write something like var g = new HelloWorld() { ... }; (C# style) or auto g = new HelloWorld() { ... }; (C++ style), and the type of g would be inferred from the assignment. That would allow you to capture the anonymous type without needing a type name. However, Java has no such capabilities at this time.
Example:
interface Outer {
default String get() {
return "hi";
}
class Inner {
String got() {
return get();
}
}
}
This yields the error
java: non-static method get() cannot be referenced from a static context.
The inner interface/class is always static; unlike with an outer class where it's non-static unless declared static.
This is how things are today and in the upcoming java 8. Is there a fundamental reason for this difference between outer classes and outer interfaces?
Update:
After reading #Radiodef´s comment I changed the inner interface to be an inner class. An outer class can't contain a non-static inner interface so the example was confusing. An inner class is really what I would like anyway.
Update: For reference. This is perfectly legal:
class Outer {
String get() {
return "hei";
}
class Inner {
String got() {
return get();
}
}
}
Maybe I misunderstood your question, but your code snippet is exactly equivalent to
interface Outer {
public default String get() {
return "hi";
}
public static class Inner {
String got() {
return get();
}
}
}
As the JLS Chapter 9.5 (Java 8) states
A member type declaration in an interface is implicitly public and
static. It is permitted to redundantly specify either or both of these
modifiers.
So if you did
Inner innerInstance = new Outer.Inner();
innerInstance.got();
what would get() be invoked on? There is no object of type Outer involved here.
Is there a fundamental reason for this difference between outer
classes and outer interfaces?
This isn't the issue. Your class code is an example of inner classes, ie. non static nested class. The interface code is an example of a static nested class. You are comparing two different things.
The equivalent example with a static nested class within an enclosing class would be
class Outer {
String get() {
return "hei";
}
public static class Inner {
String got() {
return get(); // won't compile
}
}
}
where again it doesn't make sense for get() to work since there is no corresponding (enclosing) instance to invoke it on.
If the question, as #Radiodef put it, is
why must the class be implicitly static beyond that this is the
existing spec?
then my answer is the following:
An interface, by definition, is
A point at which independent systems or diverse groups interact
An interface does not have state and it does not have behavior. It simply describes behavior. Interface members are implicitly static because an interface does not have state.
I will provide a way for you to remember it.
For a static member, it's not bound to an object of the declaring class/interface; for a non-static member, it has to bound to an object of the declaring class.
All interface's members are implicitly static, except default ones.
So, in your Exemple: static class Inner is not bound to an object of interface Outer(Since there is no meaning of object of interface), so it can't call the member of Outer.
For your legal one in the Update: class Inner is bound to an object of class Outer, so when you create an object of Inner, you also create an anonymous object of class Outer, so when you call get() in Inner::got(), the get() is called upon that anonymous object.
Hope this help.
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 make something like this work:
class Outer {
int some_member;
abstract class InnerBase {
abstract void method();
}
}
class OuterExtendsInner extends Outer.InnerBase {
OuterExtendsInner(Outer o) { o.super(); }
void method() {
// How do I use some_member here?
// Writing Outer.this.some_member -> error about Outer not being an enclosing class
// Writing just some_member -> no-go, either
}
}
The workaround is to have a method in InnerBase that returns Outer.this and call THAT from derived classes, but is there another way?
I primarily want to extend the InnerBase from outside in order to have better code-organization, but I could move all derived classes into Outer.
The problem here is that the synthetic field which links InnerBase to Outer is a private field. Thus, we can only access the outer object from within InnerBase, or if some method or field there provides a reference to the same object.
You could do this in OuterExtendsInner:
class OuterExtendsInner extends Outer.InnerBase {
Outer o;
OuterExtendsInner(Outer o) {
o.super();
this.o = o;
}
void method() {
// now you can reference o.some_member
int x = o.some_member;
}
}
The answer is: you can't, because it would break encapsulation. Only InnerBase can have access to attributes of Outer, not OuterExtendsInner. It is not direct inheritance. InnerBase does not inherit of Outer.
I haven't tried WhiteFang34's answer. It might work, but I'm not clear on it ...
If you really want to define an extension of your inner class elsewhere than in the outer class, the most natural thing would be to define it as an extension of the inner class in another outer extending your outer class as follows:
class Outer {
int some_member;
abstract class InnerBase {
abstract void method();
}
}
class OuterExtendsOuter extends Outer {
class InnerExtendsInner extends Outer.InnerBase {
void method() {
System.out.println(some_member);
}
}
}
I haven't actually run this code either, but it should work.
Update:
Based on the comment thread, I have now compiled and run both my code above and WhiteFang34's code.
Both in fact work, but as noted in the comments by Paŭlo Ebermann, both create two copies of the outer inside the instantiated inner class.
I'm going to upvote Paŭlo's answer, and would advocate just not trying to do this by either tactic, as it's really an abuse of the inner class mechanism.
Just make your extended inner classes live inside the same outer class!
Update 2:
What happens in my code, based on runtime examination using a debugger and on examining the output from javap inspections of the classes, is that both InnerBase and OuterExtendsOuter$InnerExtendsInner have synthetic private final fields named this$0. Because no constructors are explicitly defined, the default constructors are used, and the code snippet
OuterExtendsOuter outer = new OuterExtendsOuter();
Outer.InnerBase inner = outer.new InnerExtendsInner();
causes these two fields to both reference outer.
In other words, Paŭlo's comment is entirely correct.
By further experimentation, the same actually happens if you extend InnerBase in another inner class of Outer, so it has little to do with it being defined in the same outer class or an extension of it, but is in fact an outcome of how non-static inner classes are handled generally.
I suspect this is documented somewhere, but I haven't seen that.
Probably best to mix inheritance and inner classes as little as possible!
Just have a getter method in the InnerBase?
class Outer {
int some_member;
abstract class InnerBase {
abstract void method();
protected int getSome_Member() // This is possible, because Abstract classes can have non-abstract methods.
{
return some_member;
}
}
}
class OuterExtendsInner extends Outer.InnerBase {
OuterExtendsInner(Outer o) { o.super(); }
void method() {
// you can access "some_member" now
int myNumber = getSome_Member();
}
}
Well your problem is that every instance of InnerBase (I know it's abstract) has to have a reference to an Outer object. That is part of the semantics of nested classes. Instantiating OuterExtendsInner would need such a reference.
You can avoid that making InnerBase a static nested class.
The outer class can extend the inner class iff the inner class is compiled to ".class".
Now, every time you compile the outer class it encounters the "extends innerclass" which is
not yet compiled and the compiler will throw a NoClassDefException or ClassNotFoundException.
Isn't it ? So you will never get that inner class compiled. If you can overcome this problem
then you can also extend the inner class :) .