Showing posts with label inheritance. Show all posts
Showing posts with label inheritance. Show all posts

Wednesday, January 26, 2011

Quick Recap: Chapters 6 – 14

Chapter 6: Encapsulation

• Encapsulation hides implementation details behind an Interface or an API
• Encapsulated code has two features:
     o Instance variables are hidden (Usually with private modifier)
     o Getter and Setter methods are provided to give access to instance variables

Chapter 7: Inheritance

• Inheritance allows a class to be a subclass of a superclass and thereby inherit code and functionality of the superclass
• All classes are subclasses of Object and therefore they inherit Objects methods
• IS-A relationship is expressed with the keyword extends
• HAS-A means an instance of one class “has a” reference to an instance of another class
• Single, Multilevel, Multiple (Partial of course) and Hybrid are the types of inheritance

Chapter 8: Polymorphism

• Polymorphism means many forms
• A reference variable is always of a single, unchangeable type, but it can refer to a subtype object
• A single object can be referred to by reference variables of many different types, as long as they are the same type or a supertype of the object
• The reference variables type (not the objects type), determines which methods are called
• Polymorphic method invocations apply only to overridden instance methods

Overriding & Overloading:

• Methods can be both overridden and overloaded
• Constructors can only be overloaded
• Abstract methods must be overridden by the first concrete class (non abstract class)
• Overridden methods:
     o Must have the same argument list
     o Must have the same return type or a covariant return
     o Must not have a more restrictive access modifier
     o Must not throw new or broader checked exceptions
     o May throw fewer or narrower checked exceptions or any unchecked exception
• Final methods cannot be overridden
• Only inherited methods may be overridden (private methods are not inherited)
• You can use super.OverriddenMethodName() to call the super class’s version of the method
• Overloading means reusing a method name
• Overloaded methods
     o Must have different arguments list
     o May have different return types (But you cannot overload a method by just changing the return type)
     o May have different access modifiers
     o May throw different exceptions
     o Overloading is not Polymorphism
• Reference type determines which overloaded method will be used at compile time (In case you have overloaded a method that is available in the parent class)

Chapter 9: Reference Variable Casting

• There are two types of reference variable casting: downcasting and upcasting
• Downcasting: If you have a reference variable that refers to a subtype object, you can assign it to a reference variable of the subtype. You must make an explicit cast to do this, and the result is that you can access the subtype’s members with this new reference variable.
• Upcasting: You can assign a reference variable to a supertype reference variable explicitly or implicitly. This is an inherently safe operation because the assignment restricts the access capabilities of the new variable.


Chapter 10: Implementing an Interface

• When you implement an Interface, you are fulfilling its contract
• If you implement an interface you must provide concrete overriding for all methods defined in the interface
• If you don’t provide implementation for all methods, you must mark your class Abstract
• A single class can implement many interfaces


Chapter 11: Return Types

• Overloaded methods can change return types
• Overridden methods cannot change return types (Except in case of covariant returns)
• Object reference return types can accept null as a return value
• An array is a perfectly legal return type, both to declare and to return as a value
• For methods with primitive return types, any value that can be implicitly converted to the return type can be returned
• Nothing can be returned from a method that has the void modifier
• You can use the return keyword to get out of a method early but you cannot return anything from a void method and you cannot use an empty return in a non-void method
• Methods with an object reference return type, can return a subtype
• Methods with an interface return type, can return any implementer

Chapter 12: Constructors and Instantiation

• A Constructor is always invoked when a new object of a class is created
• Each superclass in an objects inheritance tree will have a constructor called
• Every class (Even an abstract class) has atleast one constructor
• Even if you don’t write a constructor explicitly, the compiler will add a default no-arg constructor to your class
• If you write a constructor that takes arguments, the compiler will not place a no-arg constructor in your class
• Constructors must have the same name as the class (Case Sensitive)
• Constructors don’t have a return type (If you see a return type, then it’s a method and not a constructor)
• Constructors can use any access modifier including private
• The default constructor is always the no-arg constructor
• The first statement of every constructor must be a call to either this() or super()
• You cannot have both this() and super() in the same constructor
• Constructors are never inherited, so they cannot be overridden
• A constructor can be directly invoked only by another constructor
• You cannot call a constructor explicitly

