How to override a method with default (package) visibility scope? - java

My problem is that I can't understand how method resolution works in the following case: Suppose, we have two packages, A and B. There are two classes, A is placed within A, B within B.
A:
package com.eka.IO.a;
import com.eka.IO.b.B;
public class A {
void foo() {
System.out.println("parent");
}
public static void main(String... args) {
B obj = new B();
obj.foo();
}
}
B:
package com.eka.IO.b;
import com.eka.IO.a.A;
public class B extends A {
public void foo() {
System.out.println("child");
}
}
The code above prints "child", which is perfectly OK. But if I change the method main the following way:
public static void main(String... args) {
A obj = new B();
obj.foo();
}
the code prints "parent", and I don't understand why. (obj has runtime type B, B has a public method foo)
Next, I change foo's visibility to public,
public class A {
public void foo() {
and the code prints "child" again.
As far as I know, instance methods are resolved at runtime, using the following principle:
JVM checks the runtime class of the object.
JVM looks for the method of runtime class
If method is found, JVM calls it, otherwise moves to the parent runtime class.
In my example, in any of three cases, runtime class for obj is always B. B's method foo is always public. Why in the second case JVM calls A's method?
Up:
Good answers, but still some things are unclear for me.
a) It's the compiler that checks whether a method overrides another method. (Hope, I'm right).
b) in case of A obj = new B(); the compiler generates the following code:
INVOKEVIRTUAL com/eka/IO/a/A.foo ()V
b1)if A's foo is declared without modifier (package visibility), then JVM calls A's method.
b2)if A's foo is declared public, then JVM calls B's method.
The unclear thing is why in the second case INVOKEVIRTUAL actually calls B.foo. How does it know, that B overrides the method?

The process is slightly different than you described it. First, Java will only make the methods that exist in the declared class and are visible at the current scope available. This is already done at compile time.
At runtime,
JVM checks the runtime class of the object.
JVM checks whether the object's runtime class has overridden the method of the declared class.
If so, that's the method called. Otherwise, declared class's method is called.
Now, the tricky part is "has it been overridden"?
A class can't override a method that is not visible to it. It can declare a method by the same name and with the same arguments, but this method is not considered to be overriding the original method. It's simply a new method, just like any other method that's defined in B but not in A.
If this was not so, then you could break the parent's class contract at a place where the author thought it should not be broken and therefore did not allow access to it.
So since the class did not override the method, you can only reference that method the same way you'd be able to reference any method declared in B that was not in A - only through a B reference.
Why doesn't the compiler prevent you from using names of methods that are already in the parent class, then?
Well, if you get a package, and the only information you have about it is what's in the classes' contracts, as written in its Javadoc, you won't even know about the existence of that method. All of a sudden, you write a method that, as far as you know, is unique, and you get a compilation error.
There is no reason to do that. What's not visible to you should not prevent you from freely naming your own methods. Thus it is allowed.
But if you want the compiler to prevent you from making mistakes like that, use the #Override annotation whenever you are writing a method that is supposed to override a parent class's method. This way, the compiler will warn you if you are trying to override a method that is not part of the class's contract.

