Object Oriented Programming (in Java)

Fundamental Concepts

 

programming = construction of a class

 

class = a description of a set of objects sharing the same structure

 

object = a state machine (instance of class)

              state = a composition of

                                          data (primitive types)

                                          other objects (reference types)

              behavior = a set of procedures on the states

 

package = a set of classes (class library)

 

encapsulation mechanisms = walls for access, visibility control of names

                  package

P

 
                      class

m ( )

 

C

 
                          method

 

P.C.m( )

 
                  

 

 

Class definition (Naming)

 

                   class A {  v1;  v2; . . .  m1();  m2(); . . . }

 

Class usage

                        declaration of variable               A   a,  aa;

 

                        creation of instance                   a = new A();

 

                        activation of method                  a.m();

 

                        system defined operations         aa = a;

                                                                        aa == a

                                                                        a  instanceof  A

 

                                                                        Object:  boolean equals(Object obj)

                                                                                      Object clone()

Object interaction:   

 

            class A { . . .;  B  b = new B(); . . .  }

 

 

 


            A  a = new A()

 

·        a  creates  b  (a  has  b)

 

·        a  accesses  b

            directly:            b.x

            indirectly:          b.m()

 

·        a  accesses  b  and  c

            b.m(c)              -- call by value for primitive types                                    -- call by reference for reference types

 

                              b  accesses  c.z  through  a.f()

 

                                    a  connects  b  and  c  by executing  b.m(c) in f()

                                    b  requests  c.z  by executing  c.n()  in  m(c)

                                    c  grants  c.z  by executing  return z  in  c.n()

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

·        a  deletes  b (automatic)

            garbage collection

                        

 

Class Inheritance (Sub-classing, Prefixing):

 

            class A { v1; m1( ) }

 

               class B extends A { v2 ;  m2( ) }

                           ( B  is  A )

 

               class C extends B { v3 ;  m3( ) }

                           ( C  is  B  and  C  is  A )

 

 

 

 

 

 

 

 

 


              

 

 

               A  a = new A();                        static and dynamic type of   a  is  A

               B  b = new B();                        static and dynamic type of   b  is  B

               C  c = new C();                        static and dynamic type of   c  is  C

 

               a = b;               ok (the dynamic type of  a  is  B)

 

               a = (A) b;         ok (safe casting, always valid)

 

               b = a;               illegal, compiler error (undefined fields);  b.m2() ?

 

               b = (B) a;         ok (unsafe casting) if the dynamic type of  a  is  B

                                       otherwise, runtime error

 

                                       To be safe:  if (a instanceOf B)  b = (B) a;

 

               a = c;               ok (the dynamic type of  a  is  C)

 

               b = c;               ok (the dynamic type of  b  is  C)


class A {

   public  int x = 1;

   public int get(){ return x; }

}

 

class B extends A {

   public  int x = 2;

2

 
   public int get(){ return x; }

get()

 
}

get()

 
 


B

 
public class CastTest {

1

 
    public static void main(String args[]) {

        A  a = new A();

        B  b = new B();

   

        if ( a instanceof B){   //possible ClassCastException

            b = (B) a;

            System.out.println(b.x);       

            System.out.println(b.get());

        }

       

        a = b;

        System.out.println(a.x);        // 1

        System.out.println(a.get());    // 2

       

        a = (A) b;

        System.out.println(a.x);         // 1

        System.out.println(a.get());    // 2

       

  //    b = a;        compiler error

       

        b = (B) a;

        System.out.println(b.x);         // 2

        System.out.println(b.get());    // 2

       

  //    b = (A) b;    compiler error

       

    }

}
Shadowed Variables (from class C): Static

 


v

m()

 

A

 
            v1 = v2 = v3 = v

((A) this)

 
 


v

m()

 
               v                               v in class C

B

 
               this.v                         v in class C

super

 
               super.v                      v in class B

v

m()

 

C

 
               ((B) this).v                 v in class B

this

 
               ((A) this).v                 v in class A

               super.super.v             illegal

 

 

Overriding Methods (from class C): Dynamic

 

            m1 = m2 = m3 = m

 

               a = new A();

               a.m();                           same as a.m1()

               a.v                                same as a.v1

 

               b = new B();

               a = b;

               a.m();                           m2()

               a.v                                v1

 

               c = new C();

               a = (A) c;

               a.m();                           m3()

               a.v                                v1

 

               b = (B) a                      compile ok, possible runtime error

               b.m();                           m3()

               b.v                               v2

 

               a = (A) b;

               a.m();                           m3()

               a.v                                v1

 

               b = (B) a;                     compile ok, runtime ok

            b.m();                           m3()

                  b.v                               v2

 


Visibility Modifiers

Class Member Accessibility [Table 3-1, page 73]

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 


                        public class A {            public int  x;

                                                            protected  int  y;

                                                            int  z;

                                                            private  int  u;        }

  

          C’ has access to only public members of A.

                        class C’ {     A  a;      a.x     }

 

            C has access to all non-private members of A.

                        class  C  {    A  a;     a.x      a.y      a.z    }

 

            B’ has access to and inherits public and protected members of A.

                        class B’ extends A  {     A  a;    a.x    a.y    x    y    }

 

            B has access to and inherits public, protected and default (package) members of A.

                        Class B  extends A  {   A  a;    a.x    a.y   a.z    x    y    z  }

Abstract Method =  interface definition only (pure virtual function)

                                      no implementation (no body part)

 

          Regular Method Declaration

          [modifiers] type name ( parameters ) [throws exceptions] { method body }

 

            Abstract Method  Declaration

            [modifiers]  abstract  type name ( parameters ) [throws exceptions]

 

 

