How does an explicitly scoped this keyword in java work? - java

I know this key word is used to point to current class fields and to call constructor like:
class A{
String name;
public A(String name)
{
this.name=name;
this.(name.length());
}
public(int len)
{
//some code here
}
}
but my I recently came across:
class B extends A
{
A varA = B.this;
}
I don't understand how B.this works. can any one elaborate in detail

B.this is a reference to B class instance.
as B extends A it is possible to declare a variable of type A and assign it to a reference to B class instance.

In the example you have, B.this is equivalent to this, so it's not very illustrative. Scoped this declarations are far more valuable when you start working with inner classes....
class Outer {
public void doSomething() {
}
class Inner {
public void doSomething() {
Outer.this.doSomething();
}
}
}
Notice the use of Outer.this in the Inner class. Without it, the inner class would have no way of disambiguating between the this that referred to the Inner instance and the this that referred to the Outer instance.

In fact, the this keyword is used to refer to the instance of a class.
When you do
this.name
you are referring to the attribute name from the actual instance of the class A.
When you do
B.this
you are referring to the B class intance.

The B.this means that you are getting the reference/pointer of the B class instance, B inherits from A so what you are actually doing is Initializing your A with the reference/pointer of B.
The B.this is useful when you are calling the instance of B class inside a anonymous/inner classes.
You can also call this which is equivalent to B.this but you cant call this in a anonymous/inner classes or else you'll get the instance of them not the class B instance.

Related

Constructor in Child Class

Why is the constructor in B required?
IntelliJ suggests to remove =null as it is redundant presumably because it is initialized through the given constructor in A.
However, this removal (which is presumably also performed by the compiler) then (presumably) requires the constructor in B.
Any other explanation?
public abstract class A {
private Object foo = null;
public A(Object foo){this.foo=foo;}
}
public class B extends A {
public B(Object foo){super(foo);}
}
Java does not have "constructor inheritance". The only way to initialize A is to pass the foo parameter to its constructor, and the only way to do this is to create a constructor for B that does so.
Note, however, that they don't have to have the same signature (like you have in the question) - B's constructor only needs to pass some parameter to A. E.g.:
public class B extends A {
public B() {
super("Arbitrary default passed to A");
}
public B(Object passedToA, Obejct notPassedToA) {
super(passedToA);
System.out.println("This argument was not passed to A():" + notPassedToA);
}
}
Why is the constructor in B required?
If the class B extends A, the class B must be instantiated in all possible ways as the class A can be and the class B can have additional ways to be instantiated. It means that class B is forced to have a constructor.
The only exemption can be in case of a no-arg constructor because the compiler makes it up with a default constructor i.e. if you put a no-arg constructor in the class A the child classes are not forced to have this.

Why can't a local class that extends an inner class access the inner class enclosing instance?