You're experiencing Method Shadowing. From Java Language Specification. Chapter 6. Names. 6.4. Shadowing and Obscuring. 6.4.1. Shadowing (emphasys mine):
Some declarations may be shadowed in part of their scope by another declaration of the same name, in which case a simple name cannot be used to refer to the declared entity
(...)
A declaration d is said to be visible at point p in a program if the scope of d includes p, and d is not shadowed by any other declaration at p.
(...)
A declaration d of a method named n shadows the declarations of any other methods named n that are in an enclosing scope at the point where d occurs throughout the scope of d.
Let's check if B#foo overrides A#foo. From 8.4.8.1. Overriding (by Instance Methods):
An instance method mC declared in or inherited by class C, overrides from C another method mA declared in class A, iff all of the following are true:
A is a superclass of C.
C does not inherit mA.
The signature of mC is a subsignature (§8.4.2) of the signature of mA.
One of the following is true:
mA is public. (not your case)
mA is protected. (not your case)
mA is declared with package access in the same package as C (not your case since the classes are in different packages), and either C declares mC or mA is a member of the direct superclass of C.
mA is declared with package access and mC overrides mA from some superclass of C (not your case because there should be another class between C and A that let's you override mA).
mA is declared with package access and mC overrides a method m' from C (m' distinct from mC and mA), such that m' overrides mA from some superclass of C (not your case because there should be another class between C and A that let's you override mA).
So, B#foo does not override A#foo by any mean. With this in mind, when you call obj.foo() then foo will be obtained based on the class obj is designated at compile time. The explanation of this part is explained at 15.12. Method Invocation Expressions
If you want to avoid this, mark your method with #Override annotation in the subclass to make sure you're specifically overriding the desired method and not hiding it. If you get a compiler error when annotating your method, then you will know that you're not overriding such method but shadowing it.
As a result from this, you cannot override a method with default scope from a subclass that is in a different package than the parent class. Mark the method as protected in the parent class or redesign your classes accordingly to avoid this scenario.

Related

Java Inheritance: Difference while inheriting super class members and variables

I was going through Java inheritance and I tried the following code
class A {
public int x = 1;
public void print1() {
System.out.println("Print from A");
}
}
class B extends A {
public int x = 2;
public void print1() {
System.out.println("Print from B");
}
}
class C extends B {
public int x = 3;
public void print1() {
System.out.println("Print from C");
}
public static void main(String aa[]) {
C c = new C();
((A) c).print1();
System.out.println(c.x);
System.out.println(((A) c).x);
}
}
The output was
Print from C
3
1
Now, my question is that I am able to access class A member x from class C instance c but why am I not able to access the class A method print1(). I know, if I want I can call new A().print1();. But, I want to access it from an instance of class C directly. So by overriding methods, are the top parent class methods lost in the bottom child class? However, the parent class members are retained (although hidden). Why so? And is there a way to call a method from class A in class C without creating an instance of A?
EDIT
What's happening here?
When you say ((A)c).print1();, JVM knows that actual the instance, on which it needs to call is print1() is of type C hence class C's print1() version is executed.
But when you type ((A)c).x, you are referring to state, not behavior and that too using reference of type A. Which version of x will be picked up, is decided at compile time as compiler knows what is the type reference (In this case A). That is why you see A's state.
This statement from Java doc might also be interesting for you:
Within a class, a field that has the same name as a field in the
superclass hides the superclass's field, even if their types are
different. Within the subclass, the field in the superclass cannot be
referenced by its simple name. Instead, the field must be accessed
through super, which is covered in the next section. Generally
speaking, we don't recommend hiding fields as it makes code difficult
to read.
Why is it this way?
Answer to your questions:
Question 1:
my question is that I am able to access class A member x from class C
instance c
About variable x, since it is declared as public, no business validation can be applied on that. Moreover, the developer who's declaring it as public, is aware that concept of encapsulation can't be applied now (which is obviously not recommended). So there is no harm in allowing access to parent's state using child instance. Therefore, by using ((A)c).x, you can access x from class A.
Question 2:
However, the parent class members are retained (although hidden). Why
so?
It's because Java does not allow you to use super.super.super.. arbitrarily to access any parent's behavior in the inheritance hierarchy. And the reasoning behind it is to preserve encapsulation. You can only access behavior of the immediate parent class using super keyword but not beyond that.
To explain it more, let's say you have implementation of class B like:
class B extends A {
public int x = 2;
public void print1() {
if(x >= 2) {
System.out.println("Print from B");
}
}
}
Now if super.super was allowed, you can easily bypass validation in print1() method of class B and can invoke A's print1() method from the instance of class C.
Question 3:
However, the parent class members are retained (although hidden). Why
so?
As, mentioned earlier, to retain encapsulation.
Question 4:
And is there a way to call a method from class A in class C without
creating an instance of A?
So there is no way to access print1() from A using C's instance.
When you override a function which already implemented in base(parent) class, when you call that function within the child class, automatically the class in the child will call so in your case when you call print1() of a C object:
C c = new C();
c.print1();
you will call the override function. However if in any part of your program you feel that you need to call the top parent class for any case (which cannot be fulfilled by super) then you should reconsider your design strategy; maybe you shouldn't override the print1() or even you shouldn't put print1() in the base class in the first place
In object oriented programming, only methods have the ability to be overriden. You cannot override a data member. This explains why you get the outputs.
print1() method of A is overriden in C, and c is an object of C. So, it will call the print1() method of C. On the other hand, the variable x is not overriden.
To call the superclass method, you can do:
super.print1();
Here , Same named Instance Variable is used in all the Classes to confuse the compiler, but you should know that Only Member functions can be overridden not member variables.
So, All the three x will be stored separately in memory. but public void print1() will be overridden by its child class. So,
((A)c).print1(); this piece of Code will Call the overridden method defined in class C. doesn't matter in which class you cast the Object of Class C.
But in Second Case ((A)c).x will print the value from Class A.
((A)c).x :- this will reference to the variable x belongs to Class A not to Class C. because variables never overridden in Inheritence.
((A)c).print1(); Actually it is similar to the c.print1(); .
It doesn't matter that you typecast it with Class A, it will still call print1() function of the Class C.

