Thursday, 31 December 2015

Java OOPS Concepts: Java Oops concepts

Java OOPS Concepts: Java Oops concepts: Encapsulation Imagine you wrote the code for a class, and another dozen programmers from your company all wrote programs that used your ...

Statics

Static Variables and Methods
The static modifier has such a profound impact on the behavior of a method or variable that we're treating it as a concept entirely separate from the other modifiers. To understand the way a static member works, we'll look first at a reason for using one. Imagine you've got a utility class with a method that always runs the same way; its sole function is to return, say, a random number. It wouldn't matter which instance of the class performed the method—it would always behave exactly the same way. In other words, the method's behavior has no dependency on the state (instance variable values) of an object. So why, then, do you need an object when the method will never be instance-specific? Why not just ask the class itself to run the method?

Let's imagine another scenario: Suppose you want to keep a running count of all instances instantiated from a particular class. Where do you actually keep that variable? It won't work to keep it as an instance variable within the class whose instances you're tracking, because the count will just be initialized back to a default value with each new instance. The answer to both the utility-method-always-runsthe-same scenario and the keep-a-running-total-of-instances scenario is to use the static modifier. Variables and methods marked static belong to the class, rather than to any particular instance. In fact, you can use a static method or variable without having any instances of that class at all. You need only have the class available to be able to invoke a static method or access a static variable. static variables, too, can be accessed without having an instance of a class. But if there are
instances, a static variable of a class will be shared by all instances of that class; there is only one copy.

The following code declares and uses a static counter variable:

class Frog {
    static int frogCount = 0; // Declare and initialize
    // static variable
    
    public Frog() {
        frogCount += 1; // Modify the value in the constructor
    }

    public static void main (String [] args) {
        new Frog();
        new Frog();
        new Frog();
        System.out.println("Frog count is now " + frogCount);
    }
}

