I need to link an object of type B to any instance of type A (circular dependencies). I could also declare another method, which must be called after the constructor of A and link a new B to an A-instance. What I want to achieve is not having to call such a method manually. This is the sample code:
public Class A{
B b;
public A(){
b = new B(this); // this does not work,
// as this references an object that has not been created yet
}
}
public Class B{
A a;
public B(A a){
this.a = a; //or something else
}
}
I commented the problematic line. I also understand why it can't work. What I need to know is, if there is a well-known design pattern to avoid this problematic? Or should I just redesign my class model, putting anything in B to A? Any suggestions?
It does work. It's problematic in that it exposes an object before it's been fully initialized (so if the B constructor calls methods on the parameter, for example, that could be a bad thing), but it does work. The reference B.a will be a reference to the instance of A that's been/being constructed.
I would recommend trying to avoid the cyclic reference where possible, but where the alternative is even worse, the code you've given will work.
Using this approach is not recommended and possibly create runtime exception because the object is not fully initialized. We can take simple scenario as:
public class A {
B b;
String s;
public A(){
b = new B(this); // this does not work, as this references an object that has not been created yet
s = "print me";
}
}
public class B {
A a;
public B(A a){
this.a = a; //or something else
System.out.println(this.a.s); // will same as a.s;
}
}
It will output null because a partially initialized reference is copied to constructor. This code compiles because compiler doesn't find anything missing in code as all appropriate references and variable are there.
Related
Is there a work around that will allow me to cast an object of the base class to an object of the derived class?
something like the following
B extends A
A a = new A();
B b = (B)a
Is there a trick that will achieve this?
No, absolutely not. What would you expect the values of any fields declared in B but not in A to be? For example, what would you expect this to do:
Object x = new Object();
String text = (String) x;
System.out.println(text);
An Object has no text data... so what would it mean to cast it as a string?
You can only cast a reference to a type which is appropriate for the actual type of the object.
The desire to do this usually indicates a design problem somewhere... or it might mean that you want something like:
public class A {
public A() {
// Whatever
}
public A(A a) {
// Use the existing values in "a" to initialize this object
}
}
public class B extends A {
/** Creates a new B from the values in an A, with suitable defaults. */
public B(A a) {
super(a);
// Now initialize any fields in B with appropriate values
}
}
Then:
A a = new A();
B b = new B(a);
That will create two objects, unlike a cast... but it would at least be valid.
How is that even possible? Think about it. It is like saying if you have a class FourWheeler, you can simply cast it into a Ferrari and make it a Ferrari!
No, this isn't possible. When B extends A it inherits the behavior of A, but on the same time, there is nothing stopping you from defining new behavior for B (where those new behaviors won't be part of A)
For example say A has a single method called 'methodA'. Now when B extends A it inherits 'methodA' but it also declares another method called 'methodB'. So under such circumstance you will get a runtime 'ClassCastException' when you try to call the 'methodB' over an instance of Object A.
In the below code, are b and show inherently static?
public class A {
public static class B {
private int b = 0;
public void show() {
System.out.println(b);
}
}
}
No they aren't static. You need to create an instance of B to access them.
The static keyword in your code example means that instances of B can be created without an instance of A.
If B was not static:
Instances would have an implicit reference to an instance of A.
The only way to create them would be to use new B() inside class A, or using syntax like new A().new B().
Methods in B can refer to A.this (the implicit reference to an instance of A).
Methods in B can refer to A.this.someField (using that implicit reference).
Methods in B can call instance (non-static) methods in A.
However, because B is static:
Instances do not have a reference to an instance of A - you don't need an A to create a B.
Instances can be created using new A.B() (or just new B() from within in class A)
Methods in B cannot refer to A.this.
Methods in B cannot access fields in A (unless passed in as a parameter).
Methods in B cannot call instance (non-static) methods in A.
They are not static. They are instance fields in B.
Meaning you need to have an instance of B to get/set them.
B is static in A but that does not make those fields of B static.
You can create many instances of B without any reference to A.
So B is static class in A but the same is not true for B's instance fields.
The static keyword has two meanings that are actually quite different and that can be confusing.
Static on a variable/method means that it exists at the class level, not the instance level. This means that you only have one copy of that variable/method no matter how many instances of the class you create.
Static on an inner class though just means that the class does not depend upon its outer class. In your example you can create a new B() without having an A. If you didn't have the static keyword on the class you could not create a new B() unless it was within an instance of A.
B is a static inner class of A.
Need to instantiate B.
A.B innerObject = new A.B();
innerObject.show();
The identifier static has a specific purpose here that many people don't immediately grasp. I'm going to take your code and change it a bit.
public class A {
private int a;
public A(int a) {
this.a = a;
}
public class B {
public void show() {
System.out.println(a);
}
}
}
Now, what's happening in class B? Because B is a non-static class, it has access to other non-static members in class A. Essentially, it states that every class A object has their own flavor of class B objects, even thought they are functionally the same. For us to get that same behavior if B was a static class:
public class A {
private int a;
public A(int a) {
this.a = a;
}
public int getA() { return a; }
public static class B {
public void show(A a) {
System.out.println(a.getA());
}
}
}
Here, this implies that the flavor of B objects doesn't change depending on which A object created it. The B class is static so that it cannot access non-static members of the A class object that created it and must access those members explicitly from whichever A object it wants to interact with.
In the previous implementation, a B object would seamlessly access fields and non-static methods of the A object that created it.
These are two different behaviors and often it's clear exactly which one fits your objective.
If I have two classes, A and B,
public class A {
public int test() {
return 1;
}
}
public class B extends A{
public int test() {
return 2;
}
}
If I do: A a1 = new B(), then a1.test() returns 2 instead of 1 as desired.
Is this just a quirk of Java, or is there some reason for this behavior?
This is called polymorphism. At runtime the correct method will be called according to the "real" type of a1, which is B in this case.
As wikipedia puts it nicely:
The primary usage of polymorphism in industry (object-oriented
programming theory) is the ability of objects belonging to different
types to respond to method, field, or property calls of the same name,
each one according to an appropriate type-specific behavior. The
programmer (and the program) does not have to know the exact type of
the object in advance, and so the exact behavior is determined at
run-time (this is called late binding or dynamic binding).
No, that is correct (it is due to polymorphism). All method calls operate on object, not reference type.
Here your object is of type B, so test method of class B will be called.
This is polymorphism and more specifically in Java overriding. If you want to invoke Class A's test method from Class B then you need to use super to invoke the super classes method. e.g:
public class B extends A{
public int test() {
return super.test();
}
This is intended behavior. The method test() in class B is overriding the method test() of class A.
For
A a1 = new B();
a1 is pointing towards the object of B which is the real type at run-time. Hence value is printed from Object B.
A obj = new A();
obj.test()
will return 1
A obj = new B();
obj.test()
will return 2
B obj = new B();
obj.test()
will return 2
As stated in other answers this is how polymorphism works.
This post may make things a bit clearer
Java uses dynamic binding (or late binding), so the method of B is called, not A. This is the opposite of static binding. There is a nice example here.
You declare your object as A but your instance is B. So the method which will be called is from class B. B extends A(we can say that A is parent for B) if you will comment method test in B and then recall this method, in this case the method invoked will be test from A class and will return 1.
I have two classes A and B while B is a subtype of A:
public class A {
private String stringVar;
public A() {
stringVar = "";
}
public String getStringVar() {
return stringVar;
}
public void setStringVar(String str) {
this.stringVar = str;
}
#Override
public String toString() {
return getStringVar();
}
}
Class B:
public class B extends A {
private int intVar;
public B() {
intVar = 0;
}
public int getIntVar() {
return intVar;
}
public void setIntVar(int intVar) {
this.intVar = intVar;
}
#Override
public String toString() {
return super.toString() + " " + getIntVar();
}
}
As you can see in the following main method I assign the b to a. Now "a" can't invoke b's methods which is clear, because I'm using an instance of type A now. But it behaves like a B when toString is invoked. Curious, I would have expected toString of a. Why is this so?
public class Main {
public static void main(String[] args) {
A a = new A();
B b = new B();
b.setIntVar(200);
b.setStringVar("foo");
a = b;
System.out.println(a);
}
}
Because a points to the implementation of B.
And is declared as A.
So behavior of B. And methods visible of A.
To use B methods do like this
((B) a).getIntVar();
Think of it like this
Object o = new FancyObject();
When compiling this only Objects methods will be accepted even though it's a FancyObjcet with lots of methods.
To use the methods of FancyObject on o do like this.
Object o = new FancyObject();
(FancyObject o).fancyMethod();
Quote "because I'm using an instance of type A now" you are still using an instance of type B. You can see it like you have upcasted b but it's the same instance.
Picture cross linked from another site with credits in the picture, if this is against the rules then somebody is free to edit this part of my answer.
This is nature of inheritance / polymorphism and overriding methods.
Overrided methods will be determined in runtime based on objects real type and not based on reference type.
Therefore a.toString() is actually b.toString() because it is determined in runtime.
http://download.oracle.com/javase/tutorial/java/IandI/override.html
The concept you need to understand is the difference between References and Objects.
a is a reference (a local variable in this case) that points first to an Object of type A and then to an Object of type B.
The compiler knows that it must be of type A (or a subtype thereof), so it can safely call all methods A defines, but they will be called on the actual Object, not on the original Type of a.
This is polymorphism: The object that a holds has static type A, but it is still an Object of dynamic type B. Dynamic dispatch therefore chooses the overridden toString() defined in B.
That's exactly how Java's runtime polymorphism works. All that matters is the actual type at runtime. What you have done is take a reference to an A and point it at an instance of B. You have changed the type of the thing that a points to.
Try
a = (A)b;
No, B Overrides the toString method of A, so if an object is an instance of B, when you call its toString method, you get whatever method that instance has. In general, if you have an object and call its methods, the method called is the one that is in the instance, not in the variable type. The only exception is static methods.
In C++, this is not the case. The method called is the one of the variable type, if one exists, unless you explicitly select the above described behavior by making a method virtual.
That is called runtime polymorphism in OOP.
G'day people,
I am feeling embarrass by asking such a naive question. But I can't understand one thing,
I have Inheritance structure like this,
B extends A, code I have wrote is as below,
Class A
public class A{
private int pos = 0;
public A(){
this.pos = 12;
}
public int getPos(){
return this.pos;
}
}
Class B
public class B extends A{
int spec = 15;
public B(){
super();
}
public int getSpec(){
return this.spec;
}
}
And I have one more class to test, Which will get us to my question.
Class Test
import java.util.*;
public class Test{
public static void main(String[] args){
B a = new B();
ArrayList<A> c = new ArrayList<A>();
c.add(a);
System.out.println(c.get(0).getPos());
System.out.println(c.get(0).getSpec());
}
}
Question : Now I am creating an instance of B, Which means I can access to my parent class's method getPos() and B's own method getSpec(). But if I create ArrayList with type A(...B is type A too, as it extends A...) and add my B's instance it losses it's ability to access it's own method. What am I doing wrong? Does ArrayList implementation is casting my B to A internally?
Note : My basic understanding of inheritance is parent cannot access
child's method except they are protected. But Child can access their
parent class's method.
There's no casting involved. What you're doing is no different from this:
A bAsA = new B():
While the object referred by bAsA is truly a B object, it is held by an A variable and thus only A methods are available (unless you explicitly cast it as a B variable).
Since your ArrayList is an ArrayList of A, each item in the ArrayList is treated as an A variable and only A methods are available.
Does ArrayList implementation is casting my B to A internally?
No. There is no "internal casting." You, the programmer, have told the compiler it's a list of A.
You have declared the List as List<A>, which you can read as "a list of A". Since all B are A, you can add any B to a List<A>. On retrieval, however, you're only guaranteed to get back an A, not a B — because it's a List<A>, remember — so the compiler treats everything that comes out of the list as an A, even if (at runtime) it's an instance of B.
In addition to the answers provided by #Matt Ball and #Hovercraft Full Of Eels, you can avoid having to explicitly cast by declaring methods implemented by the subclass as abstract methods in the superclass.
public abstract class A{
.
.
public abstract int getSpec();
}
EDIT-
As mentioned by #Kublai Khan, it is necessary to then make the superclass an abstract class.