Abstract Class  = a class that contains at least one abstract method

            ex.

            abstract class  Shape {    abstract void draw();  }

 

            class Box extends Shape {  . . .  void draw(){ draw this box }; . . . }

            class Arrow extends Shape {  . . .  void draw(){ draw this arrow }; . . . }

 

            class Graph {  . . .

                        Shape[]  shapes = new Shape[100];

                        shapes[0] = new Box( ... );  shapes[1] = new Arrow( ... ); . . .

 

                        for ( int i = 0; i < shapes.length; i++ )  shapes[i].draw();   . . .   }

 

 

 

 

 

 

 

 

 


Note:

·        A class may be declared abstract (to prevent instantiation) even if it has no abstract methods.

 

·        An abstract class may have non-abstract methods.

·        If there is an abstract method, the class must be declared as abstract.

 

·        An abstract class cannot be instantiated.

 

·        If a subclass of an abstract class does not implement all of the abstract methods it inherits, that subclass is itself abstract.

 

 

Interface  = a reference type whose members are constants and abstract methods

 

            interface  I  {  . . .  m();  . . . }

            interface  J  {  . . .  n();  . . .  }

 

            class  A  implements  I, J {  . . .  m(){ m1  };  . . .;  n() { n1 };  . . . }

            class  B  implements  I, J {  . . .  m(){ m2  };  . . .;  n() { n2 };  . . . }

 

            I      i  =  new A();       

            I     ii  =  new B();

            J     j  =  new A();

            J    jj  =  new B();

 

            i.m();                execution of m1             i.n()  is illegal

            ii.m();               execution of m2             ii.n()  is illegal

                j.n();                 execution of n1             j.m()  is illegal

            jj.n();                execution of n2             jj.m()  is illegal

 

            Notes:

(1)  No inheritance of variables.

 

(2)  Interfaces can be extended.

            interface  K  extends  I  {  p();  }

 

            class  C  implements  K  {  . . .;  m(){ m3 }; . . .;  p(){ p1 }; . . .  }

            class  D  extends  A  implements  K {  p(){ p2 };  }

 

            K    k  =  new C();

            K    kk = new  D();

 

            k.m();                           execution of m3

            kk.m();                         execution of m1

            k.p();                            execution of p1

            kk.p();                          execution of p2

 

(3)  No inheritance of method implementation.

 

                        class  C  implements  K  {  . . .; p(){ p1 }; . . .  }

                                    No definition of m(){ } causes a compiler error.

 

 

Main Usage              Multiple inheritance

                                    Callbacks

 

 

Anonymous Class (JDK1.1)  =  unnamed class defined within an expression

                                                            where only one instance of the class is created.

 

            new  supertype ( [construction parameter] ) {  classbody  }

 

                        (supertype = class)

            = construct an instance of a class that extends the class

                        (supertype = interface)

            = construct an instance of a class that implements the interface

 

            Note:   Since there is no name for the class,

                        Only one instance, no constructor, no static field, no modifier, and

                        instance initializer (for any class) = constructor with no arguments.

 

                        ex.        class A {  public int[] a;

                                                            {   a = new int[10];

                                                                for(int I=0; I<10; I++) a[I] = 1;

                                                            }

                                                   . . .

                                                            { any initialization statement }

                                                   . . .

                                                }

 

Instance intializers { … } are executed in sequence after the superclass constructor but before the constructor of the current class.

 

                                    new  supertype ( [construction parameter] )

                                                {  { initializer } classbody  }

 

            ex1.      Button  b1 =  new  Button(“Help”) { . . actions for Help . . }

                                    º

               class        BH  extends        Button { . . actions for Help . . }

   Button     b1 =  new  BH(“Help”)

 

                        Button  b2 =  new  Button(“Stop”) { . . actions for Stop . . }

                                    º

               class        BS  extends         Button { . . actions for Stop . . }

                           Button    b2 =  new  BS(“Stop”)

 

 

            Ex2.     interface   A  { int g(); }

                        class E { A  f() { return  new A() {  int  g() { return 3; }; }; }  }

                       

                        E    e = new E();

                        A   a = e.f();

 

                        a.g()  ==  3                   yes


 

/**

 * Anonymous classes can not define static members and can not have

 * constructors since they don't have names.  They can override superclass

 * methods.  Defining new non-static members that do not exist in the

 * superclass is allowed, but the new members can not be accessed via

 * normal means, since one can not typecast to an anonymous class type

 * or declare a variable of an anonymous type.

 * Erik B. Berry

 */

package test;

 

class A extends Object{

  public int h = 1;

  public int i = 2;

  public int e() {return 10;}

  public int f() {return 11;}

}

 

public class test {

  public static void main(String[] args) {

    // An anonymous class extending A.  The two new declarations are legal, but

    // virtually useless.  Static members are disallowed by the compiler.

    A a = new A() {

      public int i = 3;

      public int j = 4;

      // Produces Error: Variable k cannot be static in an anonymous class

      //public static int k = 5;

      public int f(){ return 12; }

      public int g(){ return 13; }

    };

    // Prints the expected 1

    System.out.println(a.h);

    // Prints the expected 10

    System.out.println(a.e());

 

    // Prints 2, because a is of type A, not the anonymous type (shadowing)

    System.out.println(a.i);

    // Prints 12, because this is an overridden superclass method

    // with dynamic (runtime) binding

    System.out.println(a.f());

 

    // Produces error: method g() not found in class test.A

    //System.out.println(a.g());

    // Produces error: variable j not found in class test.A

    //System.out.println(a.j);

  }

}

 

/**

 * Note: Technically, one could access new members defined by an anonymous

 * class using reflection in Java 1.1 or by placing the .method invocation

 * immediately after the anonymous class declaration's ending brace.

 */