using 'this' keyword in 'super()' constructor - java

I want to use this in super constructor, but there is no way to call this before calling supertype constructor.
I have got 3 classes. I will describe my exact problem using an example.
public class A {
C c;
A(C c) {
this.c = c;
}
}
public class B extends A {
B(C c) {
super(new C(this)); // error
}
}
public class C {
A a;
C(A a) {
this.a = a;
}
}

The problem is that you are passing the this reference to something else before the instance has been constructed. If this was allowed, the C constructor would be given an reference to a partial B object. That would break abstraction for B.
The section of the JLS that talks about this is 8.8.7.1. It says:
An explicit constructor invocation statement in a constructor body may not refer to any instance variables or instance methods or inner classes declared in this class or any superclass, or use this or super in any expression; otherwise, a compile-time error occurs.
I understand the problem, but I am asking, how to solve it. I need class C to have its "owner" from when it is created but I also need class A to "own" it from beginning.
You must pass the B reference to the C instance after constructing B; i.e. by assigning a new value to C.b, directly or via a method call such as a setter. There is no way around this. Java doesn't provide a way to create objects AND make them into a cycle in a constructor chain.
One way to hide the cycle creation is to use the Builder Design Pattern. But a setter call or equivalent has to happen behind the scenes.
Note that if your a and c fields are both declared as final, then there is no pure Java solution at all. (You could use some "nasty" reflection to modify one of the final variables. Or possibly some trickery with object deserialization.)

You can use a parameter-less constructor to construct the C instance, and then use a setter to set the instance variable.
public class A {
C c;
A(C c) {
this.c = c;
c.setA(this);
}
}
public class B extends A {
B(C c) {
super(new C());
}
}
public class C {
A a;
C() {
}
public void setA(A a) {
this.a = a;
}
}

Related

In Java, can a class reference the instance of another class which contains it?

class A {
private B b = new B();
}
class B {
private A a;
public void setA(A a){
this.a = a
}
}
setA is called after an instance of A has been initiated. I want to do this becase A has a method that B wants to call inside it.
Here A composes B.
class A {
private B b = new B();
}
And here B composes A :
class B {
private A a;
public void setA(A a){
this.a = a
}
}
No design judgement, supposing that you are in a case where the bidirectional dependency is needed, you should avoid initializer or constructor to create instances of this class since you need an instance from A to create B and reversely. Making this in an asymmetric way as in your sample code hides in a some way the relationship between these two classes.
So you could use a setter or a factory approach to make it clearer.
Setter approach :
class A {
private B b;
public void setB(B b){
this.b = b;
}
}
class B {
private A a;
public void setA(A a){
this.a = a
}
}
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
Or with a factory approach where you can rely on A or B class to expose the factory method according to the client need POV :
class A{
// ...
public static A ofWithB(){
A a = new A();
B b = new B();
a.setB(b);
b.setA(a);
return a;
}
}
A a = A.ofWithB();
B b = a.getB();
Sure, the language allows to do that.
But by doing this, you create what is called a circular dependency. A needs B, and B needs A. That is considered bad practice in many cases.
So, the real answer would be to step back and look at the problem you intend to solve. And to then design a solution that does not create a circular dependency! Sometimes bidirectional connectivity is necessary, but in general, it can quickly become a source for potential problems later in. So do not buy into such a solution unless you have carefully evaluated your options and you didn't find a better way.
It might be helpful for example that method that B needs in an interface. Then your B object only needs an instance of that interface (which could be an A under the covers).
Any time code (in B in your example) has a reference to an instance of a different class (A in your example), the rules governing its access to that instance's members (methods and fields) are the same:
If the member is private, B cannot access it
If the member is protected, B can access it only if B and A are in the same class, or B is a subclass of A
If the member is package-private (no access modifier if it's in a class), B can only access it if B and A are in the same package
If the member is public, B can access it
(In an interface, no access modifier = public and you can't have other access modifiers.)
It doesn't matter whether the instance is held on a field of an instance of B. The only thing that matters is what class the code trying to perform the access is in.
See Controlling Access to Members of a Class

Overriding a class method in subclass Java

I have a class which has 2 methods:
class A {
public methodA();
public methodB();
}
I have two other classes B & C, which have Class A as its members:
class B {
A a;
B(Config config) {
a = config.getA();
}
}
class C {
A a;
C(Config config) {
a = config.getA();
}
}
However, in class C I want to implement a different way of method B. I guess I need to override the method, but then I will need to make class A as an abstract class. Is that correct? Is there a different way to approach this
Edit: I am not directly creating a new instance of A. I am getting it from a helper class.
I will need to make class A as an abstract class
No just make sure that methodB has not been declared to be final, since final methods cannot be overridden. You can override the method "inline" by creating a new anonymous class from the A class within your C code:
class C {
A a;
C() {
a = new A() {
#Override
public void methodB() {
// .... code goes here
}
};
}
}
Can't be done in simple way.
In Java, if you need method to be overriden, it is done in a child class. However as you get the instance of A from someone else (the config), you have no way to control what is the class instantiated by config.
There are some alternatives:
If the new methodB can be done without knowing the internal of A, you can create a wrapper of A:
class C {
static class CustomA extends A{
A a;
public CustomA (A a) { this.a = a; }
#Override
public void methodB() {
a.methodB();
a.otherMethod();
}
}
A a;
C(Config config) {
a = new CustomA(config.getA());
}
}
Another alternatives is to change your Config to allow creation of other A child classes dictated by the caller of getA(). This can be done by misc way like Reflection or initialization of already-created A instance, and etc.
Another alternative is to extract logic of methodB out to a strategy. So you can replace the strategy to whatever you want. Check out Strategy pattern in GoF design pattern.

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();
}
}

how to pass a self-reference to constructors in java?

i have a class A that needs to instantiate a second class B, whose constructor needs a reference to the same object of class A...
would look like:
public class A {
B b;
public A() {
b = new B(this);
}
}
public class B {
A a;
public B(A a) {
this.a = a;
}
}
well - eclipse keeps complaining that this isnt possible. i assume, this is because the reference of class A isnt "ready" yet at this moment...?
but the error wont go away if i move the init of class B to a seperate function within A wich i would call from "outside"...
how can i pass this self-reference from outside to the constructor of B?
Be very careful, because until A is constructed, it doesn't really exist. If B were to call a method on A, the program should fail because you can't call a method on A prior to A being constructed. Construction is not complete until A fully returns from its constructor code.
If you must initialize B with A whenever A is constructed, it is much better to make a factory class for A which guarantees that B is initialized after A is constructed. It would look something like this
public class AFactory {
public A newA() {
A a = new A();
B b = new B(a);
return a;
}
}
For this to work properly 100%, you might need to limit the visibility of the A() constructor. I personally would put AFactory into the same package as A and make the access "default" or "package private like so
package same.as.afactory;
public class A {
A() {
...
}
}
I'd ask myself: Are you sure that's the design you want? And, if it is, would it make sense for one of those classes to be an inner class of the other?
Look, here is a way to use a constructed self instance in the constructer itself:
public class Foo {
private int x;
public Foo() {
this(1);
// the self instance should have been constructed now
}
public Foo(int x) {
this.x = x;
}
}
How do I call one constructor from another in Java?
Create a holder object which you can pass from A to B, and then insert the this instance of A into when the A constructor is finished. Then B can refer to the this-value inside the holder later.

Categories