/** * Sandeep Desai s_desai@hotmail.com http://www.thedesai.net * * Objects.java * Show all the OOP features like objects, inheritance, polymorphism, * exceptions and RTTI (Run-Time Type Identification) * You can print this program and read it from top to bottom * * Book Reference: Thinking in Java 3rd Ed * * To run this program download the J2SDK 1.4.2 or later from java.sun.sun.com * * OOPS * encapsulation * polymorphism * overloading (same method name with different * parameters determined at compile time) * overriding (override by inheriting) * when inheriting cannot make access weaker * (public to private not OK, private to public OK) * * * constructor can throw any exception. * construct can list exceptions using throws keywords like other methods * constructor cannot have native final synchrnoized static * constructors are not inherited * constructor body can have return statement * constructors can call other constructors * methods cannot call constructors * you can either call super or this in a constructor, but not both * c * * Initializer blocks are executed in the order of declaration. * Instance initializer(s) gets executed ONLY IF the objects are constructed. * multiple static initializers OK * abstract class may not have abstract methods * a class with abstract methods has to be declared abstract * static void foo() and void foo() in a class cause compile error * No way to call grandparents method can only access parent using super * You can never cast objects of sibling classes( sharing the same parent ), * even with an explicit cast. * variables can have same name as method names * Object o = new Integer(10); * Object o2 = (String) o; // Class Cast exception at runtime * * * Class declarations can come in any order ( derived first, base next etc. ). * top level class cannot be private or protected * instance variable cannot be syncrhonized strictfp native abstract * private methods become invisible so inherting class, * can redefine them with same name * method delcaration access modifiers any order, * but return type has to preced method name * concrete class can override method and make it abstract * transient and static skipped by serializable * variable access decided at compile time (overriden methods at runtime) * * interface ai {int i=0;} * class Parent { int i=ai.i+1; } * class Child extends Parent {int i=ai.i+2; } * test() { Parent p = new Parent(); Child c = (Child) c; // runtime ClassCast error } * * // base b = new parent() // throws null pointernull pointer exception * class base { String s="b"; base() { print(); } void print() { s.trim(); //NPE } } * class parent extends base { String s="p"; void print() { s.trim(); } } * * class Test extends { * static { int i = 0; System.out.println("a"); } * static { int j = 0; System.out.println("b"); } * { int j= 0; System.out.println("c"); } * { int k = 0; System.out.println("d"); }} * * Inner classes * generates MyOuter$MyInner.class * declared inside a class * * Non static inner classes * cannot have a static member. * can have only compile time constants static or final * cannot have an interface * can be abstract, private, public, protected * can refer to outer class member variables * outer class instance implicitly passed to inner class * refer to outer class instance as MyOuter.this * outside of outer class create new * MyOuter mo = new MyOuer(); * MyOuter.MyInner mi = mo.new MyOuter.MyInner(); * * Static inner class * is really a top level non nested class * can refer only to static outer class member * outside of outer class create using * MyOuter.MyInnner mi = new MyOuter.MyInner(); * * Method local inner class * declared in a method * can be abstract or final only * can only refer to local variables that are final * * Anonymous inner class * have no name * can only extend one class or interface * cannot have constructor * local variables marked final * * Argument local inner class * declared inside a method call * * Exceptions: * try should end with catch or finally * catch should preced finally * finally always called except if System.out.exit() called * finally called even if catch statement throws exception * finally called even if there is a return statement * inherting methods can remove exception, * but cannot add new exceptions or general exceptions * If exception thrown look for try catch * You can add RuntimeException or Error but not * Exception to inherting method with no exceptions * * */ /** * Selected list of RuntimeExceptions * ArithmeticException, ClassCastException, ConcurrentModificationException, * IllegalArgumentException, IllegalMonitorStateException, IndexOutOfBoundsException, * NegativeArraySizeException, NoSuchElementException, NullPointerException, * SecurityException, SystemException, UnmodifiableSetException, UnsupportedOperationException */ // import java.lang.*; Is automatically imported // import specific classes, allows us to use this class in this file import java.util.Vector; import java.util.Random; /** * All objects inherit from java.lang.Object * good to check instanceof in equals * class Foo { boolean equals(Object o) } compile * error as equals has default package access * public void equals(Object o) * protected void finalize() // called only once (maybe) exceptions thrown ignored * public int hashCode() // good idea to override hashCode and equals together * public void notify() // Wake up thread that is waiting for this Objects lock * public void notifyAll() * public void wait() * public void wait(long timeout) * public String toString() // Object.toString() returns classname@4ae3 */ /** * +-Object * | * +--+ Throwable (printStackTrace() method, unwinds stack) * | * +--+ Error (Out of Memory etc) typicall not handled in code * | +-- AssertionError (empty, primitive datatype and Object constructor) * | * | * +--+ Exception * +--+ IllegalAccessException not runtime * | * +--+ RuntimeException (unchecked exception does not have to be caught) * +-- IllegalArgumentException * +-- ArithmeticArgumentException * +-- NullPointerArgumentException * +-- IndexOutOfBoundsException * +-- UnsupportedOperationException * */ // Class name and file name has to match, top level class cannot be private public class Objects { // all classes inherit from java.lang.Object // public static void foo() {} public static void method(String foo) throws Exception {} // exceptions are used for error handling // exceptions propogate if not caught // exception matching done on catch clause public static void exceptions() { int[] ai = new int[2]; try { ai[3] = 4; // gaurded region } catch (IndexOutOfBoundsException ie) { System.out.println(ie); } } public static void objects() { // uses classes and interfaces defined below // since inner classes require a reference to outer class object // we have to do a outerClassInstance.new Rectangle arectangle = new Rectangle(); // 1) allocates memory for Rectangle object // 2) Call base class constructor (Shape ) // 3) Call base class constructor (Object ) // 4) Call derived class constructor in order of inheritance // 5) member initializers // 6) Call Rectangle constructor() of class for which // object is being created (Rectangle) Rectangle arectangle2 = new Rectangle(2, 2); // In this case Rectangle constructor called first Circle acircle = new Circle(3); Shape[] ashape; ashape = new Shape[2]; ashape[0] = arectangle; // upcast is safe ashape[1] = acircle; // upcast is safe // Polymorphism, java at runtime figures out the right draw method to call ashape[0].draw(); // will call Rectangle.draw() // downcast can be fail at runtime with ClassCastException Rectangle rect = (Rectangle) ashape[0]; // since ashape[1] refers to a Circle this line will fail at runtime try { rect = (Rectangle) ashape[1]; } catch (ClassCastException e) { System.out.println("class cast exception"); } // use RTTI (Runtime Type Identification) // instanceof checks if object is of specific class // or inherits from sepcific class if (ashape[0] instanceof Rectangle) {} // true if (ashape[0] instanceof Shape) { } // true if (!(null instanceof Rectangle)) { System.out.println("null instanceof false"); } if (ashape instanceof Object) {} // true Print p = acircle; if (p instanceof Object) { System.out.println("Circle instanceof Print Interface"); } // Construct instance of a class equivalent to a new // Java forces use to check for the exceptions try { Rectangle rect2 = (Rectangle) Rectangle.class.newInstance(); } catch (IllegalAccessException ie) {} // catch (InstantiationException ie2) {} // Constructor threw some exception Rectangle rect3 = new Rectangle(); System.out.println("Order of constructor calls"); // ***** constructors for all parent classes always called Circle c = new Circle(1, 1.0f); // show how object are passed by reference, so you can change object // contents but not reference // show how to reference static data and methods } // all exceptions thrown by a method have to be listed // two types of exceptions checked and unchecked (Runtime) // catching unchecked exceptions is optional e.g are divide by zero, // Array Illegal out of bound exception // method inherited new Checked Exceptions cannot be added // or more general checked exceptions cannot be listed // Any method optional to list any Error or RuntimeExceptions // Note NegativeValueException and InvalidValueException class defined below // all three ways listed below are valid ways to for this method declaration public static void incrementValue(int ai) throws NegativeValueException, InvalidValueException //public static void incrementValue(int ai) //throws InvalidValueException // just listed parent exceptions class //public static void incrementValue(int ai) throws Exception { if (ai < 0) throw new NegativeValueException("value is negative", 10); if (ai > 10) throw new InvalidValueException("value is too large", 10); // (unchecked) runtime exception does not have to be caught if (ai % 2 == 0) throw new SomeRuntimeException(); ++ai; } public static void exceptions2() { int a = 0; // catch is optional, must have catch or finally // list all subclass (specific) exceptions first and then general // will generate compilation error // try {} catch(Exception e) {} catch(InvalidValueException e) {} try { incrementValue(a); incrementValue(-1); // will throw exception incrementValue(2); // this line never run return; // finally is executed even if return in try code } catch (NegativeValueException ne) { ne.printStackTrace(); // where exception was thrown System.out.println(ne.getLocalizedMessage()); } catch (InvalidValueException ne) { } catch (Exception e) {} // Will catch all exceptions catch (Throwable t) {} // Will catch all runtime exceptions // Note that exceptions thrown in finally are lost finally { // need try catch here to if calling methods that throw // checked exceptions } // optional finally is called, put cleanup code here e.g closing files } // Java 1.4 adds a new feature for chaining exceptions public static void wrapException() throws WrapException { int a = 0; try { incrementValue(-1); // will throw exception } catch (Exception e) { // capture information about original cause of exception throw new WrapException("don't like value", e); // lose all information about original cause of exception //throw new WrapException("don't like value"); } } public static void exceptions3() { try { wrapException(); } catch (WrapException we) { System.out.println("Caught wrap exception"); Throwable t = we.getCause(); // this is the actual exception thrown // prints correct stack trace of actual code throwing exception we.printStackTrace(); } } /** * Overloaded methods (Which method to call determined at compile time) * Overloaded Rules: * overloaded methods must change the argument list * overloaded methods can change the return type * overloaded methods can change the access modifier * overloaded methods can declare new or broader checked exceptions * A method can be overloaded in the same class or in a subclass */ static void m1(int x) {} //static int m1(int x) {} // will not compile static void m1(float x) {} // will call m1(Shape) method not m1(Rectangle) // Shape s = new Rectangle(); overloadedMethod(s); static void m1(Shape x) {} static void m1(Rectangle x) {} // If your code has a lot of instanceof then your are not doing proper OOP Code public static void rtti() { // Load a class try { Class.forName("Tutorial"); } catch (ClassNotFoundException e) {} Class booleanClass = boolean.class; // each primitiv data type has a .class //Boolean.TYPE Package packageName = Objects.class.getPackage(); String foo = null; try { foo = (String) String.class.newInstance(); } catch (IllegalAccessException e) {} catch (InstantiationException e) {} Class stringClass = foo.getClass(); boolean b = String.class.isInstance(foo); } public static void anonymousInnerClass() { // local variables accessed from inner class have to be final // because the class may pass this variable to some other class // final Button b = new Button(); String s; b.name = "foo"; Controller c = new Controller(); // Anonymous inner class, we are implementing class within an // argument to a method // can only extend 1 class or 1 interface // translates to b.addActionListener(new class Objects$1 // implements ActionListener() { b.addActionListener(new ActionListener() { // can't define constructor, so have to put the code // as shown below { System.out.println("no constructor"); } // local variables accessed from inner class have to be final public void actionEvent() { System.out.println(b.name); } // can call outerclass methods since we have reference // to outer class object public void anotherEvent() { foo(); } } ); // **** ; is very important only place class declaration ends in ; c.callback(); // can have class within a method goes out of scope after the method class Foo { public void foo() {} } { // class with any {} scope could be an if, while etc class Foo { public void foo() {} } } } static int si = 2; // allocated only once per program run private static float staticMethod() { return 4.2f; } // can’t reference this.i // this code is excuted when Java loads the Tutorial class static { si = 3; System.out.println("Tutorial class loaded"); } public static void main(String[] args) { exceptions(); objects(); exceptions2(); exceptions3(); // Chained Exceptions // only one instance of static for the whole process si = 3; Objects.si = 4; // Objects.staticMethod(); Objects t = new Objects(); // create a new instanace of tutorial // no need to free this memory it will be garbage collected when // there are no live threads referenceing this object int x; // Not initialized, can have any value { // int x = 3; // Not allowed int y = 3; } // y out of scope here Vector v = new Vector(); // requires import java.util.Vector; // does not require import as we are using full package name v = new java.util.Vector(); v.add(new String("a")); // automatic upcasting from String to object } // aa’s reference cannot be changed but you can still to things like aa.trim() // to change contents of object final String aa = new String("a "); final static int fj = new Random().nextInt(); //final int qfinal; //someMethod(new Integer[] { new Integer(1), new Integer(2) }); } /** * * Cannot run java MyOuter$MyInner * Innner class cannot be protected or final * Inner class can access outer class private variables * For Method Inner class, can only access local variables that are final * * Inner classes * 1) A class defined within a method * 2) A class defined within a scope inside a method * 3) An anonymous class implementing an interface or a class * 4) An anonymous class extending a class that has a nondefault constructor * 5) An anonymous class that performs field initialization * 6) An anonymous class that performs construction using instance initialization * (anonymous inner classes cannot have constructors) * */ class MyOuter { class MyInner { public void foo() { int a = MyOuter.this.j; // To refer int b = j; // To refer } //Inner class cannot have static member //static int j; // final static OK final static int j = 0; // interface foo {} // will not compile interface implicitly static } int j; interface MyInnerInterface {} } class InheritInner extends MyOuter.MyInner { //! InheritInner() {} // Won't compile InheritInner(MyOuter wi) { wi.super(); } public void foo2() { // Inner class in a method can only be instantiated in the class // as scope of class within method // Method local cannot be public, private or protected, static or transient // only abstract and final class methodInnerClass { } methodInnerClass mi = new methodInnerClass(); } public static void innerClass() { MyOuter mo = new MyOuter(); MyOuter.MyInner mi = mo.new MyInner(); } } //static class Foo {} // Illegal class MyOuter2 { // nested static class are also called Top Level nested class static class MyInner2 { } public static void innerClass2() { MyOuter2 mo2 = new MyOuter2(); // creating objects with static inner class MyOuter2.MyInner2 mi2 = new MyOuter2.MyInner2(); } } // Exceptions are classes you can have any methods or members class InvalidValueException extends Exception { InvalidValueException(String msg, int max) { super(msg); this.max = max; } public int max = 0; } // class NegativeValueException extends InvalidValueException { NegativeValueException(String msg, int max) { super(msg, max); } } // RuntimeExceptions are typically programmer errors and // ideally should not happen class SomeRuntimeException extends RuntimeException {} // Java 1.4 feature // /we can chain exceptions so that the user can trace the original exception class WrapException extends Exception { // if this constructor is used the cause and the stack trace of // the original exception is lost WrapException(String msg) { super(msg); } // this constructor ensures that we capture the orignal cause // and stack trace of this exception WrapException(String msg, Exception e) { super(msg, e); } } // interface can have data and method declarations but no code // an instance of an interface cannot be created // they are useful for declaring constants // Everything is public by default // interface implicitly abstract interface Print { // Note interface does not extend Object int i = 3; // static and final and has to have a value (basically a constant) public static final String s = "foo"; int len = s.length(); void print(); // methods public abstract by default //public abstract void print(); // private int i; cannot have private in an interface } // interface can extend another interface interface Print2 extends Print {} // public is required for print otherwise compile error class Print3 implements Print { public void print() {} } // A class contains data and methods (functions) // An instance of an abstract class cannot be created // May contain zero or more abstract methods // keywords strictfp, native, syncrhonized, static are implementation // specific so illegal with abstract // strictfp class or method modifier // native method only modifier abstract class abstractClass implements Print {} abstract class Shape { // Constructor has the same name as the class. It is called when an instance // of this class is created // It is used to initialize the instance (object) // Call only final or private methods in a constructor as inheritance // can cause problems // If no constructors declare this is created by default public Shape() { base = 0; System.out.println("Shape() constructor called");} public Shape(int base) { this.base = base; } // Another constructor // this is a reference to self // forces that class be declared abstract and that all classes inherting // from this class implement this method public abstract void draw(); // class inherting cannot downgrade from public to private public double area() { return base; } protected void protectedMethod() {} public void fooMethod() throws InvalidValueException {} public int base = -1; /** * Maybe called when memory is garbage collected, * recommended not to use, can be used for debugging * Will be called only once * exceptions thrown ignored but garbage collection halted * System.gc() request to force garbage collection */ protected void finalize() throws Throwable {} } // Rectangle inherits from Shape, can inherit from only one class class Rectangle extends Shape { private int length; // constructors can add to base class exceptions public Rectangle() {} // will call the Shape constructor first public Rectangle(int width, int length) { super(width); this.length = length; } // method can be only called within the class, is automatically final // as it cannot be overriden // child class can have foo1() method which will be different private void foo1() {} // can be called by methods in this class and by classes inherting from // this class and this package // becomes private in child class protected void foo2() {} // default is package access can be called by any class in this package void foo3() {} public void foo4() {} // can be called by anybody final public void foo5() {} // method cannot be overridend by child class /** * Overriding methods * Overriding Rules: * argument list must match exactly * return type must match exactly * access level must not be more restrictive * access level can be less restrictive * cannot throw new or broader exceptions * can throw narrow or fewer exceptions * cannot override method marked final * if method can't be inherited you cannot override it * overloaded methods can change return type overriding methods cannot */ public double area() { super.area(); // Call parent class area method return base*length; } // we made parent class method from protected to public here public void protectedMethod() {} public double areaWithCheck() throws NegativeValueException { super.area(); // Call parent class area method if (base < 0 || length < 0) throw new NegativeValueException("base or length is negative", 10); return base*length; } // inherited method can throw inherited exceptions // cannot add new exceptions ????? // @see public void fooMethod() throws NegativeValueException {} public void draw() { System.out.println("draw Rectangle length=" + length); } // can have same method with different arguments, overload method names public void draw(int f) { } // can't have two method names with same arguments but different return types // public int draw(int f) { } // static int ici = 2; // Inner class cannot have static String type; { // useful for anonymous classes type = "Rectangle"; System.out.println("called on new Rectangle before constructor"); area(); } private class test {} // inner class can be private } /** * A class can implement more than one interface but can extend only one class * Constructor Rules: * Same name as class * no return type * not inherited * super(..) always called * Can be private (Singleton Design Pattern) * OK to have method with same name as constructor (Bad practice) * If no constructor provided default no arg constructor created * (has same access modifier as class) * includes super() call to parent class * If constructor provided then default constructor not created * First statement must be call to this() or super() * Illegal to access instance variables before super() call finishes * Illegal -> {int z; foo() { super(z); }} * Can pass static in above example * Abstract classes have constructors * interfaces do not have constructors * methods cannot call constructors, only constructors can call constructors * use this() to call constructor from another constructor * super() or this() should be first line so can't call both * * Note overloaded constructors below */ // class foo { foo(int x) { } // this calls foo(int x) foo(float y) { this((int) y); } } // //class boo1 extends foo { } // will not compile //class boo2 extends foo { boo2(int y) { } } // will not compile class boo2 extends foo { // can only reference static method or variable in super() call boo2(int y) { super(m(y)); } static int m(int x) { return x; } } class test { public static void testfoo() { // will not compile as constructor not inherited //boo2 b21 = new boo2(1.0f); boo2 b22 = new boo2(1); } } // nobody can inherit from Circle all methods in this class // will automatically be final final class Circle extends Shape implements Print { public Circle(int radius) { super(radius); } public Circle(int radius, float precision) { System.out.println("Circle constructor(int, float) called"); } public void draw() { System.out.println(" draw circle "); } public void print() { draw(); } // have to implement print() // inner class can access outer class methods as inner class object cannot // be created without // a reference to outerclass object class innerClass { void method() { draw(); } } } // This example is based on the Java UI event callback model interface ActionListener { public void actionEvent(); public void anotherEvent(); } class Button { public String name; public void addActionListener(ActionListener al) { this.al = al; } public void callback() { if (al != null) al.actionEvent(); } ActionListener al; } class Controller { public void add(Button b) { button = b; } public void callback() { button.callback(); } Button button; }