(I keep re-reading that question title and thinking about how ridiculous it must look, but I assure you that is the best description of the problem, and I have an actual application where this is the best structure. I swear I'm not crazy.)
Consider the following. Each block is a separate file:
package myPackage;
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
}
}
package myPackage;
import myPackage.A.B;
public class Main {
public static void main(String[] args) {
class C extends B {
public C(A enclosingInstance) {
enclosingInstance.super();
}
public void show() {
System.out.println(A.this.i);
}
}
A myA = new A(2);
C myC = new C(myA);
myC.show();
}
}
Note that the enclosingInstance business is to solve a problem involving intermediate constructor invocations. See "Why can't outer classes extend inner classes?".
I would expect the output to be "2". But instead, I have a compile error on System.out.println(A.this.i);:
No enclosing instance of the type A is accessible in scope
I think the programmatic concept I'm trying to solve is sound: Create a new type of B inside main to give to A that uses things from A that types of B can access.
So what am I doing wrong, or why isn't this possible in java?
EDIT/UPDATE: Note that the same error appears when the code in main is moved to a non-static method. That is to say, I tried moving everything inside of static void main to a new, non-static method of class Main called go(). Then I changed static void main to the single line new Main().go();. The error is in the same spot. So it doesn't seem to be an issue of class C being defined in a static context.
You want A.this to refer to the enclosing instance of the B instance. But why should it? That's not what the syntax means. A.this would mean the enclosing A instance of the C instance, and this does not make sense because C is not an inner class of A.
To make this clearer, here is an example where C is an inner class of A.
public class A {
public int i;
public A(int i) {
this.i = i;
}
public class B {
void foo() {
System.out.println(A.this.i);
}
}
public class C extends B {
C(A a) {
a.super();
}
void bar() {
System.out.println(A.this.i);
}
}
public static void main(String[] args) {
A a1 = new A(1);
A a2 = new A(2);
C c = a1.new C(a2);
c.foo();
c.bar();
}
}
Here C extends B, and both C and B are inner classes of A. Therefore any C has an enclosing A instance, and it also has an enclosing A instance when considered as a B, and these enclosing instances are different (as proved by the fact that foo and bar print different numbers).
So, A.this could not possibly mean what you want it to mean, because it already means something else. I guess the reason why the language designers didn't come up with other syntax to mean the enclosing instance of a super class, is because such syntax would be very complicated, with little pay-off (simple workarounds already exist).
This is absurd code that you should never write for production.
It is, in part, explained in the documentation for Explicit Constructor Invocations
Qualified superclass constructor invocations begin with a Primary
expression or an ExpressionName. They allow a subclass constructor to
explicitly specify the newly created object's immediately enclosing
instance with respect to the direct superclass (§8.1.3). This may be
necessary when the superclass is an inner class.
All this to say that C is a local class (which is an inner class, which is kind of nonsense because if you declare it in a static method there is no enclosing instance) that is a subclass of B but not a nested class of A. As such, there is no enclosing instance. An instance of C does not have an enclosing instance. (Though it would if you declared it in an instance method, but that would be an instance of Main.)
The newly created object's immediately enclosing instance (from JLS) is specified indirectly through a constructor parameter.
You'd have to store it yourself
private A enclosingInstance;
public C(A enclosingInstance) throws CloneNotSupportedException {
enclosingInstance.super();
this.enclosingInstance = enclosingInstance;
}
and since A#i is public, you can access it normally
public void show() {
System.out.println(enclosingInstance.i);
}
With the provided information, I would do this :
public class B {
protected A getOuterInstance() {
return A.this;
}
}
and just let C inherit and use this method. I know you dislike this method but this is the simplest answer I can see. With more information, I would probably propose a design which would try not involving any inner class as this is not a normal use case for inner classes.

Inheritance and constructors in Java

In the following example:
class A {
private int a;
private int b;
private int c;
public A(int a, int b , int c) {
this.a = a;
this.b = b;
this.c = c;
}
}
class B extends A {
public B() {
super(1,2,3);
}
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
You cannot call super() like this:
class B extends A {
super(1,2,3);
}
super() OR this() should be the first statement in a constructor. First correct this basic mistake of yours before going further. super() is used by default even if you don't explicitly use it.
class B extends A {
B (){
super(1,2,3);
}
}
This is the right way. Please Read about Constructors and Java language basics first before posting questions.
EDIT
I didn't notice that someone edited you question to add super(1,2,3) in a constructor, now answering your questions as follows:
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
No, by calling super(1,2,3) all you're doing is passing 3 integer values to the base class constructor public A(int a, int b , int c) After that you're assigning these values to the private instance variables of base class, you're not making a separate fields for class B, if thats what you asked, and No B class still can't access base class instance variables directly (by stating directly I mean by inheritance or making an instance, there are other ways like setters/getters etc)
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
No, if you don't use a constructor in B class which uses super(int, int, int) to match the arguments of base class constructor (int a, int b , int c) then your code won't even compile. The default constructor will call the no-args constructor of Base class, but since Base class has no default constructor you'll get compilation error!
First of all, the code you posted is not valid Java. It is important that you post working code, otherwise we can't be sure about what you are asking.
Does the statement super(1,2,3) in the class B create a private fields same as the private fields in the class A? Or is it illegal to use this statement because B cant inherit the private fields of A?
Assuming you put the statement in a constructor instead of at class level, which is illegal, then no, that will not automatically create fields in class B. It just calls the constructor in the superclass A that takes three int arguments and initializes the fields in the superclass part of the object.
And we suppose that we didn't use the super constructor in the class B then normally the computer will call the default constructor of the class A. We know that private fields are not inherited in Java so what will the default constructor initialize in this state ?
Since there is no default (i.e. no-arguments) constructor in class A, you would get a compiler error - the compiler would complain that there is no appropriate constructor in class A.
Java only automatically adds a no-arguments constructor to a class if you do not specify a constructor at all in the class. Since class A already has a constructor, Java is not automatically going to add a no-arguments constructor.
First of all you need to understand one thing: private fields of a parent class ARE BEING INHERITED. The only thing is that if they are private in parent, then they cannot be accessed directly from the child class (the B class in your example). So in other words: not a single B class method can access those fields, but every A class method can access them. So for example its possible that there is a public/protected method inside A class that changes some of those fields and this method can be called from a child class (B).
Once you correct your class to the proper:
class B extends A {
public B() {
super(1,2,3);
}
}
...we can proceed to answer your actual questions.
The constructor of A does not create fields. The fields are created as part of creating of any A object, and are initialized by the constructor.
Those fields are created in B as well, but not because you called super(1,2,3) but because you extend A. As soon as an instance of B, which is an extended instance of A is created, those fields are there - but they are accessible only to methods that are declared in A itself and not in its descendents.
By calling super(1,2,3), you are initializing those private fields. They are still not accessible to B. The constructor of A is mediating between B and these private variables. If you had a method that prints those fields in A, and that method was not private, you could call it and it would print them with these values.
As for your second question, if you didn't call the super(1,2,3), Java would try to call the default constructor. However, for a class that has a constructor, there is no default constructor. The empty/nullary constructor only exists if you either declared it yourself, or if you didn't declare any constructor at all.
// The following two classes have a default constructor which will be called
// if any descendent doesn't call super(...)
class HasADefaultConstructor {
}
class AlsoHasADefaultConstructor {
AlsoHasADefaultConstructor() {
}
}
// But this one doesn't.
class DoesntHaveADefaultConstructor {
DoesntHaveADefaultConstructor( String a ) {
}
}
So you can't inherit private varibles, but you can access them if the parent class has the appropriate getters:
Run the example and you see the output is 'a is: 1'
Regarding the default constructor: In your example you have explicitly implemented
a constructor. So the implicit default constructor is not there any more
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}
class B extends A {
public B() {
super(1, 2, 3);
}
public void foo() {
//access a
System.out.println("a is: " + super.getA());
}
public static void main(String[] args) {
B bb = new B();
bb.foo();
}
}

