Let's say we have a class name Home. What is the difference between Home.this and Home.class? What do they refer to?
Home.this
Home.this refers to the current instance of the Home class.
The formal term for this expression appears to be the Qualified this, as referenced in Section 15.8.4 of the Java Language Specification.
In a simple class, saying Home.this and this will be equivalent. This expression is only used in cases where there is an inner class, and one needs to refer to the enclosing class.
For example:
class Hello {
class World {
public void doSomething() {
Hello.this.doAnotherThing();
// Here, "this" alone would refer to the instance of
// the World class, so one needs to specify that the
// instance of the Hello class is what is being
// referred to.
}
}
public void doAnotherThing() {
}
}
Home.class
Home.class will return the representation of the Home class as a Class object.
The formal term for this expression is the class literal, as referenced in Section 15.8.2 of the Java Language Specification.
In most cases, this expression is used when one is using reflection, and needs a way to refer to the class itself rather than an instance of the class.
Home.class returns the instance of java.lang.Class<Home> that corresponds to the class Home. This object allows you to reflect over the class (find out which methods and variables it has, what its parent class is etc.) and to create instances of the class.
Home.this is only meaningful if you're inside a nested class of Home. Here Home.this will return the object of class Home that the object of the nested class is nested in.
Related
There are 2 ways to get a class's Class object.
Statically:
Class cls = Object.class;
From an instance:
Object ob = new Object();
Class cls = ob.getClass();
Now my question is getClass() is a method present in the Object class,
but what is .class? Is it a variable? If so then where is it defined in Java?
That's implemented internally and called a class literal which is handled by the JVM.
The Java Language Specification specifically mentions the term "token" for it.
So .class is more than a variable, to be frank it is not a variable at all. At a broader level you can consider it as a keyword or token.
https://docs.oracle.com/javase/specs/jls/se9/html/jls-15.html#jls-15.8.2
A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void, followed by a '.' and the token class.
A class literal evaluates to the Class object for the named type (or for void) as defined by the defining class loader (§12.2) of the class of the current instance.
That information resides in the class 'file', although classes need not have a physical .class file in the file system. The JVM takes care of making it available from the class definition, as the other answer states.
See also:
https://docs.oracle.com/javase/specs/jvms/se9/html/jvms-4.html
In the following code, I noticed that I can call getWorld() without a reference to the HelloWorld object? But doesn't the implicit 'this' keyword now refer to the inner anonymous class? If so, why I am able to call getWorld()?
public class HelloWorld {
public void getWorld() {
this.setListener(new MyListenerInterface(){
#Override
public void innerMethod() {
getWorld();
}
});
}
}
Ignore the recursion in the code.
The answer is in Section 15.12 of the JLS.
If it is a simple name, that is, just an Identifier, then the name of the method is the Identifier.
If the Identifier appears within the scope of a visible method declaration with that name (§6.3, §6.4.1), then:
If there is an enclosing type declaration of which that method is a member, let T be the innermost such type declaration. The class or interface to search is T.
By using just the simple name of the method, the resolution of which method to call looks up through the enclosing methods until it finds one which has a method with that name, and then attempts to use that method (or methods) to find an exact match.
This is different than the case where you use this.getWorld(), since this refers unambiguously to the inner class instance. That results in a different type of resolution (the Typename . Identifier section of the specification, just below the linked quote), which does not look at the enclosing outer class.
An interesting consequence of this is that you can cause the code to stop compiling by adding a method to the inner class which has the same name, but a different arity. Since it only is searching for the name itself when it tries to determine the class instance to resolve it on, it will try to use the inner class, but not find an exact matching method.
So this:
public class HelloWorld {
public void getWorld() {
this.setListener(new MyListenerInterface(){
#Override
public void innerMethod() {
getWorld();
}
void getWorld(int i){}
});
}
}
would not compile. Method name resolution will discover getWorld in the inner class, and so will stop searching up the hierarchy. But when it tries to do arity resolution, it will see that none of the (one) getWorld methods in the class match, and will fail.
TL;DR - using just the simple name is note quite the same as using this.method(), even though it generally evaluates to the same thing. The language specification has specific rules for handling that case, which can allow it to look in any enclosing instance to find a matching method.
Calling getWorld you get outside the anonymous class and are back at the top level class, so this refers to the object that is creating the anonymous one.
It is like calling a method from other class, this there refers to a different object (not to the caller, but to the callee).
class Main
{
public static void main (String[] args) throws java.lang.Exception
{
}
public class SuperInner{
int a;
}
public class Inner{
public class MegaInner{
public MegaInner(){
Main.SuperInner.this.a = 6; //error: not an enclosing class: Main.SuperInner
}
}
}
}
IDEON
What JLS says is:
Let C be the class denoted by ClassName. Let n be an integer such that
C is the n'th lexically enclosing class of the class in which the
qualified this expression appears.
[...]
It is a compile-time error if the current class is not an inner class
of class C or C itself.
In the case C:=Main, the set of inner classes S := {SuperInner, MegaInner, Inner}. Which means the code above should work fine. What's wrong?
One could have multiple instances of SuperInner, as well as of Inner or MegaInner.
Calling Main.SupperInner.this.a from within MegaInner, it wouldn't be clear which instance (if there is an instance at all) should have the a variable set to 6.
The inner classes behave much like normal classes: one always needs an instance to set a variable in them. Main.SuperInner.this does not denote an instance from MegaInner's view, as this only refers to the class-hierarchy of MegaInner, which SuperInner is not a part of.
The "Qualified this" expression Main.SuperInner.this.a appers inside MegaInner.
The enclosing classes of MegaInner are Inner and Main. So this is the 0th qualified this, Inner.this is the 1st qualified this, and Main.this is the 2nd qualified this.
The part you were missing is that it has to be an enclosing class of the class where the expression with the this appears. SuperInner is not an enclosing class of MegaInner and therefore the Qualified this does not apply to it.
Think about it in reality. A this expression refers to an instance of the class. It does not refer to the class itself. You cannot refer to this from a static method, for example.
Now, when you create an instance of MegaInner, it has to be part of an actual instance of Inner and an actual instance of Main. But there is no guarantee that there is an actual instance of SuperInner. The code of the enclosing classes may create objects of type SuperInner at any time and independently of instances of Inner.
Thus, you can't access a this of it at compile time. But if you are given an instance of it through a reference variable, you are allowed to access the variable a, as they are all members of the same outer class.
From the JLS (§15.8.2):
A class literal evaluates to the Class object for the named type (or for void) as defined by the defining class loader (§12.2) of the class of the current instance.
This makes sense, but what if there is no 'current instance'? (i.e. the expression is in a class method, aka 'static method')
My intuition tells me to use the same rule, swapping out 'class of the current instance' for something like 'class of the class method'. However, I cannot find any such rule in the JLS, which in my experience tends to be very explicit. This makes me uncertain about my intuition.
The alternative is that my assumption that there is no 'current instance' when in a class method, is incorrect. If so - what are the rules for determining the 'current instance' when in a class method?
Class of the current instance indicates the instance of java.lang.Class whose type is T. Even if the class in consideration has static method, It is always an instance of java.lang.Class.
You can get related explanation in Java Documentation for java.lang.Class:
Instances of the class Class represent classes and interfaces in a running Java application. An enum is a kind of class and an annotation is a kind of interface. Every array also belongs to a class that is reflected as a Class object that is shared by all arrays with the same element type and number of dimensions. The primitive Java types (boolean, byte, char, short, int, long, float, and double), and the keyword void are also represented as Class objects.
Class has no public constructor. Instead Class objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the defineClass method in the class loader.
The following example uses a Class object to print the class name of an object:
void printClassName(Object obj) {
System.out.println("The class of " + obj +
" is " + obj.getClass().getName());
}
It is also possible to get the Class object for a named type (or for void) using a class literal. See Section 15.8.2 of The Java™ Language Specification. For example:
System.out.println("The name of class Foo is: "+Foo.class.getName());
I believe "instance" in this case refers to the instance of the class itself, i.e., the class definition, and not an object instance of that class. This is difficult to articulate, so let's consider an example:
class A {}
class B {
Class<A> a = A.class;
}
Here, the expression A.class executes within a class B. However, it is possible that class B might be loaded into the runtime more than once using different class loaders. So, when the documentation says, "as defined by the defining class loader (§12.2) of the class of the current instance", I believe it is referring to whichever class loader loaded the copy ("instance") of the B class that is currently executing.
In short, the Class<A> instance assigned to a will be loaded from the same class loader that loaded B.
In practice, this isn't the sort of thing you're likely to have to have to worry about. Most Java developers don't have to deal with multiple class loaders in their day-to-day work.
The class literal can never appear alone, it must always be qualified by either a class name or a primitive type name. class should be used when you need to access a class object statically. someObject.getClass() should be used when you need to access an objects class at runtime.
Thus:
public class Foo {
public static String getMyFooClassNameStatic_good() {
return Foo.class.getName(); // ok
}
public static String getBarClassName() {
// the Bar class will be looked up in the same class loader as
// the one that the the Foo CLASS instance was loaded from that
// is executing this method. So if there are multiple versions
// of Bar floating around, the one you will get is the one that
// was loaded from the same class loader as the loaded Foo. That's
// what the language about "current instance" in the spec is
// getting at.
return Bar.class.getName();
}
public static String getMyFooClassNameStatic_bad() {
return class.getName(); // syntax error -
// use one of:
// Foo.class.getName()
// (new Foo()).getClass().getName()
// Class.forName("Foo").getName()
}
public static String getIntClassName() {
return int.class.getName(); // ok
}
}
Why must I qualify a reference to class inside the class that it's defined in? For example:
public class Foo {
private static Logger log = LoggerFactory.getLogger(Foo.class);
}
Why can't I just call LoggerFactory.getLogger(class) since I'm already in the context of the Foo class?
The JLS defines
15.8.2. Class Literals
A class literal is an expression consisting of the name of a class, interface, array, or primitive type, or the pseudo-type void, followed by a '.' and the token class.
It wouldn't make the language ambiguous to allow class where an expression is expected to allow the syntax you describe, but it would involve overriding the keyword class to mean both
a kind of declaration
a reference to an instance of type Class.
The syntax you suggest might allow naming the class of an anonymous class, but getClass() would have the same meaning in anonymous classes.
Getting rid of two tokens (the unqualified class name and the .) doesn't provide much value, and it could cause confusion inside an inner class. For example, what is class inside a lambda expression?