Polymorphism
The relation "is a"

public class Point {

    double x,y;

    public Point (double x, double y) { 
        this.x = x;
        this.y =y;
    }

    public String toString() {
        return "point: (" + x + "," + y+")" ;
    }
}

public class PointC extends Point {
    byte col;
    public PointC(double x,double y,byte col){
        super(x,y);
        System.out.println("Construct drvd");
        this.col = col;
    }
    public String toString(){
        return "color "+col+" "+super.toString();
    }
}


Point p ;
p = new Point (2.3, 5.4);



p = new PointC (2.3, 5.4, (byte)7) ;





Upcasting and downcasting, instanceof operator


Casting from a subclass to a superclass is called upcasting. Typically, the upcasting is implicitly performed by the compiler.

It’s common to use reference variables to refer to a more specific type. And every time we do this, implicit upcasting takes place.

Downcasting is the casting from a superclass to a subclass.  The operator instanceof must be used before downcasting to check if the object belongs to the specific type. If not - there will be an exception at run time.


public class TestCast {
    public static void main(String[] args) {
        PointC pc = new PointC(7,12,(byte)3); //ОК

        Point p = pc; //implicit upcasting pc to Point
        System.out.println("\n p refer to PointC:"+p);

        //PointC pt = p;   //error, implicit downcasting is not possible
        if(p instanceof PointC)  {   //verification if p refer to PointC object
            PointC pc1 = (PointC)p;  // OK - explicit downcasting p to PointC
            System.out.println("\n pc:"+pc1);
        }
        else{
            System.out.println("Downcasting (implicit or explicit) is not possible");
        }
    }
}



 heterogeneous array

public class Test {
    public static void main(String arg[]){
        Point p[] = new Point[6];
        for(int i =0; i< p.length;i++){
            if(Math.random()>0.5){
                p[i]= new Point(5*i,2*i);
            }
            else{
                p[i]= new PointC(3*i,4*i,(byte)i);  //
implicit upcasting
            }
        }
        System.out.println(
                "\nThe points in the array are");
        for(int i =0;i<p.length;i++){
            System.out.print(i+": ");
            if(p[i] instanceof PointC) {
                System.out.println("is PointC with color "+((PointC)p[i]).col); //
explicit downcasting
            }
            else {
                System.out.println("is Point");
            }
        }

    }
}


Generalization for type casting:





* - classes wich declare the function fx()

Creation the references:
A a ; B b ; C c ; D d ; E e ; F f ;

correct assignment:
a = b ; a = c ; a = d ; a = e ; a =f ;    // OK  implicit upcasting
b = d ; b = e ;                                    
 // OK implicit upcasting
c = f ;                                                 // OK implicit upcasting

incorrect assignment:
b = a ;             // error  implicit  downcasting
d = c ;             
// error type casting (implicit or explicit). There is no direct inheritance connection.
c = d ;              // error type casting (implicit or explicit). There is no direct inheritance connection.

Methods call in upcastings:

a=new A();  a.fx();            method fx() from A
a=new B();  a.fx();            
method fx() from A
a=new C();  a.fx();            
method fx() from C
a=new D();  a.fx();            
method fx() from D
a=new E();  a.fx();            
method fx() from A
a=new F();  a.fx();             
method fx() from C


       




Abstract classes

Data abstraction is the process of hiding certain details and showing only essential information to the user.

Abstraction can be achieved with either abstract classes or interfaces.

The abstract keyword is a non-access modifier, used for classes and methods:

The abstract class is a restricted class that cannot be used to create objects ( it must be inherited from another class).

The abstract method 
specifies what derived classes need to do without showing how to do it. It can only be used in an abstract class, and it does not have a body.  The body must be provided by the subclass (inherited from).

An abstract class can have both abstract and regular methods

abstract class A{                // does not instantiate the objects
    .....                                    // can only be derived
    public void fx() { ..... }                 // fx() normal method defined in A
    public abstract void fa(int n) ;     // fa() – 
abstract method - only the signature
}

It is OK to create the referneces for abstract classes
A va ;                     // OK
A arA[] = new A[5];   //OK

It is not possible to 
be instantiated (there is no abstract objects)
va = new A(...) ;     //Error - cannot be instantiated
arA[0] =
new A(...) ;   //Error - cannot be instantiated


class B extends A{
    public void fa(int n) { ..... } /* mandatory definition of the
inherited method fa(). If not, the B class must be abstract too */
.....
}

It is OK to be
instantiated with the derived classes
A va = new B(...) ; // OK

Example:

abstract public class Displayable {
    abstract public void dspl();
}
---------------------------------------
public class Two extends Displayable{
    private double value;
    Two(double v){
        this.value =v;
    }
    public void dspl(){
        System.out.println("double value: "+value);
    }
}
--------------------------------------------
public class One extends Displayable{
    private int value;
    One(int v){
        this.value =v;
    }
    public void dspl(){
        System.out.println("int value: "+value);
    }
}
-------------------------------------------
public class Test {
    public static void main(String arg[]){
        Displayable tb[] = new Displayable[6];
        for(int i =0;i<tb.length;i++){
            double d;
            if((d=Math.random())>0.5){
                tb[i]=new One((int)(d*10));
            }
            else {
                tb[i]=new Two(d*10);
            }
        }
        for(int i=0;i<tb.length;i++){
            tb[i].dspl();
        }
    }

}

-----------------------------------------------
Result:
int value: 7
int value: 6
double value: 0.5517838775491102
int value: 9
int value: 7
double value: 1.1911353652113688