How does method invoking takes place?

I'm new to Java Programming and learning polymorphism.
__EDIT__
As per the answers I received from everyone,I have code:
Here I'm typecasting my Derived object (obj) to Base type and then calling method().
public class Tester {
public static void main(String[] args) {
Base obj=(Base)new Derived();
obj.method();
}
}
class Base{
public void method(){
System.out.println("In Base");
}
}
class Derived extends Base{
public void method(){
System.out.println("In Derived");
}
}
Output I'm getting is: "In Derived".
So after typecasting my object should become of type Base referenced by Base type.
But it's not happening? Why?
Does typecast work on child->parent conversion or it has no effect here?
Base obj=new Derived();
In the above statement, the reference part points to type Base. This is how the compiler identifies which class to consider. But your code will create an error. Let me explain the structure of the above statement before explaining why will it show an error.
Structure of the above statement:
Declaration-The reference part is Base obj.
Instantiation: The new keyword is a Java operator that creates the object/allocates space in the memory.
Initialization: The new operator is followed by a call to a constructor, which initializes the new object.
Since, Derived is a sub-class of Base, you are allowed to call the constructor in the Derived class. This is how inheritance and polymorphism works.
Okay, Now let us go back to the error part.
The obj.method() in your code is looking for a function method() in Base class but the method(int a) function in Base class requires an argument of type integer to be passed. So for the code to work, the calling statement has to be something like obj.method(5).This statement works because the calling statement is actually passing 5 to the function.
There is an easy fix for your code:
Derived obj=new Derived();
Have you noticed?
I have relaced the reference to type Derived.
Why does that work?
Because there is method() function in your Derived class which doesn't require an integer argument.
There is one more amazing fact about inheritance in Java:
Everything possessed by a super-class is also possessed by the sub-class but the reverse is not true. And yes, the sub-class has the right to redefine any method/function it has inherited from super-class.
The above statement means the following code will work:
Derived obj=new Derived();
obj.method(5);
You must be wondering-How come this code works even though method() in Derived requires no argument. In fact, Derived has no method(int a).
Well, the answer to this is the amazing fact I have mentioned above.
Yes, method(int a) also belongs to Derived since it's a sub-class of Base.
But How does the code mentioned below work?
Derived obj=new Derived();
obj.method(5);
Simple, the JVM looks for the method(int a) in class Derived and it finds the function since Derived has inherited the function from Base class.
Remember this too, the sub-class also has a privilege to over-ride a method in super class. This means that you can add method(int a) function in class Derived which over-rides the original method inherited from Base.
How inheritance works?
When you call obj.method(5) in the above code, the JVM first looks for any over-ridden method of the same type in Derived. If it does not find any over-ridden method, it moves up in the inheritance hierarchy chain to the super class and looks for the same method. But the reverse is not the true.
how does compiler comes to know which method is to be called & too from which class?
The compiler searches for the method in the class (in this case Base) of the object (in this case obj). If the method is not found in that class, then it looks for the method in the super class (in this case Object). If still not found, it flags an error.
Is it that compiler checks the reference type class & if method to be invoked is not present in reference type class it gives error??
Yes. But, as said before, If the method is not found in that class, then it looks for the method in the super class (in this case Object). If still not found, it flags an error.
Your obj.method() will fail, because Base does not have a method with the signature method() (it has method(int))
If your obj was of type Derived, then both these case will work:
obj.method(); // will call this method from the Derived class
obj.method(1); // will call this method from the Base class
when there are same method names in different classes , the compiler comes to know by:
1-if you are passing any argument , then the type of argument which you are passing will tell the compiler which method to be called
2-if there are two classes , then make the object of that class for which you want to call the method

