Object Orientation
From Suhrid.net Wiki
Jump to navigationJump to searchContents
Constructors
- NO return type.
- Can have all the access modifiers.
- Can't be marked as abstract or final or static.
Class Modifiers
Regular Classes:
- Access Modifiers: public and default only
- Non access: strictfp, abstract and final only
- Adding any other modifier will result in a compiler error.
- A final class cannot be overriden (e.g. String)
- An abstract class cannot be instantiated (e.g. DateFormat)
Class Members
- Members can use all the access modifiers: public, private, default(package), protected
- Private members are not inherited.
- This means private members can be redeclared in subclasses.
- Instance level variables cannot be synchronized, abstract, strictfp, native.
Protected
- Protected is wider than package. Protected = package + subclasses.
- For classes and subclasses in the same package protected works in exactly the same way as package(default).
- For subclasses in other packages, protected members (both fields and methods) are only accessible through inheritance in the subclass.
- The subclass in a different package cannot use a super-class reference to access the protected member.
- Sub-class reference can be used to access a protected member.
- The keyword super can be used to access the protected member from within a subclass.
package pkg1;
public class Foo {
protected String str = "Hello";
}
package pkg2;
public class Bar extends Foo {
public void go() {
Foo f = new Foo();
String s = f.str; //Wont work ! Compiler error
System.out.println(str); //Will work - through inheritance
}
}
package pkg2;
public class Fubar {
public void goo() {
Bar b = new Bar();
System.out.println(b.str); //wont work - str only accessible through inheritance
}
}
- One more example
package pkgA;
public class Animal {
int count = 10;
protected int secret = 42;
void eat() {
System.out.println("Animal Eat");
}
protected void mope() {
System.out.println("Animal Moping");
}
}
//Same package - different class
package pkgA;
public class Zoo {
public static void main(String[] args) {
Zoo z = new Zoo();
z.go();
}
public void go() {
Animal a = new Animal();
//Package and protected are accessible
a.eat();
a.mope();
System.out.printf("Package : %d %n", a.count);
System.out.printf("Protected : %d %n", a.secret);
}
}
//Same package - subclass
package pkgA;
public class Cat extends Animal {
public static void main(String[] args) {
Cat c = new Cat();
c.catnap();
}
public void catnap() {
System.out.println("Animal count :" + count); //package variable through inheritance
System.out.println("Secret : " + secret); //protected variable through inheritance
eat(); //package method through inheritance
mope(); //protected method through inheritance
Animal a = new Animal();
//Access through super-class reference or super in all cases will work.
a.count = 20;
super.secret = 18;
super.eat();
a.mope();
}
}
//Subclass in a different package
package pkgB;
import pkgA.Animal;
public class Dog extends Animal {
public static void main(String[] args) {
Dog d = new Dog();
d.dawg();
d.mope(); //OK subclass reference.
}
public void dawg() {
//None of the package level members will be accessible.
System.out.println(secret); //This will work
System.out.println(super.secret) // OR this will too
Animal a = new Animal();
System.out.println(a.secret); //This wont. Compile error.
System.out.println(mope()); //OK
System.out.println(super.mope()); //OK
System.out.println(a.mope()); //NO. Compiler error.
}
}
=== protected static methods and constructors ===
* Protected static methods can be invoked by all classes in the same package AND by child classes which are in other packages.
* Since it is static, the rules regarding which reference (child/super) to invoke it do not apply.
* It can be invoked using the Class name.
* For classes in same package, invoking the protected constructor is not a problem.
* FOr class outside the package, the protected constructor can only be invoked by child-classes using a call to super().
<syntaxhighlight lang="java5">
package prexams.exam4.util;
public class Utils {
protected Utils() {
}
public Utils(String s) {
}
protected static void do3() {
System.out.println("do3");
}
}
package prexams.exam4;
import prexams.exam4.util.Utils;
class NonChild {
public void go() {
Utils u = new Utils(); //Non-child class cant access protected constructor
}
public void bar() {
Utils.do3(); // Non-child class - Protected static method is inaccessible.
}
}
public class UPS extends Utils {
UPS() {
super(); //OK since UPS is a subclass.
}
public static void main(String[] args) {
Utils.do3(); //static is accessible
UPS ups = new UPS();
ups.do3(); //meaningless but OK
Utils u = new Utils("u");
u.do3(); //meaningless but OK
}
public void foo() {
Utils u = new Utils(); //NOT OK - UPS Constructor can only called through super().
}
}
Abstract Methods
As they go against the logic of overriding :
- abstract methods cannot be static.
- abstract methods cannot be private.
Overriding
- Polymorphic method invocations apply ONLY to instance methods.
- The argument list for the overriding method must EXACTLY match that of the overriden method. Covariant arguments wont work! If arguments dont match, then the methods will overload.
- Example:
class Masher {
public void mash(Object o) {
System.out.println("Masher.mash");
}
}
class Jaws extends Masher {
public void mash(String o) { //Overloads not Overrides the superclass method
System.out.println("Jaws.mash");
}
}
public class Override {
public static void main(String[] args) {
Masher m = new Jaws();
m.mash("Hello"); //Will print Masher.mash
}
}
- The return type must be the same or a subtype (Covariant return) of the superclass method.
- If the return types are not the same and arguments are the same - then this will be a name clash and the code wont compile.
- Example:
interface Moveable {
Number moveIt();
}
class Bike implements Moveable {
public Integer moveIt() {
return new Integer(42);
}
}
- Access level CANT be more restrictive but CAN be less restrictive.
- Overriding method can throw ANY runtime exception regardless of what superclass method declares.
- Overriding method cannot throw checked exceptions that are NEWER or BROADER than superclass method.
- Overriding method can throw narrower or fewer checked exceptions.
- It also need NOT redeclare any exceptions (checked or unchecked) from the superclass.
class Handler {
public void handle() throws IOException {
System.out.println("Handler.handle()");
}
public void handleIt() throws NumberFormatException {
System.out.println("Handler.handleIt()");
}
public void handleMe() {
System.out.println("Handler.handleMe()");
}
}
class FileHandler extends Handler {
public void handle() { //OK need not redeclare checked exception
System.out.println("FileHandler.handle()");
}
public void handleIt() { //OK need not redeclare unchecked exception
System.out.println("FileHandler.handleIt()");
}
public void handleMe() throws IllegalArgumentException { //OK can declare new unchecked exception
System.out.println("Handler.handleMe()");
}
}
class Handler {
public void handle() throws IOException {
System.out.println("Handler.handle()");
}
public void handleIt() throws InterruptedException {
System.out.println("Handler.handleIt()");
}
public void handleMe() {
System.out.println("Handler.handleMe()");
}
}
class FileHandler extends Handler {
public void handle() throws FileNotFoundException { //OK, narrower checked exception can be declared to be thrown
System.out.println("FileHandler.handle()");
}
public void handleIt() throws Exception { //NOT OK, broader checked Exception being declared
System.out.println("FileHandler.handleIt()");
}
public void handleMe() throws UnknownHostException { //NOT OK, newer checked exception being declared
System.out.println("Handler.handleMe()");
}
}
Static Members
- When it comes to statics, subclasses can redefine static memebers (variables and methods). They are not overrides.
- Which member will be used depends on the reference type ! not the actual object type. See below:
class Vehicle {
public static int I = 10;
static String stop() {
return "Vehicle Stop";
}
static String move() {
return "Vehicle Move";
}
}
class Ship extends Vehicle {
public static int J = 20;
static String move() {
return "Ship Move";
}
}
public class Statics {
public static void main(String[] args) {
Vehicle v = new Vehicle();
System.out.println(v.I);
System.out.println(v.move()); //10
System.out.println(v.stop()); //Vehicle Stop
Vehicle sv = new Ship();
System.out.println(sv.I); //10
System.out.println(sv.move()); //Vehicle Move
Ship s = new Ship();
System.out.println(s.I); //10
System.out.println(s.J); //20
System.out.println(s.stop()); //Vehicle Stop
System.out.println(s.move()); //Ship Move
}
}
- When static methods are redefined in the sub-class they dont override the superclasses's, they "hide" it.
- However a static method CANNOT hide an instance method and an instance method CANNOT override a static method.
class Veg {
void eat() {
}
static void grow() {
}
}
class Potato extends Veg {
static void eat() { //COMPILER ERROR - overriding method is static
}
void grow() { //COMPILER ERROR - overriden method is static
}
}
Overloading
- Overloaded methods differ only in argument list, no other restrictions.
- Methods can be overloaded with argument types that are in the same hierarchy.
- The decision to invoke a particular overloaded method is made at COMPILE time, not at RUN time like polymorphic methods.
- See below: compiler will invoke overloaded method depending on the reference type.
class Gadget {
}
class Phone extends Gadget {
}
public class Overlord {
public static void main(String[] args) {
new Overlord().go();
}
void go() {
Gadget g = new Gadget();
Phone p = new Phone();
Gadget gp = new Phone();
foo(g); //Prints: Gadget
foo(p); //Prints: Phone
foo(gp);//Prints: Gadget
}
void foo(Gadget g) {
System.out.println("Gadget");
}
void foo(Phone p) {
System.out.println("Phone");
}
}
Casting
- References can be cast if the types belong in the same hierarchy.
- This means that an Object reference can be cast to anything.... because everything is an Object.
- However, the compiler can figure out if two references are of completely different types and they cannot be cast
Object obj = new String();
String str = (String) obj; //OK, an object can be a String.
Object obj2 = new Integer();
String str2 = (String) obj2; //Compiler says OK - but this will fail at runtime with a ClassCastException
Exception oie = new InterruptedException();
OutOfMemoryError ome = (OutOfMemoryError) oie; //An Exception can never be an Error
- The cast need not be of the same type as that of the reference variable, it can be of a sub-type as well:
interface Computable {
}
class Electronics {
}
class Computer extends Electronics implements Computable {
}
class Laptop extends Computer {
}
public class Casting {
public static void main(String[] args) {
Electronics e = new Laptop();
Electronics e2 = (Computer) e;
Computer comp = (Laptop) e;
}
}