In the preceding code, the static frogCount variable is set to zero when the Frog class is first loaded by the JVM, before any Frog instances are created! (By the way, you don't actually need to initialize a static variable to zero; static variables get the same default values instance variables get.) Whenever a Frog instance is created, the Frog constructor runs and increments the static frogCount variable. When this code executes, three Frog instances are created in main(), and the result is

Frog count is now 3

Now imagine what would happen if frogCount were an instance variable (in other words, nonstatic):

class Frog {
    int frogCount = 0; // Declare and initialize
    // instance variable
    
    public Frog() {
        frogCount += 1; // Modify the value in the constructor
    }

    public static void main (String [] args) {
        new Frog();
        new Frog();
        new Frog();
        System.out.println("Frog count is now " + frogCount);
    }
}

When this code executes, it should still create three Frog instances in main(), but the result is...a compiler error! We can't get this code to compile, let alone run

Frog.java:11: nonstatic variable frogCount cannot be referenced
from a static context
System.out.println("Frog count is " + frogCount);
^
1 error

The JVM doesn't know which Frog object's frogCount you're trying to access. The problem is that main() is itself a static method, and thus isn't running against any particular instance of the class, rather just on the class itself. A static method can't access a nonstatic (instance) variable, because there is no instance! That's not to say there aren't instances of the class alive on the heap, but rather that even if there are, the static method doesn't know anything about them. The same applies to instance methods; a static method can't directly invoke a nonstatic method. Think static = class, nonstatic = instance. Making the method called by the JVM (main()) a static method means the JVM doesn't have to create an instance of your class just to start running code.

One of the mistakes most often made by new Java programmers is attempting to access an instance variable (which means nonstatic variable) from the static main() method (which doesn’t know anything about any instances, so it can’t access the variable). The following code is an example of illegal access of a nonstatic variable from a static method:

class Foo {
    int x = 3;

    public static void main (String [] args) {
        System.out.println("x is " + x);
    }
}

Understand that this code will never compile, because you can’t access a nonstatic (instance) variable from a static method. Just think of the compiler saying, “Hey, I have no idea which Foo object’s x variable you’re trying to print!” Remember, it’s the class running the main() method, not an instance of the class. Of course, the tricky part for the exam is that the question won’t look as obvious as the preceding code. The problem you’re being tested for— accessing a nonstatic variable from a static method—will be buried in code that might appear to be testing something else. For example, the preceding code would be more likely to appear as

class Foo {
    int x = 3;
    float y = 4.3f;

    public static void main (String [] args) {
        for (int z = x; z < ++x; z--, y = y + z)
            // complicated looping and branching code
    }
}

So while you’re trying to follow the logic, the real issue is that x and y can’t be used within main(), because x and y are instance, not static, variables! The same applies for accessing nonstatic methods from a static method. The rule is, a static method of a class can’t access a nonstatic (instance) method or variable of its own class.

Accessing Static Methods and Variables
Since you don't need to have an instance in order to invoke a static method or access a static variable, then how do you invoke or use a static member? What's the syntax? We know that with a regular old instance method, you use the dot operator on a reference to an instance:

class Frog {
    int frogSize = 0;

    public int getFrogSize() {
        return frogSize;
    }

    public Frog(int s) {
        frogSize = s;
    }

    public static void main (String [] args) {
        Frog f = new Frog(25);
        System.out.println(f.getFrogSize()); // Access instance method using f
    }
}

In the preceding code, we instantiate a Frog, assign it to the reference variable f, and then use that f reference to invoke a method on the Frog instance we just created. In other words, the getFrogSize() method is being invoked on a specific Frog object on the heap.

But this approach (using a reference to an object) isn't appropriate for accessing a static method, because there might not be any instances of the class at all! So, the way we access a static method (or static variable) is to use the dot operator on the class name, as opposed to using it on a reference to an instance, as follows:

class Frog {
    static int frogCount = 0; // Declare and initialize static variable

    public Frog() {
        frogCount += 1; // Modify the value in the constructor
    }
}

class TestFrog {
    public static void main (String [] args) {
        new Frog();
        new Frog();
        new Frog();

        System.out.print("frogCount:"+Frog.frogCount); //Access static variable
    }
}

But just to make it really confusing, the Java language also allows you to use an object reference variable to access a static member: 

Frog f = new Frog();
int frogs = f.frogCount; // Access static variable FrogCount using f

In the preceding code, we instantiate a Frog, assign the new Frog object to the reference variable f, and then use the f reference to invoke a static method! But even though we are using a specific Frog instance to access the static method, the rules haven't changed. This is merely a syntax trick to let you use an object reference variable (but not the object it refers to) to get to a static method or variable, but the static member is still unaware of the particular instance used to invoke the static member. In the Frog example, the compiler knows that the reference variable f is of type Frog, and so the Frog class static method is run with no awareness or concern for the Frog instance at the other end of the f reference. In other words, the compiler cares only that reference variable f is declared as type Frog.


Finally, remember that static methods can't be overridden! This doesn't mean they can't be redefined in a subclass, but redefining and overriding aren't the same thing. Let's take a look at an example of a redefined (remember, not overridden), static method:

class Animal {
    static void doStuff() {
        System.out.print("a ");
    }
}

class Dog extends Animal {
    static void doStuff() { // it's a redefinition, not an override
        System.out.print("d ");
    }

    public static void main(String [] args) {
        Animal [] a = {new Animal(), new Dog(), new Animal()};
       for(int x = 0; x < a.length; x++)
           a[x].doStuff(); // invoke the static method
    }
}

Running this code produces the output:
a a a

Remember, the syntax a[x].doStuff() is just a shortcut (the syntax trick)…the compiler is going to substitute something like Animal.doStuff() instead. Notice that we didn't use the Java 1.5 enhanced for loop here, even though we could have. Expect to see a mix of both Java 1.4 and Java 5 coding styles and practices on the exam.

Tuesday, 29 December 2015

Overriding / Overloading

Overridden Methods
Any time you have a class that inherits a method from a superclass, you have the opportunity to override the method (unless, as you learned earlier, the method is marked final). The key benefit of overriding is the ability to define behavior that's specific to a particular subclass type. The following example demonstrates a Horse subclass of Animal overriding the Animal version of the eat() method:

public class Animal {
    public void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}

class Horse extends Animal {
    public void eat() {
        System.out.println("Horse eating hay, oats, " + "and horse treats");
    }
}

For abstract methods you inherit from a superclass, you have no choice. You must implement the method in the subclass unless the subclass is also abstract. Abstract methods must be implemented by the concrete subclass, but this is a lot like saying that the concrete subclass overrides the abstract methods of the superclass. So you could think of abstract methods as methods you're forced to override.

The Animal class creator might have decided that for the purposes of polymorphism, all Animal subtypes should have an eat() method defined in a unique, specific way. Polymorphically, when someone has an Animal reference that refers not to an Animal instance, but to an Animal subclass instance, the caller should be able to invoke eat() on the Animal reference, but the actual runtime object (say, a Horse instance) will run its own specific eat() method. Marking the eat() method abstract is the Animal programmer's way of saying to all subclass developers, "It doesn't make any sense for your new subtype to use a generic eat() method, so you have to come up with your own eat() method implementation!" A (non-abstract), example of using polymorphism looks like this:

public class TestAnimals {
    public static void main (String [] args) {
        Animal a = new Animal();
        Animal b = new Horse(); //Animal ref, but a Horse object
        a.eat(); // Runs the Animal version of eat()
        b.eat(); // Runs the Horse version of eat()
    }
}

class Animal {
    public void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}

class Horse extends Animal {
    public void eat() {
        System.out.println("Horse eating hay, oats, " + "and horse treats");
    }
    
    public void buck() { }
}

In the preceding code, the test class uses an Animal reference to invoke a method on a Horse object. Remember, the compiler will allow only methods in class Animal to be invoked when using a reference to an Animal. The following would not be legal given the preceding code:

Animal c = new Horse();
c.buck(); // Can't invoke buck();
// Animal class doesn't have that method

To reiterate, the compiler looks only at the reference type, not the instance type. Polymorphism lets you use a more abstract supertype (including an interface) reference to refer to one of its subtypes (including interface implementers).

The overriding method cannot have a more restrictive access modifier than the method being overridden (for example, you can't override a method marked public and make it protected). Think about it: if the Animal class advertises a public eat() method and someone has an Animal reference (in other words, a reference declared as type Animal), that someone will assume it's safe to call eat() on the Animal reference regardless of the actual instance that the Animal reference is referring to. If a subclass were allowed to sneak in and change the access modifier on the overriding method, then suddenly at runtime—when the JVM invokes the true object's (Horse) version of the method rather than the reference type's (Animal) version—the program would die a horrible death. (Not to mention the emotional distress for the one who was betrayed by the rogue subclass.) Let's modify the
polymorphic example we saw earlier in this section:

public class TestAnimals {
    public static void main (String [] args) {
        Animal a = new Animal();
        Animal b = new Horse(); //Animal ref, but a Horse object
        a.eat(); // Runs the Animal version of eat()
        b.eat(); // Runs the Horse version of eat()
    }
}

class Animal {
    public void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}

class Horse extends Animal {
    private void eat() { // whoa! - it's private!
        System.out.println("Horse eating hay, oats, " + "and horse treats");
    }
}

If this code compiled (which it doesn't), the following would fail at runtime:
Animal b = new Horse();     // Animal ref, but a Horse
                                           // object , so far so good

b.eat();                                // Meltdown at runtime!

The variable b is of type Animal, which has a public eat() method. But remember that at runtime, Java uses virtual method invocation to dynamically select the actual version of the method that will run, based on the actual instance. An Animal reference can always refer to a Horse instance, because Horse IS-A(n) Animal. What makes that superclass reference to a subclass instance possible is that the subclass is guaranteed to be able to do everything the superclass can do. Whether the Horse instance overrides the inherited methods of Animal or simply inherits them, anyone with an Animal reference to a Horse instance is free to call all accessible Animal methods. For that reason, an overriding method must fulfill the contract of the superclass.

The rules for overriding a method are as follows:

  • The argument list must exactly match that of the overridden method. If they don't match, you can end up with an overloaded method you didn't intend.
  • The return type must be the same as, or a subtype of, the return type declared in the original overridden method in the superclass. (More on this in a few pages when we discuss covariant returns.)
  • The access level can't be more restrictive than the overridden method's.
  • The access level CAN be less restrictive than that of the overridden method.
  • Instance methods can be overridden only if they are inherited by the subclass. A subclass within the same package as the instance's superclass can override any superclass method that is not marked private or final. A subclass in a different package can override only those non-final methods marked public or protected (since protected methods are inherited by the subclass).
  • The overriding method CAN throw any unchecked (runtime) exception, regardless of whether the overridden method declares the exception.
  • The overriding method must NOT throw checked exceptions that are new or broader than those declared by the overridden method. For example, a method that declares a FileNotFoundException cannot be overridden by a method that declares a SQLException, Exception, or any other non-runtime
  • exception unless it's a subclass of FileNotFoundException.
  • The overriding method can throw narrower or fewer exceptions. Just because an overridden method "takes risks" doesn't mean that the overriding subclass' exception takes the same risks. Bottom line: an overriding method doesn't have to declare any exceptions that it will never throw, regardless of what the overridden method declares.
  • You cannot override a method marked final.
  • You cannot override a method marked static. We'll look at an example in a few pages when we discuss static methods in more detail.
  • If a method can't be inherited, you cannot override it. Remember that overriding implies that you're reimplementing a method you inherited! For example, the following code is not legal, and even if you added an eat() method to Horse, it wouldn't be an override of Animal's eat() method.
public class TestAnimals {
    public static void main (String [] args) {
        Horse h = new Horse();
        h.eat(); // Not legal because Horse didn't inherit eat()
    }
}

class Animal {
    private void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}

class Horse extends Animal { }

Invoking a Superclass Version of an Overridden Method
Often, you'll want to take advantage of some of the code in the superclass version of a method, yet still override it to provide some additional specific behavior. It's like saying, "Run the superclass version of the method, then come back down here and finish with my subclass additional method code." (Note that there's no requirement that the superclass version run before the subclass code.) It's easy to do in code using the keyword super as follows:

public class Animal {
    public void eat() { }
    public void printYourself() {
        // Useful printing code goes here
    }
}

class Horse extends Animal {
    public void printYourself() {
        // Take advantage of Animal code, then add some more
        super.printYourself(); // Invoke the superclass
                                        // (Animal) code
                                        // Then do Horse-specific
                                       // print work here
     }
}

Note: Using super to invoke an overridden method only applies to instance methods. (Remember, static methods can't be overridden.)

If a method is overridden but you use a polymorphic (supertype) reference to refer to the subtype object with the overriding method, the compiler assumes you’re calling the supertype version of the method. If the supertype version declares a checked exception, but the overriding subtype method does not, the compiler still thinks you are calling a method that declares an exception

class Animal {
    public void eat() throws Exception {
        // throws an Exception
    }
}

class Dog2 extends Animal {
    public void eat() { /* no Exceptions */}
    public static void main(String [] args) {
        Animal a = new Dog2();
        Dog2 d = new Dog2();
        d.eat(); // ok
        a.eat(); // compiler error -
        // unreported exception
    }
}

This code will not compile because of the Exception declared on the Animal eat() method. This happens even though, at runtime, the eat() method used would be the Dog version, which does not declare the exception.

Examples of Legal and Illegal Method Overrides
Let's take a look at overriding the eat() method of Animal:

public class Animal {
    public void eat() { }
}

Examples of Illegal Overrides
Illegal Override Code
Problem with the Code
private void eat() { }
Access modifier is more restrictive
public void eat() throws IOException { }
Declares a checked exception not defined by superclass version
public void eat(String food) { }
A legal overload, not an override, because the argument list changed
public String eat() { }
Not an override because of the return type, not an overload either because there’s no change in the argument list
Overloaded Methods
You're wondering what overloaded methods are doing in an OO chapter, but we've included them here since one of the things newer Java developers are most confused about are all of the subtle differences between overloaded and overridden methods.

Overloaded methods let you reuse the same method name in a class, but with different arguments (and optionally, a different return type). Overloading a method often means you're being a little nicer to those who call your methods, because your code takes on the burden of coping with different argument types rather than forcing the caller to do conversions prior to invoking your method. The rules are simple:
  • 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. In other words, if class A defines a doStuff(int i) method, the subclass B could define a doStuff(String s) method without overriding the superclass version that takes an int. So two methods with the same name but in different classes can still be considered overloaded, if the subclass inherits one version of the method and then declares another overloaded version in its class definition.
Be careful to recognize when a method is overloaded rather than overridden. You might see a method that appears to be violating a rule for overriding, but that is actually a legal overload, as follows:

public class Foo {
    public void doStuff(int y, String s) { }
    public void moreThings(int x) { }
}
class Bar extends Foo {
    public void doStuff(int y, long s) throws IOException { }
}

It's tempting to see the IOException as the problem, because the overridden doStuff() method doesn’t declare an exception, and IOException is checked by the compiler. But the doStuff() method is not overridden! Subclass Bar overloads the doStuff() method, by varying the argument list, so the IOException is fine.

Legal Overloads
Let's look at a method we want to overload:
public void changeSize(int size, String name, float pattern) { }

The following methods are legal overloads of the changeSize() method:
public void changeSize(int size, String name) { }
public int changeSize(int size, float pattern) { }
public void changeSize(float pattern, String name)
throws IOException { }

Invoking Overloaded Methods
Note that there's a lot more to this discussion on how the compiler knows which method to invoke, but the rest is covered in Chapter 3 when we look at boxing and var-args—both of which have a huge impact on overloading. (You still have to pay attention to the part covered here, though.)

When a method is invoked, more than one method of the same name might exist for the object type you're invoking a method on. For example, the Horse class might have three methods with the same name but with different argument lists, which means the method is overloaded.

Deciding which of the matching methods to invoke is based on the arguments. If you invoke the method with a String argument, the overloaded version that takes a String is called. If you invoke a method of the same name but pass it a float, the overloaded version that takes a float will run. If you invoke the method of the same name but pass it a Foo object, and there isn't an overloaded version that takes a Foo, then the compiler will complain that it can't find a match. The following are examples of invoking overloaded methods:

class Adder {
    public int addThem(int x, int y) {
        return x + y;
    }

    // Overload the addThem method to add doubles instead of ints
    public double addThem(double x, double y) {
        return x + y;
    }
}

// From another class, invoke the addThem() method
public class TestAdder {
    public static void main (String [] args) {
        Adder a = new Adder();
        int b = 27;
        int c = 3;
        int result = a.addThem(b,c); // Which addThem is invoked?
        double doubleResult = a.addThem(22.5,9.3); // Which addThem?
    }
}

In the preceding TestAdder code, the first call to a.addThem(b,c) passes two ints to the method, so the first version of addThem()—the overloaded version that takes two int arguments—is called. The second call to a.addThem(22.5, 9.3) passes two doubles to the method, so the second version of addThem()—the overloaded version that takes two double arguments—is called.

Invoking overloaded methods that take object references rather than primitives is a little more interesting. Say you have an overloaded method such that one version takes an Animal and one takes a Horse (subclass of Animal). If you pass a Horse object in the method invocation, you'll invoke the overloaded version that takes a Horse. Or so it looks at first glance:

class Animal { }
    class Horse extends Animal { }
    class UseAnimals {
        public void doStuff(Animal a) {
            System.out.println("In the Animal version");
        }

        public void doStuff(Horse h) {
            System.out.println("In the Horse version");
        }

        public static void main (String [] args) {
            UseAnimals ua = new UseAnimals();
            Animal animalObj = new Animal();
            Horse horseObj = new Horse();
            ua.doStuff(animalObj);
            ua.doStuff(horseObj);
       }
}

The output is what you expect:
in the Animal version
in the Horse version

But what if you use an Animal reference to a Horse object?
Animal animalRefToHorse = new Horse();
ua.doStuff(animalRefToHorse);

Which of the overloaded versions is invoked? You might want to say, "The one that takes a Horse, since it's a Horse object at runtime that's being passed to the method." But that's not how it works. The preceding code would actually print:

Even though the actual object at runtime is a Horse and not an Animal, the choice of which overloaded method to call (in other words, the signature of the method) is NOT dynamically decided at runtime. Just remember, the reference type (not the object type) determines which overloaded method is invoked! To summarize, which overridden version of the method to call (in other words, from which class in the inheritance tree) is decided at runtime based on object type, but which overloaded version of the method to call is based on the reference type of the argument passed at compile time. If you invoke a method passing it an Animal reference to a Horse object, the compiler knows only about the Animal, so it chooses the overloaded version of the method that takes an Animal. It does not matter that at runtime there's actually a Horse being passed.

Polymorphism in Overloaded and Overridden Methods How does polymorphism work with overloaded methods? From what we just looked at, it doesn't appear that polymorphism matters when a method is overloaded. If you pass an Animal reference, the overloaded method that takes an Animal will be invoked, even if the actual object passed is a Horse. Once the Horse masquerading as Animal gets in to the method, however, the Horse object is still a Horse despite being passed into a method expecting an Animal. So it's true that polymorphism doesn't determine which overloaded version is called; polymorphism does come into play when the decision is about which overridden version of a method is called. But sometimes, a method is both overloaded and overridden. Imagine the Animal and Horse classes look like this:

public class Animal {
    public void eat() {
        System.out.println("Generic Animal Eating Generically");
    }
}

public class Horse extends Animal {
    public void eat() {
        System.out.println("Horse eating hay ");
    }
    public void eat(String s) {
        System.out.println("Horse eating " + s);
    }
}

Notice that the Horse class has both overloaded and overridden the eat() method. Table 2-2 shows which version of the three eat() methods will run depending on how they are invoked.

Examples of Illegal Overrides
IllegMethod Invocation Code
Result
Animal a = new Animal();
a.eat();
Generic Animal Eating Generically
Horse h = new Horse();
h.eat();
Horse eating hay
Animal ah = new Horse();
ah.eat();
Horse eating hay
Polymorphism works—the actual object type (Horse), not the reference type (Animal), is used to determine which eat() is called.
Horse he = new Horse();
he.eat("Apples");
Horse eating Apples
The overloaded eat(String s) method is invoked.
Animal a2 = new Animal();
a2.eat("treats");
Compiler error! Compiler sees that Animal class doesn't have an eat() method that takes a String.
Animal ah2 = new Horse();
ah2.eat("Carrots");
Compiler error! Compiler still looks only at the reference, and sees that Animal doesn’t have an eat() method that takes a String. Compiler doesn’t care that the actual object might be a Horse at
runtime.
Don’t be fooled by a method that’s overloaded but not overridden by a subclass. It’s perfectly legal to do the following:

public class Foo {
    void doStuff() { }
}
class Bar extends Foo {
    void doStuff(String s) { }
}

The Bar class has two doStuff() methods: the no-arg version it inherits from Foo (and does not override), and the overloaded doStuff(String s) defi ned in the Bar class. Code with a reference to a Foo can invoke only the no-arg version, but code with a reference to a Bar can invoke either of the overloaded versions.

Differences Between Overloaded and Overridden Methods

Overloaded Method
Overridden Method
Argument(s)
Must change.
Must not change.
Return type
Can change
Can’t change except for covariant returns
Exceptions
Can change
Can reduce or eliminate. Must not throw new or broader checked
exceptions.
Access
Can change
Must not make more restrictive (can be less restrictive).
Invocation
Reference type determines which overloaded version (based
on declared argument types) is selected. Happens at compile
time. The actual method that’s invoked is still a virtual method
invocation that happens at runtime, but the compiler will
already know the signature of the method to be invoked. So at
runtime, the argument match will already have been nailed
down, just not the class in which the method lives.
Object type (in other
words, the type of the
actual instance on the
heap) determines which
method is selected.
Happens at runtime.


Monday, 28 December 2015

Java Oops concepts

Encapsulation

Imagine you wrote the code for a class, and another dozen programmers from your company all wrote programs that used your class. Now imagine that later on, you didn't like the way the class behaved, because some of its instance variables were being set (by the other programmers from within their code) to values you hadn't anticipated. Their code brought out errors in your code. (Relax, this is just hypothetical.) Well, it is a Java program, so you should be able just to ship out a newer version of the class, which they could replace in their programs without changing any of their own code. 
This scenario highlights two of the promises/benefits of Object Orientation (OO): flexibility and maintainability. But those benefits don't come automatically. You have to do something. You have to write your classes and code in a way that supports flexibility and maintainability. So what if Java supports OO? It can't design your code for you. For example, imagine if you made your class with public instance variables, and those other programmers were setting the instance variables directly, as the following code demonstrates:

public class BadOO {   
    public int size;
    public int weight;   ... 

public class ExploitBadOO {   
    public static void main (String [] args) {      
        BadOO b = new BadOO();      
        b.size = -5; // Legal but bad!!   
    } 
}

And now you're in trouble. How are you going to change the class in a way that lets you handle the issues that come up when somebody changes the size variable to a value that causes problems? Your only choice is to go back in and write method code for adjusting size (a setSize(int a) method, for example), and then protect the size variable with, say, a private access modifier. But as soon as you make that change to your code, you break everyone else's! 

The ability to make changes in your implementation code without breaking the code of others who use your code is a key benefit of encapsulation. You want to hide implementation details behind a public programming interface. By interface, we mean the set of accessible methods your code makes available for other code to call—in other words, your code's API. By hiding implementation details, you can rework your method code (perhaps also altering the way variables are used by your class) without forcing a change in the code that calls your changed method. 

If you want maintainability, flexibility, and extensibility (and of course, you do), your design must include encapsulation. How do you do that?

  • Keep instance variables protected (with an access modifier, often private). 
  • Make public accessor methods, and force calling code to use those methods rather than directly accessing the instance variable. 
  • For the methods, use the JavaBeans naming convention of set<someProperty> and get<someProperty>.

Figure 2-1 illustrates the idea that encapsulation forces callers of our code to go through methods rather than accessing variables directly.

We call the access methods getters and setters although some prefer the fancier terms accessors and mutators. (Personally, we don't like the word "mutate".) Regardless of what you call them, they're methods that other programmers must go through in order to access your instance variables. They look simple, and you've probably been using them forever:

public class Box {
    // protect the instance variable; only an instance
    // of Box can access it
    private int size;
    // Provide public getters and setters
    
    public int getSize() {
        return size;
    }

    public void setSize(int newSize) {
        size = newSize;
    }
}

Wait a minute...how useful is the previous code? It doesn't even do any validation or processing. What benefit can there be from having getters and setters that add no additional functionality? The point is, you can change your mind later, and add more code to your methods without breaking your API. Even if today you don't think you really need validation or processing of the data, good OO design dictates that you plan for the future. To be safe, force calling code to go through your methods rather than going directly to instance variables. Always. Then you're free to rework your method implementations later, without risking the wrath of those dozen programmers who know where you live.

Inheritance, Is-A, Has-A


Inheritance is everywhere in Java. It's safe to say that it's almost (almost?) impossible to write even the tiniest Java program without using inheritance. In order to explore this topic we're going to use the instanceof operator remember that instanceof returns true if the reference variable being tested is of the type being compared to. This code:


class Test {
    public static void main(String [] args) {
        Test t1 = new Test();
        Test t2 = new Test();
        if (!t1.equals(t2))
            System.out.println("they're not equal");
        
        if (t1 instanceof Object)
                System.out.println("t1's an Object");
    }
}

Produces the output:
they're not equal

Where did that equals method come from? The reference variable t1 is of type Test, and there's no equals method in the Test class. Or is there? The second if test asks whether t1 is an instance of class Object, and because it is (more on that soon), the if test succeeds.

Hold on…how can t1 be an instance of type Object, we just said it was of type Test? I'm sure you're way ahead of us here, but it turns out that every class in Java is a subclass of class Object, (except of course class Object itself). In other words, every class you'll ever use or ever write will inherit from class Object. You'll always have an equals method, a clone method, notify, wait, and others, available to use. Whenever you create a class, you automatically inherit all of class Object's methods.

Why? Let's look at that equals method for instance. Java's creators correctly assumed that it would be very common for Java programmers to want to compare instances of their classes to check for equality. If class Object didn't have an equals method, you'd have to write one yourself; you and every other Java programmer. That one equals method has been inherited billions of times. (To be fair, equals has also been overridden billions of times, but we're getting ahead of ourselves.)

For the exam you'll need to know that you can create inheritance relationships in Java by extending a class. It's also important to understand that the two most common reasons to use inheritance are

  • To promote code reuse
  • To use polymorphism
Let's start with reuse. A common design approach is to create a fairly generic version of a class with the intention of creating more specialized subclasses that inherit from it. For example:

class GameShape {
    public void displayShape() {
        System.out.println("displaying shape");
    }
    // more code
}

class PlayerPiece extends GameShape {
    public void movePiece() {
        System.out.println("moving game piece");
    }
    // more code
}

public class TestShapes {
    public static void main (String[] args) {
        PlayerPiece shape = new PlayerPiece();
        shape.displayShape();
        shape.movePiece();
    }
}

Outputs:
displaying shape
moving game piece

Notice that the PlayingPiece class inherits the generic display() method from the less-specialized class GameShape, and also adds its own method, movePiece(). Code reuse through inheritance means that methods with generic functionality (like display())—that could apply to a wide range of different kinds of shapes in a game—don't have to be reimplemented. That means all specialized subclasses of GameShape are guaranteed to have the capabilities of the more generic superclass. You don't want to have to rewrite the display() code in each of your specialized components of an online game.

But you knew that. You've experienced the pain of duplicate code when you make a change in one place and have to track down all the other places where that same (or very similar) code exists.

The second (and related) use of inheritance is to allow your classes to be accessed polymorphically—a capability provided by interfaces as well, but we'll get to that in a minute. Let's say that you have a GameLauncher class that wants to loop through a list of different kinds of GameShape objects, and invoke display() on each of them. At the time you write this class, you don't know every possible kind
of GameShape subclass that anyone else will ever write. And you sure don't want to have to redo your code just because somebody decided to build a Dice shape six months later.

The beautiful thing about polymorphism ("many forms") is that you can treat any subclass of GameShape as a GameShape. In other words, you can write code in your GameLauncher class that says, "I don't care what kind of object you are as long as you inherit from (extend) GameShape. And as far as I'm concerned, if you extend GameShape then you've definitely got a display() method, so I know I can call it."

Imagine we now have two specialized subclasses that extend the more generic GameShape class, PlayerPiece and TilePiece:

class GameShape {
    public void displayShape() {
        System.out.println("displaying shape");
    }
    // more code
}

class PlayerPiece extends GameShape {
    public void movePiece() {
        System.out.println("moving game piece");
    }
    // more code
}

class TilePiece extends GameShape {
    public void getAdjacent() {
        System.out.println("getting adjacent tiles");
    }
    // more code
}

Now imagine a test class has a method with a declared argument type of GameShape, that means it can take any kind of GameShape. In other words, any subclass of GameShape can be passed to a method with an argument of type GameShape. This code

public class TestShapes {
    public static void main (String[] args) {
        PlayerPiece player = new PlayerPiece();
        TilePiece tile = new TilePiece();
        doShapes(player);
        doShapes(tile);
    }
    public static void doShapes(GameShape shape) {
        shape.displayShape();
    }
}

Outputs:
displaying shape
displaying shape

The key point is that the doShapes() method is declared with a GameShape argument but can be passed any subtype (in this example, a subclass) of GameShape. The method can then invoke any method of GameShape, without any concern for the actual runtime class type of the object passed to the method. There are implications, though. The doShapes() method knows only that the objects are
a type of GameShape, since that's how the parameter is declared. And using a reference variable declared as type GameShape—regardless of whether the variable is a method parameter, local variable, or instance variable—means that only the methods of GameShape can be invoked on it. The methods you can call on a reference are totally dependent on the declared type of the variable, no matter what the actual object is, that the reference is referring to. That means you can't use a GameShape variable to call, say, the getAdjacent() method even if the object passed in is of type TilePiece. (We'll see this again when we look at interfaces.)

IS-A
In OO, the concept of IS-A is based on class inheritance or interface implementation. IS-A is a way of saying, "this thing is a type of that thing." For example, a Mustang is a type of horse, so in OO terms we can say, "Mustang IS-A Horse." Subaru IS-A Car. Broccoli IS-A Vegetable (not a very fun one, but it still counts). You express the IS-A relationship in Java through the keywords extends (for class inheritance) and implements (for interface implementation).

public class Car {
    // Cool Car code goes here
}

public class Subaru extends Car {
    // Important Subaru-specific stuff goes here
    // Don't forget Subaru inherits accessible Car members which
    // can include both methods and variables.
}

A Car is a type of Vehicle, so the inheritance tree might start from the Vehicle class as follows:
public class Vehicle { ... }
public class Car extends Vehicle { ... }
public class Subaru extends Car { ... }

In OO terms, you can say the following:
  • Vehicle is the superclass of Car.
  • Car is the subclass of Vehicle.
  • Car is the superclass of Subaru.
  • Subaru is the subclass of Vehicle.
  • Car inherits from Vehicle.
  • Subaru inherits from both Vehicle and Car.
  • Subaru is derived from Car.
  • Car is derived from Vehicle.
  • Subaru is derived from Vehicle.
  • Subaru is a subtype of both Vehicle and Car.

Returning to our IS-A relationship, the following statements are true:

"Car extends Vehicle" means "Car IS-A Vehicle."
"Subaru extends Car" means "Subaru IS-A Car."

And we can also say:

"Subaru IS-A Vehicle" because a class is said to be "a type of" anything further up in its inheritance tree. If the expression (Foo instanceof Bar) is true, then class Foo IS-A Bar, even if Foo doesn't directly extend Bar, but instead extends some other class that is a subclass of Bar. Figure 2-2 illustrates the inheritance tree for Vehicle, Car, and Subaru. The arrows move from the subclass to the superclass. In other words, a class' arrow points toward the class from which it extends.


HAS-A
HAS-A relationships are based on usage, rather than inheritance. In other words, class A HAS-A B if code in class A has a reference to an instance of class B. For example, you can say the following,

A Horse IS-A Animal. A Horse HAS-A Halter.
The code might look like this:

public class Animal { }
public class Horse extends Animal {
    private Halter myHalter;
}

In the preceding code, the Horse class has an instance variable of type Halter, so you can say that "Horse HAS-A Halter." In other words, Horse has a reference to a Halter. Horse code can use that Halter reference to invoke methods on the Halter, and get Halter behavior without having Halter-related code (methods) in the Horse class itself. Figure 2-3 illustrates the HAS-A relationship between Horse and Halter.



HAS-A relationships allow you to design classes that follow good OO practices by not having monolithic classes that do a gazillion different things. Classes (and their resulting objects) should be specialists. As our friend Andrew says, "specialized classes can actually help reduce bugs." The more specialized the class, the more likely it is that you can reuse the class in other applications. If you put all the Halter-related code directly into the Horse class, you'll end up duplicating code in the Cow class, UnpaidIntern class, and any other class that might need Halter behavior. By keeping the Halter code in a separate, specialized Halter class, you have the chance to reuse the Halter class in multiple applications.

Object-Oriented Design
IS-A and HAS-A relationships and encapsulation are just the tip of the iceberg when it comes to object-oriented design. Many books and graduate theses have been dedicated to this topic. The reason for the emphasis on proper design is simple: money. The cost to deliver a software application has
been estimated to be as much as ten times more expensive for poorly designed programs. Having
seen the ramifications of poor designs, I can assure you that this estimate is not far-fetched.

Even the best object-oriented designers make mistakes. It is difficult to visualize the relationships between hundreds, or even thousands, of classes. When mistakes are discovered during the implementation (code writing) phase of a project, the amount of code that has to be rewritten can sometimes cause programming teams to start over from scratch.

The software industry has evolved to aid the designer. Visual object modeling languages, like the Unified Modeling Language (UML), allow designers to design and easily modify classes without having to write code first, because object-oriented components are represented graphically. This allows the designer to create a map of the class relationships and helps them recognize errors before coding begins. Another innovation in object-oriented design is design patterns. Designers noticed that many object-oriented designs apply consistently from project to project, and that it was useful to apply the same designs because it reduced the potential to introduce new design errors. Object-oriented
designers then started to share these designs with each other. Now, there are many catalogs of these design patterns both on the Internet and in book form.

Although passing the Java certification exam does not require you to understand object oriented
design this thoroughly, hopefully this background information will help you better appreciate why the test writers chose to include encapsulation, and IS-A, and HAS-A relationships on the exam.

Users of the Horse class (that is, code that calls methods on a Horse instance), think that the Horse class has Halter behavior. The Horse class might have a tie(LeadRope rope) method, for example. Users of the Horse class should never have to know that when they invoke the tie() method, the Horse object turns around and delegates the call to its Halter class by invoking myHalter.tie(rope).

The scenario just described might look like this:

public class Horse extends Animal {
    private Halter myHalter = new Halter();
    public void tie(LeadRope rope) {
        myHalter.tie(rope); // Delegate tie behavior to the
        // Halter object
    }
}

public class Halter {
    public void tie(LeadRope aRope) {
        // Do the actual tie work here
    }
}

In OO, we don't want callers to worry about which class or which object is actually doing the real work. To make that happen, the Horse class hides implementation details from Horse users. Horse users ask the Horse object to do things (in this case, tie itself up), and the Horse will either do it or, as in this example, ask something else to do it. To the caller, though, it always appears that the Horse object takes care of itself. Users of a Horse should not even need to know that there is such a thing as a Halter class.

Polymorphism

Remember, any Java object that can pass more than one IS-A test can be considered polymorphic. Other than objects of type Object, all Java objects are polymorphic in that they pass the IS-A test for their own type and for class Object.

Remember that the only way to access an object is through a reference variable, and there are a few key things to remember about references:


  • A reference variable can be of only one type, and once declared, that type can never be changed (although the object it references can change).
  • A reference is a variable, so it can be reassigned to other objects, (unless the reference is declared final).
  • A reference variable's type determines the methods that can be invoked on the object the variable is referencing.
  • A reference variable can refer to any object of the same type as the declared reference, or—this is the big one—it can refer to any subtype of the declared type!
  • A reference variable can be declared as a class type or an interface type. If the variable is declared as an interface type, it can reference any object of any class that implements the interface.
Earlier we created a GameShape class that was extended by two other classes, PlayerPiece and TilePiece. Now imagine you want to animate some of the shapes on the game board. But not all shapes can be animatable, so what do you do with class inheritance?

Could we create a class with an animate() method, and have only some of the GameShape subclasses inherit from that class? If we can, then we could have PlayerPiece, for example, extend both the GameShape class and Animatable class, while the TilePiece would extend only GameShape. But no, this won't work! Java supports only single inheritance! That means a class can have only one immediate superclass. In other words, if PlayerPiece is a class, there is no way to say something like this:

class PlayerPiece extends GameShape, Animatable { // NO!
    // more code
}

A class cannot extend more than one class. That means one parent per class. A class can have multiple ancestors, however, since class B could extend class A, and class C could extend class B, and so on. So any given class might have multiple classes up its inheritance tree, but that's not the same as saying a class directly extends two classes.

Some languages (like C++) allow a class to extend more than one other class. This capability is known as "multiple inheritance." The reason that Java's creators chose not to allow multiple inheritance is that it can become quite messy. In a nutshell, the problem is that if a class extended two other classes, and both superclasses had, say, a doStuff() method, which version of doStuff() would the subclass inherit? This issue can lead to a scenario known as the "Deadly Diamond of Death," because of the shape of the class diagram that can be created in a multiple inheritance design. The diamond is formed when classes B and C both extend A, and both B and C inherit a method from A. If class D extends both B and C, and both B and C have overridden the method in A, class D has, in theory, inherited two different implementations of the same method. Drawn as a class diagram, the shape of the four classes looks like a diamond.

So if that doesn't work, what else could you do? You could simply put the animate() code in GameShape, and then disable the method in classes that can't be animated. But that's a bad design choice for many reasons, including it's more errorprone, it makes the GameShape class less cohesive (more on cohesion in a minute), and it means the GameShape API "advertises" that all shapes can be animated, when in fact that's not true since only some of the GameShape subclasses will be able to
successfully run the animate() method.

So what else could you do? You already know the answer—create an Animatable interface, and have only the GameShape subclasses that can be animated implement that interface. Here's the interface:

public interface Animatable {
    public void animate();
}

And here's the modified PlayerPiece class that implements the interface:

class PlayerPiece extends GameShape implements Animatable {
    public void movePiece() {
        System.out.println("moving game piece");
    }

    public void animate() {
        System.out.println("animating...");
    }
    // more code
}

So now we have a PlayerPiece that passes the IS-A test for both the GameShape class and the Animatable interface. That means a PlayerPiece can be treated polymorphically as one of four things at any given time, depending on the declared type of the reference variable:

  • An Object (since any object inherits from Object)
  • A GameShape (since PlayerPiece extends GameShape)
  • A PlayerPiece (since that's what it really is)
  • An Animatable (since PlayerPiece implements Animatable)

The following are all legal declarations. Look closely:
PlayerPiece player = new PlayerPiece();
Object o = player;
GameShape shape = player;

Animatable mover = player;

There's only one object here—an instance of type PlayerPiece—but there are four different types of reference variables, all referring to that one object on the heap. Pop quiz: which of the preceding reference variables can invoke the displayShape() method? Hint: only two of the four declarations can be used to invoke the displayShape() method.

Remember that method invocations allowed by the compiler are based solely on the declared type of the reference, regardless of the object type. So looking at the four reference types again—Object, GameShape, PlayerPiece, and Animatable— which of these four types know about the displayShape() method?

You guessed it—both the GameShape class and the PlayerPiece class are known (by the compiler) to have a displayShape() method, so either of those reference types can be used to invoke displayShape(). Remember that to the compiler, a PlayerPiece IS-A GameShape, so the compiler says, "I see that the declared type is PlayerPiece, and since PlayerPiece extends GameShape, that means
PlayerPiece inherited the displayShape() method. Therefore, PlayerPiece can be used to invoke the displayShape() method."

Which methods can be invoked when the PlayerPiece object is being referred to using a reference declared as type Animatable? Only the animate() method. Of course the cool thing here is that any class from any inheritance tree can also implement Animatable, so that means if you have a method with an argument declared as type Animatable, you can pass in PlayerPiece objects, SpinningLogo
objects, and anything else that's an instance of a class that implements Animatable. And you can use that parameter (of type Animatable) to invoke the animate() method, but not the displayShape() method (which it might not even have), or anything other than what is known to the compiler based on the reference type. The compiler always knows, though, that you can invoke the methods of class Object on any object, so those are safe to call regardless of the reference—class or interface used to refer to the object.

We've left out one big part of all this, which is that even though the compiler only knows about the declared reference type, the Java Virtual Machine (JVM) at runtime knows what the object really is. And that means that even if the PlayerPiece object's displayShape() method is called using a GameShape reference variable, if the PlayerPiece overrides the displayShape() method, the JVM will invoke the PlayerPiece version! The JVM looks at the real object at the other end of the reference, "sees" that it has overridden the method of the declared reference variable type, and invokes the method of the object's actual class. But one other thing to keep in mind:

Polymorphic method invocations apply only to instance methods. You can always refer to an object with a more general reference variable type (a superclass or interface), but at runtime, the ONLY things that are dynamically selected based on the actual object (rather than the reference type) are instance methods. Not static methods. Not variables. Only overridden instance methods are dynamically invoked based on the real object's type.