Why is a subclass' static initializer not invoked when a static method declared in its superclass is invoked on the subclass?

Given the following classes:
public abstract class Super {
protected static Object staticVar;
protected static void staticMethod() {
System.out.println( staticVar );
}
}
public class Sub extends Super {
static {
staticVar = new Object();
}
// Declaring a method with the same signature here,
// thus hiding Super.staticMethod(), avoids staticVar being null
/*
public static void staticMethod() {
Super.staticMethod();
}
*/
}
public class UserClass {
public static void main( String[] args ) {
new UserClass().method();
}
void method() {
Sub.staticMethod(); // prints "null"
}
}
I'm not targeting at answers like "Because it's specified like this in the JLS.". I know it is, since JLS, 12.4.1 When Initialization Occurs reads just:
A class or interface type T will be initialized immediately before the first occurrence of any one of the following:
...
T is a class and a static method declared by T is invoked.
...
I'm interested in whether there is a good reason why there is not a sentence like:
T is a subclass of S and a static method declared by S is invoked on T.
Be careful in your title, static fields and methods are NOT inherited. This means that when you comment staticMethod() in Sub , Sub.staticMethod() actually calls Super.staticMethod() then Sub static initializer is not executed.
However, the question is more interesting than I thought at the first sight : in my point of view, this shouldn't compile without a warning, just like when one calls a static method on an instance of the class.
EDIT: As #GeroldBroser pointed it, the first statement of this answer is wrong. Static methods are inherited as well but never overriden, simply hidden. I'm leaving the answer as is for history.
I think it has to do with this part of the jvm spec:
Each frame (§2.6) contains a reference to the run-time constant pool (§2.5.5) for the type of the current method to support dynamic linking of the method code. The class file code for a method refers to methods to be invoked and variables to be accessed via symbolic references. Dynamic linking translates these symbolic method references into concrete method references, loading classes as necessary to resolve as-yet-undefined symbols, and translates variable accesses into appropriate offsets in storage structures associated with the run-time location of these variables.
This late binding of the methods and variables makes changes in other classes that a method uses less likely to break this code.
In chapter 5 in the jvm spec they also mention:
A class or interface C may be initialized, among other things, as a result of:
The execution of any one of the Java Virtual Machine instructions new, getstatic, putstatic, or invokestatic that references C (§new, §getstatic, §putstatic, §invokestatic). These instructions reference a class or interface directly or indirectly through either a field reference or a method reference.
...
Upon execution of a getstatic, putstatic, or invokestatic instruction, the class or interface that declared the resolved field or method is initialized if it has not been initialized already.
It seems to me the first bit of documentation states that any symbolic reference is simply resolved and invoked without regard as to where it came from. This documentation about method resolution has the following to say about that:
[M]ethod resolution attempts to locate the referenced method in C and its superclasses:
If C declares exactly one method with the name specified by the method reference, and the declaration is a signature polymorphic method (§2.9), then method lookup succeeds. All the class names mentioned in the descriptor are resolved (§5.4.3.1).
The resolved method is the signature polymorphic method declaration. It is not necessary for C to declare a method with the descriptor specified by the method reference.
Otherwise, if C declares a method with the name and descriptor specified by the method reference, method lookup succeeds.
Otherwise, if C has a superclass, step 2 of method resolution is recursively invoked on the direct superclass of C.
So the fact that it's called from a subclass seems to simply be ignored. Why do it this way? In the documentation you provided they say:
The intent is that a class or interface type has a set of initializers that put it in a consistent state, and that this state is the first state that is observed by other classes.
In your example, you alter the state of Super when Sub is statically initialized. If initialization happened when you called Sub.staticMethod you would get different behavior for what the jvm considers the same method. This might be the inconsistency they were talking about avoiding.
Also, here's some of the decompiled class file code that executes staticMethod, showing use of invokestatic:
Constant pool:
...
#2 = Methodref #18.#19 // Sub.staticMethod:()V
...
Code:
stack=0, locals=1, args_size=1
0: invokestatic #2 // Method Sub.staticMethod:()V
3: return
The JLS is specifically allowing the JVM to avoid loading the Sub class, it's in the section quoted in the question:
A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.
The reason is to avoid having the JVM load classes unnecessarily. Initializing static variables is not an issue because they are not getting referenced anyway.
The reason is quite simple: for JVM not to do extra work prematurely (Java is lazy in its nature).
Whether you write Super.staticMethod() or Sub.staticMethod(), the same implementation is called. And this parent's implementation typically does not depend on subclasses. Static methods of Super are not supposed to access members of Sub, so what's the point in initializing Sub then?
Your example seems to be artificial and not well-designed.
Making subclass rewrite static fields of superclass does not sound like a good idea. In this case an outcome of Super's methods will depend on which class is touched first. This also makes hard to have multiple children of Super with their own behavior. To cut it short, static members are not for polymorphism - that's what OOP principles say.
According to this article, when you call static method or use static filed of a class, only that class will be initialized.
Here is the example screen shot.
for some reason jvm think that static block is no good, and its not executed
I believe, it is because you are not using any methods for subclass, so jvm sees no reason to "init" the class itself, the method call is statically bound to parent at compile time - there is late binding for static methods
http://ideone.com/pUyVj4
static {
System.out.println("init");
staticVar = new Object();
}
Add some other method, and call it before the sub
Sub.someOtherMethod();
new UsersClass().method();
or do explicit Class.forName("Sub");
Class.forName("Sub");
new UsersClass().method();
When static block is executed Static Initializers
A static initializer declared in a class is executed when the class is initialized
when you call Sub.staticMethod(); that means class in not initialized.Your are just refernce
When a class is initialized
When a Class is initialized in Java After class loading, initialization of class takes place which means initializing all static members of class. A Class is initialized in Java when :
1) an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
2) an static method of Class is invoked.
3) an static field of Class is assigned.
4) an static field of class is used which is not a constant variable.
5) if Class is a top level class and an assert statement lexically nested within class is executed.
When a class is loaded and initialized in JVM - Java
that's why your getting null(default value of instance variable).
public class Sub extends Super {
static {
staticVar = new Object();
}
public static void staticMethod() {
Super.staticMethod();
}
}
in this case class is initialize and you get hashcode of new object().If you do not override staticMethod() means your referring super class method
and Sub class is not initialized.