Hierarchy of inner classes in Java

I am using a hierarchy of inner classes to represent some data in an application and I have run into an error message that I simply do not understand. My code can be boiled down to the following minimal example:
public class A {
public class B extends A {}
public class C extends B {}
}
Javac (and my IDE of course) fails to compile the code with the following error message:
A.java:3: cannot reference this before supertype constructor has been called
public class C extends B {}
^
1 error
I didn't write this anywhere. There is no more code than provided above, so I assume javac has generated something related to the inner class.
I have found another way to represent my data, so I am simply interested in a good explanation of why it doesn't compile.
You need an outer class instance to create an inner class instance i.e something like new Outer().new Inner();
To extend the inner class (Parent inner class) with another inner class (child inner class), you cannot call the constructor of 'parent inner class' because the instance of 'outer class' is not there.
Try like this,
public class A{
public class B extends A {
B() { }
}
public class C extends B {
C() {
new A().super();
}
}
public static void main(String args[]) {
}
}
Similar question : Odd situation for “cannot reference this before supertype constructor has been called”
The other poster is correct, but how to fix? Simply make your class static:
public class A {
public static class B extends A {}
public static class C extends B {}
}
Note that if your inner classes refer to fields of the outer class, you can't make them static, otherwise you can (and should - doing so reduces dependencies).
Your code compiles under Java 7.
The following workaround compiles under Java 6.
public class C extends B
{
public C()
{
A.this.super();
}
}
#saugok's link to the previous question quoted Joshua's explanation. Basically he argued that since C is subclass of A, C inherits A's members as C's members. Therefore B is also C's member. (For example a class literal C.B.class is valid.) Therefore he argues that C.this is the enclosing instance for B's super(), therefore C(){super();} is actually C(){C.this.super();}. Since C.this cannot be evaluated before super constructor, thus the error.
However this doesn't seem to be warranted by the language spec. See #8.1.3. Since B is not immediately lexically enclosed by C, B is not a direct inner class of C, there is no reason to say that B's direct enclosing instance must be an instance of C.
We need to pass B() an instance of A. It is true that C.this is an instance of A ( try this code: new C().new B().new C().new B();) therefore it could be a candidate. There is also another candidate, A.this. A.this is available and ready to use (it's passed in as the hidden parameter to C()).
According to javap, javac 7 compiles the code into
class B
private A this$0;
B( A a )
this$0 = a;
super(); // A()
class C extends B
private A this$0;
C( A a )
this$0 = a;
super( a ); // B(A)

use of "this" and "class" as members

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/

Categories