I have a class BaseClass and it has two subclasses C and D. I need to put objects of both C and D type into the array of BaseClass. The assignment works.
But if I call a method print() defined in C and D on the array it will not compile. I am missing something but search on the web or here did not answer my question.
My book says the chain of inheritance will do look for print() in C.
If print() found in C use it. If not found in C go up to parent class.
How to fix?
According to the Java description the inheritance allows a subclass to inherit data and methods from the super class. Furthermore, in the inheritance it says that when a method is invoked on an object the JVM it will first look for the method in the class of the object. If the method is in there it will then use that method. However this following will not compile. The objective is to have an array of the superclass and assign to it objects of the subclasses.
The following is the program.
//This is an example program.
public class Tester
{
static public void main(String[] args)
{
BaseClass[] myarr = new BaseClass[10];
myarr[0] = new C();
myarr[1] = new D();
myarr[0].print(); //error
for (int i =0 ; i < 10; i++)
{
if(myarr[i] != null) myarr[i].print(); //will not compile. Why?
}
}
}
This is the superclass code.
public class BaseClass
{
public BaseClass()
{
}
//it wants print(), why?
}
Next I have two subclasses C and D.
//subclass
public class C extends BaseClass
{
public C()
{
}
public void print()
{
System.out.println(“hello C”);
}
}
And subclass D.
//subclass
public class D extends BaseClass
{
public D()
{
}
public void print()
{
System.out.println(“hello D”);
}
}
It does not work because when creating an Array of Type BaseClass, the compiler does not know anything about a print() method. These just get introduced in your 2 subclasses.
Just imagine you had an other Subclass called E (also extending Baseclass) which did not have a print() function. Now assign an object of E to one of the places in myarr. Until here everything would work fine. Now when you try calling the print() method the compiler would not know what to do. This is why the compiler cannot find print() and does not want to 'interprete' your code.
Now to solve this there are 2 possibilities. If you want a print()-method in every Subclass you could simply create one abstract method:
public abstract class BaseClass {
public BaseClass() {
// Some Constructor Work
}
// This tells the compiler there is a print()-method in every subclass because it must be overridden
public abstract void print();
}
Now in your Subclasses (I just do one for proof of concept :)):
public class SubClass extends BaseClass {
public SubClass() {
// Do Constructor Work if necessary
}
// I would highly suggest you also use this annotation because it helps you
// identifying overridden methods (but it is not obligatory to use)
#Override
public void print() {
System.out.println("Hello from SubClass");
}
}
Now in your main:
public static void main(String[] args) {
// Init Array
BaseClass[] myarr = new BaseClass[4];
myarr[0] = new SubClass();
myarr[1] = new OtherSubClass();
// and so on... I think you get the gist
// Now execute print()
myarr[0].print(); // This works perfectly now.
}
Now possibility 2 which depending on your usecase could be the only working one (though I would highly recommend to use the technique shown before as here you must be 100% certain which ClassType your object is) is a lot unsafer and you must know what you are doing or you get errors (and noone likes errors right? :)): Use Casting.
public static void main(String[] args) { // Note I will be using "your" classes here again
// Array Init...
BaseClass[] myarr = new BaseClass[10];
// Assign blabla
myarr[0] = new C();
myarr[1] = new D();
((C) myarr[0]).print(); // Casting to C-Type which has a print()
}
This will basically tell the compiler (and the JVM): "Hey don't care about what type this object is. Just assume it would be a C-Type!"
I think you start to realize what could be the problem. If the compiler wants to read a C-Type but instead gets a D-Type or an E-Type it does not know what to do --> Error.
Hope I could help you :)
EDIT:
Ah and note that by adding the abstract modifier to a class you cannot create an object of this class any more, just of the corresponding children-classes. This is why I also wanted to give you possibility 2 as this is more versatile.
At compile time, the compiler will check to see that BaseClass has a print() method since the static type of any element in myarr is BaseClass. At runtime, the program will be able to dynamically resolve the type of each object to either C or D. Only then will it look at the C or D classes for their respective print methods. To fix this, you could add a default print method in BaseClass.
Related
Given two classes, a parent class and a child class:
class A {
private void greet() {
System.out.println("Class A");
}
}
class B extends A {
public void greet() {
System.out.println("Class B");
}
}
One has a method called greet(), which is private, and the other one defines a method with the same name, only that it is public. Now, as far as I know, the child's greet() method doesn't override the parent's method, because it 'hides' it? (given the fact that private methods can't be overridden?)
Now, given the following class and method (considered to be in the same package as A and B):
public class Main {
public static void main(String[] args) {
B b = new B();
b.greet();
}
}
This should compile. But this one:
public class Main {
public static void main(String[] args) {
A a = new B();
b.greet();
}
}
This one up here doesn't compile, because it's missing a typecast.
My question would be: why? If the greet() method was public in both places, it would have shown Class B both times. I'm pretty confused about why Java doesn't figure at runtime, for the second case, that a is actually referencing to an object of type B, and directly calls the method from class B.
Tried reading more about polymorphism in an OCA-preparation book, but the authors didn't seem to be so specific about it.
In your snippet that doesn't compile, the compiler sees that the compile time type of a is class A.
Therefore, it will only allow you to call accessible methods of class A (or of super-classes of A). greet is a private method of A, and therefore not accessible. Therefore the compiler doesn't allow calling it.
The fact that the runtime type of a would be class B, which has an accessible greet method, makes no difference, since the compiler doesn't try to figure out what the runtime type of a variable would be.
At compile time A.greet() is not accessible.
Hence does not compile.
For overriding, the method must be accessible at compile time, but the decision to call the method is done at runtime.
I have created anonymous class by implementing interface I inside public static void main() method. So, by java 8 for the abstract method test(), the implementation is provided from imple() method of class C.
So, inside public static void main() method, printing _interface.getClass(), I got
package_path.Main$$Lambda$1/310656974 which is absolutely fine. Bacause it print's the anonymous class name.
Also, _interface is pointing to an anonymous object in heap and hence I'm doing _interface.test();
So, the first statement that test() method has now is to print the class name,
But eventually what it print was,
package_path.C (telling me C is the class name). How is that possible? Shouldn't package_path.Main$$Lambda$1/310656974 be printed again? Because 'this' means anonymous inside the test method right?
#java.lang.FunctionalInterface
interface I {
void test();
}
class C {
void imple() {
System.out.println(this.getClass());
System.out.println("Inside Implementation");
}
}
class Main {
public static void main(String[] args) {
I _interface = new C()::imple;
System.out.println(_interface.getClass());
_interface.test();
}
}
Hopefully, this might help you understand, that when you declare
I _interface = new C()::imple;
you've actually implemented the interface somewhat similar to (though not same as):
I _interface = new I() {
#Override
public void test() {
new C().imple(); // creating an instance of class `C` and calling its 'imple' method
}
};
Hence when the test method is called, it first creates an instance of C which prints
class x.y.z.C
as the class.
Because 'this' means anonymous inside the test method right?
Now as you can see above, there is no more anonymous class from which imple
is being called from, hence this is not representing the anonymous class anymore.
As Holger clarified in comments further, despite the representation as lambda or anonymous class at the calling site, the this.getClass() inside a method of class C will evaluate to C.class, regardless of how the caller looks like.
Recommend: Continue to read and follow on Is there any runtime benefit of using lambda expression in Java?
I'm studying CS and we have questions about polymorphism that I cant wrap my mind around. Here is an example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
public BB(){
foo();
}
public void foo(){
System.out.print("BB:foo ");
}
public void goo(){
System.out.print("BB::goo ");
}
public static void main(String[] args){
// Code goes here
}
}
When in void main i add the line:
AA a = new BB();
it goes first AA constructor prints AA:foo but then goo() sends it to BB's goo, why so?
Simple polymorphism such as "Animal -> cat/spider/dog" is easy to understand but when it comes to this I'm just lost. Can you guys give me any tips how to read this code? What are the rules are?
EDIT: there is no #Override annotation because this is a question from an exam.
Explanation
public class AA {
private void foo() { ... }
^^^^^^^
}
Polymorphism is not applied to private methods. A subclass does not inherit private methods, so they cannot be overridden:
A class C inherits from its direct superclass all concrete methods m (both static and instance) of the superclass for which all of the following are true:
m is a member of the direct superclass of C.
m is public, protected, or declared with package access in the same package as C.
No method declared in C has a signature that is a subsignature of the signature of m.
Java Language Specification - 8.4.8. Inheritance, Overriding, and Hiding
Therefore, the foo() call from the A constructor doesn't invoke BB#foo, it calls AA#foo.
But the goo() call within AA#foo refers to the overridden method BB#goo. Here, with public methods, method overriding and polymorphism were applied.
It's a bit tricky, so I would recommend you put the #Override annotation everywhere it's supposed to be.
public class BB extends AA {
#Override // it doesn't compile - no overriding here
public void foo() { ... }
#Override // it does override
public void goo() { ... }
}
It also might be helpful to detect another problem:
Programmers occasionally overload a method declaration when they mean to override it, leading to subtle problems. The annotation type Override supports early detection of such problems.
If a method declaration in type T is annotated with #Override, but the method does not override from T a method declared in a supertype of T, or is not override-equivalent to a public method of Object, then a compile-time error occurs.
Java Language Specification - 9.6.4.4. #Override
Illustration
If a constructor body does not begin with an explicit constructor invocation and the constructor being declared is not part of the primordial class Object, then the constructor body implicitly begins with a superclass constructor invocation super();, an invocation of the constructor of its direct superclass that takes no arguments.
Java Language Specification - 8.8.7. Constructor Body
To put it simply,
public BB() {
foo();
}
turns into
public BB() {
super();
foo();
}
Keeping super(); in mind, we can make the next illustration:
new BB()
AA() // super(); -> AA constructor
A#foo() // private method call
B#goo() // polymorphic method call
BB() // BB constructor
B#foo() // plain method call
It's explained very well in the official docs:
https://docs.oracle.com/javase/tutorial/java/IandI/super.html
If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass. If the super class does not have a no-argument constructor, you will get a compile-time error. Object does have such a constructor, so if Object is the only superclass, there is no problem.
So, the Java compiler is adding super() without args for you.
In fact, if the class you are extending doesn't have a default constructor you will be required to call this constructor with args before.
Otherwise, the reason why AA:goo is not being called is because is override by BB even if it doesn't have the #Override annotation, if you want to see that call you need to use super(); in your b:goo method. In fact, the foo is not override because it private so it's not possible to override it, if you try to add the annotation #Override you'll se you have a compilation failure.
AA::foo() is private so AA::foo() and BB::foo() aren't the same.
new BB()
will call AA::Constructor first, calling AA::foo().
AA::foo() call goo() and since you instantiated BB class it'll be BB::goo().
Please use "override" keyword on method when you want to do something like this
There is also a serious design flaw in the example code: it is calling an overridable method from a constructor. This means that object BB might not be fully initialized at the time that this method is called on it. For example:
public class AA{
public AA(){
foo();
}
private void foo() {
System.out.print("AA::foo ");
goo();
}
public void goo(){
System.out.print("AA::goo ");
}
}
public class BB extends AA{
private Date timestamp;
public BB() {
super();
foo();
timestamp = new Date();
}
public void foo() {
System.out.print("BB:foo ");
}
public void goo() {
// goo() gets called before timestamp is initialized
// causing a NullPointerException
System.out.print("BB::goo " + timestamp.getYear());
}
public static void main(String[] args){
AA obj = new BB();
}
}
Remember this: NEVER CALL AN OVERRIDABLE METHOD FROM A CONSTRUCTOR (even not indirectly as in this example)
Polymorphism is Simple yet Confusing at times when we use different set of names [Which is the case here].
Polymorphism is basically a Parent Child Relationship. Key here is, if you are trying hard to place the names of the classes, use yourself instead i.e. give comment line next to class names as below
public class AA{} //your Parent name
public class BB extends AA{} // yourself i.e. your name
When it comes to the code like this, AA a = new BB(); , decode the code as below:
BB is you, AA is your parent.
new keyword is with YOU(i.e. BB), so a new object of YOU would be created or born. In order to for YOU to born, without your parents(i.e. AA), you cannot exist and so, first they will be born or created (i.e. AA constructor would run). Once your Parents (i.e. AA) are created, then it is time for YOU to born(i.e. BB constructor would run).
In your example,
public AA(){
foo(); -- line A
}
private void foo() {
System.out.print("AA::foo ");
goo(); -- line B
}
public void goo(){
System.out.print("AA::goo "); -- line C
}
As I told earlier, Line A would be called when you say AA a = new BB(); as Line A is in Constructor of AA, Line A calls foo() method and so the control lands in foo(), prints "AA::foo " and executes Line B. Line B calls goo() method and so on it reaches Line C. After Line C is executed, there is nothing left to execute in AA constructor (i.e. Object is created) and so the control flows down to the child Constructor ( As parent is created, it is time for the child to born) and so the child Constructor would be called next.
For Students/Beginners, I strongly recommend to go through Head First Java Edition. It really helps you in laying the Java Foundation Strong.
public class B extends A{
public static void main(String[] args) {
new B().privateMethod();//no error -output B-privateMethod.Sounds like overriding
new B().staticMethod(); //no error -output B-StaticMethod.Sounds like overriding
}
private void privateMethod() {
System.out.println("B-privateMethod.");
}
static void staticMethod() {
System.out.println("B-StaticMethod.");
}
}
class A{
private void privateMethod() {
System.out.println("A-privateMethod.");
}
static void staticMethod() {
System.out.println("A-StaticMethod.");
}
}
On R&D I found in case of privateMethod()- since this method was not available on object of child class so child class's and parent class's privateMethod() are separate method and they have no relationship so this is not overriding.
but in case of staticMethod()- parent class's method was available on object of child class ,and when we define this in child class, object of child class start pointing to child class method.this looks like method overriding but not,since static method does not override.
how does static method handle by java developement kit?
new B().privateMethod();
this is not overriding, since B doesn't see A's privateMethod().
new B().staticMethod();
this is not overriding, calling a static method via an instance is allowed, though it can be confusing. It is exactly the same as calling it via the class name - B.staticMethod(). If a super class A of B has a static method visible from B, you can call that method from B (and it doesn't matter if you write B.staticMethod() or A.staticMethod() or new B().staticMethod().
If later you define a static method of the same name in B, that method hides the method of the same name in A, so calling B.staticMethod() or new B().staticMethod() now invokes B's static method. However, calling A.staticMethod() will still invoke A's static method.
Polymorphism is not for static methods. Static methods are called with JVM instructions invokestatic, whereas polymorphism is achieved with invokevirtual. The calls to static methods are determined at compile time, and polymorphic methods are dynamically dispatched at runtime.
You can easily tweak your code so that A.staticMethod() is called, by just assigning new B() to a variable of type A.
public static void main(String[] args) {
new B().privateMethod();
A b = new B(); // change here.
b.staticMethod(); // A.staticMethod() is called here.
}
Never speak about static and override in the same sentence.
The whole concept of overridable methods is to dynamically bind at runtime which method is to be executed. Consider this:
class A { void print() { out.println("A"); }
class B extends A { void print() { out.println("B"); }
A obj = new B();
obj.print();
Although the variable obj is of type A, it still prints out "B".
Static methods on the other hand are bound at compile time. This means the compiler uses the type of the variable (or the expression) to determine what method to execute:
class A { static void print() { out.println("A"); }
class B extends A { static void print() { out.println("B"); }
A obj = new B();
obj.print();
This now yields "A". Unfortunately the Java language allows to call static methods on variables or expressions. This is not recommended! Better call static methods on the type itself:
A.print();
B.print();
In the first example - obj.print(); - the compiler automatically translates the statement into A.print(). The actual object does not count. In fact you could write the following:
A obj = null;
obj.print();
Or:
((A) null).print();
That still prints "A".
Having the following superclass:
public class SuperClass {
protected Integer a;
protected Integer b;
public void doSomething() {
this.a = 10;
}
public void doEverything() {
SuperClass.this.doSomething();
this.b = 20;
}
public static void main(String[] args) {
SuperClass instance = new SubClass();
instance.doEverything();
System.out.println(instance.a); //should print 10
System.out.println(instance.b);
}
}
And the following subclass:
public class SubClass extends SuperClass {
#Override
public void doSomething() {
super.doSomething();
super.a *= 10;
}
public void doEverything() {
super.doEverything();
this.b += 5;
}
}
Outputs:
100
25
So, SuperClass.this.doSomething(); is accessing SubClass's doSomething, but I need it to access the SuperClass's doSomething. In that case, I don't have the super keyword, because I'm already on super!
Is there a way to reference¹ the deep SuperClass.this.doSomething, so it would output 10 for the first output value?
¹ I'm interested on referencing: we could, of course, extract the SuperClass's doSomething to an auxiliar private method and access it directly.
If there is no way, does the situation where a superclass method needing to access its another (although overridden) method mean that my OOP design isn't correct? Why?
I assume you come to Java from C++ background. The languages are similar in concepts and in syntax, but they are different in the implementation.
You can achieve what I think is your intention also in Java, but the structure will look differently from C++.
In Java the construct SuperClass.this in your example is exactly the same as this, so SuperClass.this.doSomething(); is exactly what just doSomething() would be. So why does Java at all has the construct SuperClass.this? It has its meaning unrelated to the inheritance. It is useful in the context of nested classes.
Imagine a structure like this:
class A {
class B {
public void doSomething() {
// this here refers to an instance of the class B
System.out.println(this);
// We need to write is this way,
// because this hides the this reference to the instance of A.
// A.this is the instance of A where this is nested
System.out.println(A.this);
}
}
So how can you make sure to be able to have a method in a class that subclasses can override, and still be able to call the specific implementation?
Well, in the strict sense, you cannot. What you can do, is to create a final method, which cannot be overridden, and call it from a non-final method.
class SuperClass {
public void doSomething() {
doSuperClassyThing();
}
public final void doSuperClassyThing() { // cannot be overridden
...
}
}
A similar approach (with a bit different goal) you can see in the Template Method Pattern.
You cannot do what you want. The way polymorphism works is by doing what you are seeing.
That means there is no direct way to call SuperClass.doSomething() from SuperClass.doSomething() without going though SubClass.doSomething() unless you're working with an actual instance of SuperClass.
In some other languages you have power to tell how to handle this for example with keyword virtual in c++, but in java you don't have that option. All the method are being dynamically binded so you cannot do that. You can only not override or prevent it from being overriden at all.
The answer is that you can't refer to it. The only way to do this is the private helper method approach that you are aware of already.
If you want to know the reason why, I guess it's just because it would complicate the language for no reason; you can always get the same result by using a private helper method. The syntax SuperClass.this.doSomething() is already taken for something else. That means calling the method doSomething on the enclosing instance if SuperClass is an enclosing class.
If you ever find yourself on that situation, maybe you should rethink and consider that the class structure is not that correct yet.
Try to implement one of the following approaches:
Composition over Inheritance.
Creating a new Inheritance level (a class in the middle that has a reference to super).
Same as (2.), but using an inner class.
Extract the wanted method to a separate private one and call it where applicable.
Since (1.) wouldn't be as dry as the others, (4.) leaves a feeling of a workaround, and (2.) would require the creation of a new file and would reference outside SuperClass; I think the closest approach would be (3.), which is the only solution that in some way references super inside SuperClass (although it's actually referenced on a SuperClass inner class):
SuperClass.java:
public abstract class SuperClass {
protected Integer a;
protected Integer b;
public void doSomething() {
this.a = 10;
}
public abstract void doEverything();
public static class Impl extends SuperClass {
#Override
public void doEverything() {
super.doSomething();
this.b = 20;
}
}
public static void main(String[] args) {
SuperClass instance = new SubClass();
instance.doEverything();
System.out.println(instance.a); //prints 10
System.out.println(instance.b);
}
}
SubClass.java:
public class SubClass extends SuperClass.Impl {
#Override
public void doSomething() {
super.doSomething();
super.a *= 10;
}
#Override
public void doEverything() {
super.doEverything();
this.b += 5;
}
}