how to check a method override or not

i have two question
1 overriding
2 compile time binding
hi i want to know that how i can check that sh() become override
is method argument play any role in method overriding ?
why we say that static method bind at compile time but actually static method allocate memory at the class loading time ?
when i use javac tool that means i use compiler and i compile a java file ,so that moment static memory not allocate ,static memory allocate a class loading time
then why say that static method use compile time binding
is class loading time same as compile time ?
i am confuse
i know here method signature is different so no override here than what actually happens here explain
class A
{
void sh(char x){
System.out.println("value of x : "+x);
}
}
class B extends A
{
public void sh(int x)
{
System.out.println("value of x"+x);
}
}
class C
{
public static void main(String...Aa) /* ??? */
{
A a1=new B();
//a1.show();
a1.sh('a');
a1.sh(10);
}
}
The Java Language Spec states
An instance method m1, declared in class C, overrides another instance method m2,
declared in class A iff all of the following are true:
C is a subclass of A.
The signature of m1 is a subsignature (§8.4.2) of the signature of m2.
Either:
m2 is public, protected, or declared with default access in the same
package as C, or
m1 overrides a method m3 (m3 distinct from m1, m3 distinct from m2),
such that m3 overrides m2.
Moreover, if m1 is not abstract, then m1 is said to implement any and
all declarations of abstract methods that it overrides.
The definition for subsignature is here. You ask
is method argument play any role in method overriding ?
According to the above, yes very much so. You signatures have to match. In other words
public void sh(int x)
is not overriding
void sh(char x){
why we say that static method bind at compile time but actually static
method allocate memory at the class loading time ?
At compile time, a method call is resolved on the static or declared type of the reference. In other words, the program won't compile if the type doesn't declare such a method. For static methods. If the method is static, then the method is immediately resolved and bound to the type it is called on. If it is an instance method, binding is resolve dynamically (late-binding) with polymorphism.
None of this has anything to do with class loading or allocating memory.
I'm not clear on what you're asking. However, when B extends A, B will also inherit the sh(char x) method. The sh(int x) method does not override this, since the argument type is different. So an object of class B will have two different methods named sh.
In your code, though, you declared a1 to be of type A. Even though it will (at run time) refer to an object of type B, as far as the compiler knows it is still type A. Therefore, the methods you can apply to this object are the ones declared in A (and its superclasses, if it had any, but it doesn't, other than Object). The only method you have (besides the Object methods) is sh(char x).
So when you say
a1.sh('a');
a1.sh(10);
the compiler will treat this as if the argument is a char, since the only method it will look at is the one that takes a char argument. This means that a1.sh(10) will call the sh in A with "character 10" as an argument--EDIT: no it won't; I tried it, and the compiler won't let me convert 10 to a char automatically.

Why parent class type reference variable having reference to child class object can't access child class's Methods

Since this object(stated in title) can invoke overridden methods in child class, why it can't invoke other methods of child class?
I need answer as detailed as possible like memory organization, internal logic in JVM etc.
below code will give you clear understanding of my question.
class A
{
int x=10;
public A()
{
System.out.println("Constructor of class A called!!!");
}
public void sayGreetings()
{
System.out.println("accept hye from class A");
}
}
class C extends A
{
int x=30;//why this is not accessed by stated object.
public C()
{
System.out.println("Constructor of Class C caled!!!");
}
public void sayGreetings()
{
System.out.println("accept hye from class C");
}
public void ssa()
{
System.out.println("Sat Sri Akal ji from class C");
}
}
public class ParentClassTypeObject
{
public static void main(String[] args)
{
C cObj=new C();
cObj.sayGreetings();
cObj.ssa();
A aCObj=new C();//this is let say stated object,main object
aCObj.sayGreetings();/*here we invoked method will be child class's
overriden method.*/
//aCObj.ssa(); //why this line gives error
System.out.println("x="+aCObj.x);
}
}
Because the interface you have to the object is the one you chose when you wrote:
A aCObj = new C();
If you want access to the C properties via the aCObj variable, declare it as a C.
By making it an A, you make it possible to write this later:
aCObj = new A();
So since the variable can point to an A, or a C, the compiler restricts you to accessing the methods defined by the interface exposed by the A type.
You still access C's definition of those methods, because that's one of the main points of OOP (polymorphism).
Reference Variable points to the object which is of same type or the Sub set of same type.
Please consider Parent and Child are two classes Where Parent is Super Class and Child inherits the Parent Class. The below image will give you a detailed explanation.
In the above picture, The Parent class Reference variable will search for the Parent Class Object in Child Object.It will find it , as it is there.So will give the output.And if you have the Same method in Child Class(Method Overriding) It will execute the child class overrided method.
But for the Child Class reference Variable ,It can not find out the child class object in Parent Class Object.So here,It's Not possible.
Hope This clear your Confusion.
If you compile the code you will get compile time error(not runtime error). The reason behind this is that
A aCObj=new C();
aCObj.sayGreetings();/* The compiler knows that aCobj is a reference of type A while compiling. Since compiler thinks aCobj is of type A and sayGreetings() method is present in class A so no error while calling this method */
aCObj.ssa(); /* As I mentioned above that compiler have no knowledge about run time. At run time aCobj will point to the object of type class C, but while compiling the compiler only knows that aCobj is of class A type and since class A have no such method called ssa(), you will get compile time error. */
One simple rule for object : Left side of assignment operator checking at compile time. Right side of assignment operator at run time.
Consider this statement:
Parent obj =new Child();
obj.method1();
obj.method2();
Whatever method u want to call using obj reference of Parent type, those method should present in Parent class because during compile time the compiler will strictly check for those methods presence in Parent class even though it may be present in Child class.
The compiler decides IF you can call a method based on the type of the reference variable.So if the reference variable is of class A you can only call methods of class A.
But also
the compiler decides WHICH method to call based on the actual type of the object and not the type of the reference variable starting a bottom up check on the inheritance tree.(it starts from the subclasses all the way up)
So in this case when you say aCObj.sayGreetings(); the compiler firstly checks the reference type of aCObj which is A.Class A has the sayGreetings() method so its ok.But the actual object is a C.So the compiler starts from subclass (C) to find whether this method is implemented all the way to the superclass (A).The method `sayGreetings() is overriden at C class. So it calls the C class sayGreetings() method(of the subclass).
On the other hand the ssa() method is of class C and since the reference variable is of class A the compiler gives an error when you try aCObj.ssa();
It's just polymorphism.Since an A class reference variable can be either A or C object the compiler restricts the access only to the methods that are common which are the methods of the superclass A.Next it checks whether this method is implemented at the class of the actual object (C).if it is not it moves up to the superclass (A) and calls the method of the superclass.But if it is implemented it calls the method of the subclass (C)
The Object is of type A not C so you cannot access the instance variable i think if you make it public then you can.
Because aCObj is declared as type A so only methods declared in type A are accessible. The compiler cannot guarantee it is also of type C.
E.g.
You may also have
public class B extends A {
public void sayGreetings() {
...
}
}
This does not have the ssa method, but could still be assigned to an object declared as type A
Case 1. The reference variable of a parent class can point to an object of its child class..
Case 2. The reference variable of a parent class that is pointing to an object of its child class can be typecasted to an object of its child class.
In case 1: reference variable of a parent class can only call the methods that are defined within the parent class and also it can call the methods of child class that are overriding the methods of parent class.But cannot call the methods that are exclusively only in child class.
In case 2: reference variable of a parent class can call the methods of its child class also.
This is due to the principle of Polymorphism.
here is the detailed explanation of your stated query:
The answer is the intersection of "polymorphism" and "static typing". Because Java is statically typed at compile time you get certain guarantees from the compiler but you are forced to follow rules in exchange or the code won't compile. Here, the relevant guarantee is that every instance of a subtype (e.g. Child) can be used as an instance of its supertype (e.g. Parent). For instance, you are guaranteed that when you access employee.getEmployeeDetails or employee.name the method or field is defined on any non-null object that could be assigned to a variable employee of type Parent. To make this guarantee, the compiler considers only that static type (basically, the type of the variable reference, Parent) when deciding what you can access. So you cannot access any members that are defined on the runtime type of the object, Child.
The answer has been taken from the following link:
Why do we assign a parent reference to the child object in Java?

Categories