/**
* 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;
}