Chapter 13: Statics

• Use static methods to implement behavior that will not be affected by the state of any instances
• Use static variables to hold data that is class specific. There will be only one copy of a static variable irrespective of how many instances you make of a class
• All static members of a class belong to the class and not any instance
• A static method cannot access instance variables
• Static methods cannot be overridden

Chapter 14: Coupling and Cohesion

• Coupling refers to the degree to which one class knows about another class
• Loose coupling is a desirable state of having classes that are well encapsulated, minimize references to one another
• Tight coupling is undesirable
• Cohesion refers to the degree in which a class has a single, well defined role or responsibility
• High cohesion is a desirable state and low cohesion is undesirable


Previous Chapter: Chapter 14: Coupling and Cohesion

Next Chapter: Self Test Chapters 6 to 14

Chapter 14: Coupling and Cohesion

You would have heard or learnt a lot about coupling and cohesion when you learnt object oriented concepts or while learning other programming languages like c++. Let me tell you up front that, this chapter is going to be from the SCJP exam perspective and is going to cover concepts related to these two topics only from the exam point of you and not the overall dig deep into the topics. Frankly speaking, you’ll have very few questions about coupling and cohesion on the real exam.

Lets get started.

These two topics, coupling and cohesion, have to do with the quality of an OO design. In general, good OO design calls for loose coupling and shuns tight coupling, and good OO design calls for high cohesion, and shuns low cohesion. As with most OO design discussions, the goals for an application are

• Ease of creation
• Ease of maintenance
• Ease of enhancement

Coupling

Coupling is the degree to which one class knows about another class. If the only knowledge that class A has about class B, is what class B has exposed through its interface, then class A and class B are said to be loosely coupled. If, on the other hand, class A relies on parts of class B that are not part of class B’s interface, then the coupling between the classes is tighter. In other words, if A knows more than it should about the way in which B was implemented, then A and B are tightly coupled.

Using this second scenario, imagine what happens when class B is enhanced. It’s quite possible that the developer enhancing class B has no knowledge of class A, (why would he/she?) Class B’s developer ought to feel that any enhancements that don’t break the class’s interface should be safe, so she might change some non-interface parts of the class, which then causes class A to break.

At the far end of the coupling spectrum is the horrible situation in which class A knows non-API stuff about class B, and class B knows non-API stuff about class A. (This is REALLY BAD CODING). If either class is ever changed, there’s a chance that the other class will break. Let’s look at an obvious example of tight coupling, which has been enabled by poor encapsulation:

class CalculateTaxes {
float rate;
float doIndia() {
TaxRatesInIndia str = new TaxRatesInIndia();
rate = str.salesRate; // ouch
// this should be a method call:
// rate = str.getSalesTaxRates("CO");
// do stuff with rate
}
}

class TaxRatesInIndia {
public float salesRate; // should be private
public float adjustedSalesRate; // should be private

public float getSalesTaxRates(String region) {
salesRate = new CalculateTaxes().doIndia(); // ouch again!
// do country-based calculations
return adjustedSalesRate;
}
}

All large OO applications are a mix of many classes and interfaces working together. Ideally, all interactions between objects in an OO system should use the APIs, in other words, the contracts, of the objects’ respective classes. Theoretically, if all of the classes in an application have well-designed APIs, then it should be possible for all interclass interactions to use those APIs exclusively. If you make changes to the way one class behaves, in a loosely coupled environment, you shouldn't be getting surprise errors in other classes. As we discussed earlier in this chapter, an aspect of good class and API design is that classes should be well encapsulated.

The point here is that coupling is a somewhat subjective concept. Because of this, the SCJP exam will test you on really obvious examples of tight coupling only. So don't worry much about having to make design decisions about code.

Cohesion

While coupling has to do with how classes interact with each other, cohesion is all about how a single class is designed. The term cohesion is used to indicate the degree to which a class has a single, well-focused purpose. Keep in mind that cohesion too is a subjective concept. The more focused a class is, the higher its cohesiveness. The key benefit of high cohesion is that such classes are typically much easier to maintain (and less frequently changed) than classes with low cohesion. Another benefit of high cohesion is that classes with a well-focused purpose tend to be more reusable than other classes. Let’s take a look at a pseudocode example:

class SalesReport {
void connectToDb(){ }
void generateSalesReport() { }
void saveAsFile() { }
void print() { }
}

Now imagine your manager comes along and says, “Hey you know that accounting application we’re working on? The clients just decided that they’re also going to want to generate a revenue projection report, oh and they want to do some inventory reporting also. They do like our reporting features however, so make sure that all of these reports will let them choose a database, choose a printer, and save generated reports to data files...”

Rather than putting all the printing code into one report class, we probably would have been better off with the following design right from the start:

class SalesReport {
Options getReportingOptions() { }
void generateSalesReport(Options o) { }
}

class ConnectToDb {
DBconnection getDb() { }
}

class PrintStuff {
PrintOptions getPrintOptions() { }
}

class FileSaver {
SaveOptions getFileSaveOptions() { }
}

This design is much more cohesive. Instead of one class that does everything, we’ve broken the system into four main classes, each with a very specific, or cohesive, role. Because we’ve built these specialized, reusable classes, it’ll be much easier to write a new report, since we’ve already got the database connection class, the printing class, and the file saver class, and that means they can be reused by other classes that might want to print a report. Again, as in Coupling, you may not get too many questions about cohesion but if you are (un)lucky you may get one or two…

Previous Chapter: Chapter 13: Statics

Next Chapter: Quick Review: Chapters 6 to 14

Thursday, January 6, 2011

Chapter 7: Object Oriented Concepts - Inheritance

Inheritance is one of the building blocks of Java and it is used extensively in all java based applications. Inheritance is everywhere in Java. I can’t think of one java project that I worked on, where inheritance wasn't used. In order to explore this topic we’re going to use the instanceof operator, which we’ll discuss in more detail in future. For now, just remember that instanceof returns true if the reference variable being tested is of the type being compared to. This code:

class InstanceTest {
public static void main(String [] args) {
InstanceTest t1 = new InstanceTest ();
InstanceTest t2 = new InstanceTest ();
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
t1's an Object

You are now probably thinking, where this equals method came from? Remember my standard statement? “Everything in Java is an Object”? Ah Yes, now you remember. Every class that you create invariably (and automatically) extends from java.lang.Object. And this Object class contains the equals method which automatically becomes available for all classes. Cool right? The creators of Java assumed (correctly of course) that all programmers would require some sort of functionality to check if two objects are equal and hence this method is placed in the Object class so that it becomes available to all java classes automatically.

The equals method checks if the two java objects under consideration are equal. By default this method checks for the object instance and since in this cast t1 and t2 are created out of two different new InstanceTest() invocations, they are not equal.

Tip: If you wanna argue you can say that since they are both just a new instance of the InstanceTest class, shouldn't they be equal? Yes, you are absolutely right. That is why java gives us the feature wherein you can override the equals() method inside your class and add the checks you want to place in order to decide if two objects are equal.

Now, the second if condition checks if t1 is an instance of Object (which it automatically is) it succeeds and prints the message on the console.
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 (You don't want your colleague sitting right next to you to write the same validation code in his class while he can obviously use the better code you have written :-) )
• To use polymorphism

Let’s begin with reuse.

A Class can re-use or in java terms inherit features/code of another class by just extending it.
Ex:

public class Child extends Parent {

}

In the above example by virtue of the extends keyword, all the public code inside the parent class is available for use inside the child class.

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 Car {
public void goForADrive() {
System.out.println("driving a car");
}
// more code
}

class Ferrari extends Car {
public void takeFerrariForADrive() {
System.out.println("driving a Ferrari");
}
// more code
}

public class TestCars {
public static void main (String[] args) {
Ferrari car = new Ferrari();
car.goForADrive();
car.takeFerrariForADrive();
}
}

Outputs:
driving a car
driving a Ferrari

Notice that the Ferrari class inherits the generic goForADrive() method from the less-specialized class Car, and also adds its own method, takeFerrariForADrive(). Code reuse through inheritance means that methods with generic functionality that could apply to a wide range of different kinds of cars —don’t have to be reimplemented. That means all specialized subclasses of Car are guaranteed to have the capabilities of the more generic superclass. You don’t want to have to rewrite the goForADrive() code in each of your specialized car classes of a racing game.
But you probably already 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 piece code exists. So it is logically and obviously easier to manage changes if all common code is available at one single place.

The second 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 CarLauncher class that wants to loop through a list of different kinds of Car objects, and invoke goForADrive() on each of them. At the time you write this class, you don’t know every possible kind of Car 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 new Car six months later.
The beautiful thing about polymorphism is that you can treat any subclass of Car as a Car. In other words, you can write code in your CarLauncher class that says, “I don’t care what kind of object you are as long as you inherit from (extend) Car. And as far as I’m concerned, if you extend Car then you’ve definitely got a goForADrive() method, so I know I can call it.”
Imagine we now have two specialized subclasses that extend the more generic Car class, Ferrari and Porsche:

class Car {
public void goForADrive() {
System.out.println("driving a car");
}
// more code
}

class Ferrari extends Car {
public void takeFerrariForADrive() {
System.out.println("driving a Ferrari");
}
// more code
}

class Porsche extends Car {
public void takePorscheForADrive() {
System.out.println("driving a Porsche");
}
// more code
}

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

public class TestCars {
public static void main (String[] args) {
Ferrari ferrari = new Ferrari();
Porsche porsche = new Porsche();
goForADrive(ferrari);
goForADrive(porsche);
}

public static void doDrive(Car car) {
car.goForADrive();
}
}

Outputs:
driving a car
driving a car

The key point is that the doDrive() method is declared with a Car argument but can be passed any subtype (in this example, a subclass) of Car. The method can then invoke any method of Car, without any concern for the actual runtime class type of the object passed to the method. There are implications, though. The doDrive() method knows only that the objects are a type of Car, since that’s how the parameter is declared. And using a reference variable declared as type Car—regardless of whether the variable is a method parameter, local variable, or instance variable—means that only the methods of Car 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 Car variable to call, say, the takePorscheForADrive() method even if the object passed in is of type Porsche.

IS-A and HAS-A Relationships

For the exam you need to be able to look at code and determine whether the code demonstrates an IS-A or HAS-A relationship. The rules are simple, so this should be one of the few areas where answering the questions correctly is easy.

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, Ferrari IS-A Car. Potato IS-A Vegetable. You express the IS-A relationship in Java through the keywords extends (for class inheritance) and implements (for interface implementation).

We will take the same car example as in the previous paragraph. A Car is a type of Automobile, so the inheritance tree might start from the Automobile class as follows:

public class Automobile { ... }
public class Car extends Automobile { ... }
public class Ferrari extends Car { ... }

In OO terms, you can say the following:

Automobile is the superclass of Car.
Car is the subclass of Automobile.
Car is the superclass of Ferrari.
Ferrari is the subclass of Automobile.
Car inherits from Automobile.
Ferrari inherits from both Automobile and Car.
Ferrari is derived from Car.
Car is derived from Automobile.
Ferrari is derived from Automobile.
Ferrari is a subtype of both Automobile and Car.
Returning to our IS-A relationship, the following statements are true:
“Car extends Automobile” means “Car IS-A Automobile.”
“Ferrari extends Car” means “Ferrari IS-A Car.”

And we can also say:

“Ferrari IS-A Automobile” because a class is said to be “a type of” anything further up in its inheritance tree. Figure 2-2 illustrates the inheritance tree for Automobile, Car, and Ferrari. 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 Ferrari IS-A Car. A Car HAS-A SteeringWheel.

The code might look like this:

public class Car { }
public class Ferrari extends Car {
private SteeringWheel mySteeringWheel;
}

In the preceding code, the Ferrari class has an instance variable of type SteeringWheel, so you can say that “Ferrari HAS-A SteeringWheel.” In other words, Ferrari has a reference to a SteeringWheel. Ferrari code can use that SteeringWheel reference to invoke methods on the SteeringWheel, and get SteeringWheel behavior without having SteeringWheel-related code (methods) in the Ferrari class itself.

Ferrari class has a SteeringWheel, because Ferrari declares an instance variable of type SteeringWheel. When code invokes turn() on a Ferrari instance, the Ferrari invokes turn() on the Ferrari object’s SteeringWheel instance variable.

HAS-A relationships allow you to design classes that follow good OO practices by not having monolithic classes that do a million different things. Classes (and their resulting objects) should be specialists. The more specialized the class, the more likely it is that you can reuse the class in other applications. If you put all the SteeringWheel-related code directly into the Ferrari class, you’ll end up duplicating code in the Porsche class, Subaru class, and any other class that might need SteeringWheel behavior. By keeping the SteeringWheel code in a separate, specialized SteeringWheel class, you have the chance to reuse the SteeringWheel class in multiple applications.

Users of the Ferrari class (that is, code that calls methods on a Ferrari instance), think that the Ferrari class has SteeringWheel behavior. The Ferrari class might have a turn(Full360) method, for example. Users of the Ferrari class should never have to know that when they invoke the turn() method, the Ferrari object turns around and delegates the call to its SteeringWheel class by invoking mySteeringWheel.turn(Full360). The scenario just described might look like this:

public class Ferrari extends Car {
private SteeringWheel mySteeringWheel = new SteeringWheel();
public void turn(Angle full360) {
mySteeringWheel.turn(full360);
}
}

public class SteeringWheel {
public void turn(Angle full360) {
// Do the actual turn 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 Ferrari class hides implementation details from Ferrari users. Ferrari users ask the Ferrari object to do things (in this case, turn a full 360 degrees), and the Ferrari will either do it or, as in this example, ask someone else to do it. To the caller, though, it always appears that the Ferrari object takes care of itself. Users of a Ferrari should not even need to know that there is such a thing as a SteeringWheel class. That is how a well designed OO system should work.

Types of Inheritance:
We shall wrap up this chapter by looking at the different types of inheritance that is available. They are:
1. Single Inheritance
A Scenario where one class is inheriting/extending the behavior of just one super class.

Ex: public class Ferrari extends Car {…}

2. Multilevel Inheritance

A Scenario where one class is inheriting/extending the bahavior of another class which in turn is inheriting behavior from yet another class.

Ex: public class Automobile {…}
Public class Car extends Automobile {…}
Public class Ferrari extends Car {…}

This multilevel inheritance actually has no limitations on the number of levels it can go. So as far as java goes, it is limitless. But for maintenance and ease of use sakes it is better to keep the inheritance levels to a single digit number.

3. Multiple Inheritance

Actually, java does not support multiple inheritance. You can achieve partial multiple inheritance using interfaces but java is not like C or C++ where you can do direct multiple inheritance. However, you can achieve partial multiple inheritance with the help of interfaces.

Ex: public class FerrariF12011 extends Ferrari implements Car, Automobile {…}

And this is under the assumption that Car and Automobile are interfaces.

Here if you see, though you don't inherit concrete code from the Car or the Automobile interface, you do inherit skeleton methods that determine the way your class eventually behaves and hence this can be considered partial Multiple Inheritance.

Tip: If you are curious asking me why doesn't java allow multiple inheritance, think about this scenario. Let us say the Automobile Class has a drive() method and the Car class has a drive() method and the Ferrari class has a drive() method too. Let us say you create a new class FerrariF12011 that looks like below:
Public class FerrariF12011 extends Ferrari, Car, Automobile {…}
And at some point of time you need to call the drive() method, what would happen? Your JVM wouldn't know which method to invoke and you may have to instantiate one of the classes that you already inherit in order to call its appropriate method. Sounds confusing right? To avoid this nonsense is why the creators of java did not include this direct multiple inheritance feature.

4. Hybrid Inheritance

This is the scenario wherein your java code exhibits traits of more than one of the inheritance types explained above. Going with the example above again:
Public class FerrariF12011 extends Ferrari implements Car, Automobile {…}
The above is a combination of both single and multiple inheritance.

Previous Chapter: Chapter 6: Object Oriented Concepts - Encapsulation

Next Chapter: Object Oriented Concepts - Polymorphism
© 2013 by www.inheritingjava.blogspot.com. All rights reserved. No part of this blog or its contents may be reproduced or transmitted in any form or by any means, electronic, mechanical, photocopying, recording, or otherwise, without prior written permission of the Author.

ShareThis

Google+ Followers

Followers