Friday, January 28, 2011

Chapter 15: Stack and Heap

You might be wondering, is Stack and Heap such a large topic that I have dedicated one full chapter to it? Actually it isnt such a big topic but it is extremely important to understand them fully and clearly in order to grasp the forthcoming topics clearly. And combining this with any other topic would make it a bit confusing or rather off-place. So it is given a separate topic status. (We will be touching about these as and when required in the forthcoming chapters and this chapter would just be a quick overview)

For the most part, the various pieces (methods, variables, and objects) of Java programs live in one of two places in memory: either the stack or the heap. For now, let us worry about only three types of things: instance variables, local variables, and objects:
• Instance variables and objects live on the heap.
• Local variables live on the stack.

Let’s take a look at a Java program, and how its various pieces are created and map into the stack and the heap:

1. class Maine { }
2.
3. class Lion {
4. Maine c; // instance variable
5. String name; // instance variable
6.
7. public static void main(String [] args) {
8.
9. Lion d; // local variable: d
10. d = new Lion();
11. d.go(d);
12. }
13. void go(Lion Lion) { // local variable: Lion
14. c = new Maine();
15. Lion.setName("Aiko");
16. }
17. void setName(String LionName) { // local var: LionName
18. name = LionName;
19. // do more stuff
20. }
21. }

This is how the variables and methods get placed in the stack and heap during execution of the above piece of code.

• Line 7—main() is placed on the stack.
• Line 9—reference variable d is created on the stack, but there’s no Lion object yet.
• Line 10—a new Lion object is created and is assigned to the d reference variable.
• Line 11—a copy of the reference variable d is passed to the go() method.
• Line 13—the go() method is placed on the stack, with the Lion parameter as a local variable.
• Line 14—a new Maine object is created on the heap, and assigned to Lion’s instance variable.
• Line 17—setName() is added to the stack, with the LionName parameter as its local variable.
• Line 18—the name instance variable now also refers to the String object.
• Notice that two different local variables refer to the same Lion object.
• Notice that one local variable and one instance variable both refer to the same String Aiko.
• After Line 19 completes, setName() completes and is removed from the stack. At this point the local variable LionName disappears too, although the String object it referred to is still on the heap.

Previous Chapter: Self Test - Chapters 6 to 14

Next Chapter: Chapter 16: Literals, Assignments and Variables

Self Test: Chapters 6 to 14

Question 1:
Given:
public abstract interface Cultivate { public void water(String s); }

Which is a correct class? (Choose all that apply.)
A. public abstract class Grow implements Cultivate {
public abstract void water(String s) { }
}
B. public abstract class Grow implements Cultivate { }
C. public class Grow extends Cultivate {
public void water(Integer i) { }
}
D. public class Grow implements Cultivate {
public void water(Integer i) { }
}
E. public class Grow implements Cultivate {
public void water(String i) { }
public void water(Integer s) { }
}

Question 2:
Given:
class Parent {
public Parent(String s) { System.out.print("B"); }
}
public class Child extends Parent {
public Child(String s) { System.out.print("D"); }
public static void main(String [] args) {
new Child("C");
System.out.println(" ");
}
}

What is the result?
A. BD
B. DB
C. BDC
D. DBC
E. Compilation fails

Question 3:
Given:
class Parent {
private final void flipper() { System.out.println("Parent"); }
}

public class Child extends Parent {
public final void flipper() { System.out.println("Child"); }
public static void main(String [] args) {
new Child().flipper();
}
}

What is the result?
A. Child
B. Parent
C. Parent
D. Child
E. Child
F. Parent
G. Compilation fails

Question :

Which statement(s) are true? (Choose all that apply.)
A. Cohesion is the OO principle most closely associated with hiding implementation details
B. Cohesion is the OO principle most closely associated with making sure that classes know about other classes only through their APIs
C. Cohesion is the OO principle most closely associated with making sure that a class is designed with a runle, well-focused purpose
D. Cohesion is the OO principle most closely associated with allowing a runle object to be seen as having many types

Question 5:

Given the following,
1. class X { void doX() { } }
2. class Y extends X { void doY() { } }
3.
4. class Chrome {
5. public static void main(String [] args) {
6. X x1 = new X();
7. X x2 = new Y();
8. Y y1 = new Y();
9. // insert code here
10. } }

Which, inserted at line 9, will compile? (Choose all that apply.)
A. x2.doY();
B. (Y)x2.doY();
C. ((Y)x2).doY();
D. None of the above statements will compile

Question 6:
Given:
1. Class1 has a Class4
2. Methods in Class1 use public methods in Class2
3. Methods in Class3 use public methods in Class1
4. Methods in Class1 use public variables in Class2
Which is most likely true? (Choose the most likely.)
A. Class4 has low cohesion
B. Class1 has weak encapsulation
C. Class2 has weak encapsulation
D. Class2 has strong encapsulation
E. Class3 is tightly coupled to Class1

Question 7:

Given:
3. class WildCat {
4. public void roar() { System.out.print("Grrrrrrrrr "); }
5. }
6. class Lion extends WildCat {
7. public void sniff() { System.out.print("sniff "); }
8. public void roar() { System.out.print("roarrrrrr "); }
9. }
10. public class WildCatShow {
11. public static void main(String[] args) { new WildCatShow().go(); }
12. void go() {
13. new Lion().roar();
14. ((WildCat) new Lion()).roar();
15. ((WildCat) new Lion()).sniff();
16. }
17. }

What is the result? (Choose all that apply.)
A. roarrrrrr roarrrrrr sniff
B. roarrrrrr Grrrrrrrrr sniff
C. roarrrrrr roarrrrrr followed by an exception
D. roarrrrrr Grrrrrrrrr followed by an exception
E. Compilation fails with an error at line 14
F. Compilation fails with an error at line 15

Question 8:

Given:
3. public class Ferrari extends Car {
4. public static void main(String[] args) {
5. new Ferrari().go();
6. }
7. void go() {
8. go2(new Car(), new Ferrari());
9. go2((Ferrari) new Car(), new Ferrari());
10. }
11. void go2(Car t1, Ferrari r1) {
12. Ferrari r2 = (Ferrari)t1;
13. Car t2 = (Car)r1;
14. }
15. }
16. class Car { }

What is the result? (Choose all that apply.)
A. An exception is thrown at runtime
B. The code compiles and runs with no output
C. Compilation fails with an error at line 8
D. Compilation fails with an error at line 9
E. Compilation fails with an error at line 12
F. Compilation fails with an error at line 13

Question 9:

Given:
3. public class Ferrari extends Car {
4. public static String run() { return "fa"; }
5. public static void main(String[] args) {
6. Ferrari t = new Ferrari();
7. Car s = new Ferrari();
8. System.out.println(t.run() + " " + s.run());
9. }
10. }
11. class Car { public static String run() { return "la"; } }

What is the result?
A. fa fa
B. fa la
C. la la
D. Compilation fails
E. An exception is thrown at runtime

Question 10:
Given:
3. class Manager {
4. static String s = " ";
5. protected Manager() { s += "Manager "; }
6. }
7. class SubManager extends Manager {
8. private SubManager() { s += "sub "; }
9. }
10. public class SubSubManager extends Manager {
11. private SubSubManager() { s += "subsub "; }
12. public static void main(String[] args) {
13. new SubSubManager();
14. System.out.println(s);
15. }
16. }

What is the result?
A. subsub
B. sub subsub
C. Manager subsub
D. Manager sub subsub
E. Compilation fails
F. An exception is thrown at runtime

Question 11:
Given:
3. class Apartments {
4. Apartments() { System.out.print("b "); }
5. Apartments(String name) {
6. this(); System.out.print("bn " + name);
7. }
8. }
9. public class Home extends Apartments {
10. Home() { System.out.print("h "); }
11. Home(String name) {
12. this(); System.out.print("hn " + name);
13. }
14. public static void main(String[] args) { new Home("x "); }
15. }

What is the result?
A. h hn x
B. hn x h
C. b h hn x
D. b hn x h
E. bn x h hn x
F. b bn x h hn x
G. bn x b h hn x
H. Compilation fails

Question 12:
Given:
3. class Animal {
4. String name = "Rocky ";
5. String makeNoise() { return "generic noise"; }
6. }
7. class Tiger extends Animal {
8. String name = "stripes ";
9. String makeNoise() { return "roarrrrrrrrrrr"; }
10. }
11. public class Zoo {
12. public static void main(String[] args) { new Zoo().go(); }
13. void go() {
14. Animal m = new Tiger();
15. System.out.println(m.name + m.makeNoise());
16. }
17. }

What is the result?
A. Rocky roarrrrrrrrrrr
B. stripes roarrrrrrrrrrr
C. Rocky generic noise
D. stripes generic noise
E. Compilation fails
F. An exception is thrown at runtime

Answers:

Q1. B is correct, an abstract class need not implement any or all of an interface’s methods. E is correct, the class implements the interface method and additionally overloads the water() method.
A is incorrect because abstract methods have no body. C is incorrect because classes implement interfaces they don’t extend them. D is incorrect because overloading a method is not implementing it.

Q2. E is correct. The implied super() call in Child’s constructor cannot be satisfied because there isn’t a no-arg constructor in Parent. A default, no-arg constructor is generated by the compiler only if the class has no constructor defined explicitly.
A, B, C, and D are incorrect based on the above.

Q3. A is correct. Although a final method cannot be overridden, in this case, the method is private, and therefore hidden. The effect is that a new, accessible, method flipper is created. Therefore, no polymorphism occurs in this example, the method invoked is simply that of the child class, and no error occurs.
B, C, D, and E are incorrect based on the preceding.

Q4. Answer C is correct.
A refers to encapsulation, B refers to coupling, and D refers to polymorphism

Q5. C is correct. Before you can invoke Y’s doY method you have to cast x2 to be of type Y. Statement B looks like a proper cast but without the second set of parentheses, the compiler thinks it’s an incomplete statement.
A, B and D are incorrect based on the preceding

Q6. C is correct. Generally speaking, public variables are a sign of weak encapsulation.
A, B, D, and E are incorrect, because based on the information given, none of these statements can be supported.

Q7. F is correct. Class WildCat doesn’t have a sniff method.
A, B, C, D, and E are incorrect based on the above information

Q8. A is correct, a Class3astException will be thrown when the code attempts to downcast a Car to a Ferrari.
B, C, D, E, and F are incorrect based on the above information.

Q9. B is correct. The code is correct, but polymorphism doesn’t apply to static methods.
A, C, D, and E are incorrect based on the above information.

Q10. C is correct. Watch out, SubSubManager extends Manager! Since the code doesn’t attempt to make a SubManager, the private constructor in SubManager is okay.
A, B, D, E, and F are incorrect based on the above information

Q11. C is correct. Remember that constructors call their superclass constructors, which execute first, and that constructors can be overloaded.
A, B, D, E, F, G, and H are incorrect based on the above information

Q12. A is correct. Polymorphism is only for instance methods.
B, C, D, E, and F are incorrect based on the above information

Previous Chapter: Quick Recap Chapters 6 to 14

Next Chapter: Chapter 15: Stack and Heap

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

Tuesday, January 25, 2011

Chapter 13: Statics

Static is one of the most important and powerful keywords in the java programming language. It can alter the behavior of variables and methods. The purpose of this chapter is to take a detailed look at this feature.

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-runs-the-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 Car {
static int CarCount = 0; // Declare and initialize
// static variable
public Car() {
CarCount += 1; // Modify the value in the constructor
}
public static void main (String [] args) {
new Car();
new Car();
new Car();
System.out.println("Car count is now " + CarCount);
}
}

In the preceding code, the static CarCount variable is set to zero when the Car class is first loaded by the JVM, before any Car 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 Car instance is created, the Car constructor runs and increments the static CarCount variable. When this code executes, three Car instances are created in main(), and the result is

Car count is now 3

Now imagine what would happen if CarCount were an instance variable (in other words, nonstatic):
class Car {
int CarCount = 0; // Declare and initialize
// instance variable
public Car() {
CarCount += 1; // Modify the value in the constructor
}
public static void main (String [] args) {
new Car();
new Car();
new Car();
System.out.println("Car count is now " + CarCount);
}
}

When this code executes, it should still create three Car instances in main(), but the result is...a compiler error! We can’t get this code to compile, let alone run.
Car.java:11: nonstatic variable CarCount cannot be referenced

from a static context
System.out.println("Car count is " + CarCount);
^
1 error

The JVM doesn’t know which Car object’s CarCount 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.

Exam Tip:
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 Bad {
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 Bad 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 Bad {
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 Car {
int CarSize = 0;
public int getCarSize() {
return CarSize;
}
public Car(int s) {
CarSize = s;
}
public static void main (String [] args) {
Car f = new Car(25);
System.out.println(f.getCarSize()); // Access instance
// method using f
}
}

In the preceding code, we instantiate a Car, assign it to the reference variable f, and then use that f reference to invoke a method on the Car instance we just created. In other words, the getCarSize() method is being invoked on a specific Car 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 Car {
static int CarCount = 0; // Declare and initialize
// static variable
public Car() {
CarCount += 1; // Modify the value in the constructor
}
}

class TestCar {
public static void main (String [] args) {
new Car();
new Car();
new Car();
System.out.print("CarCount:"+Car.CarCount); //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:
Car f = new Car();
int Cars = f.CarCount; // Access static variable
// CarCount using f

In the preceding code, we instantiate a Car, assign the new Car 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 Car 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 Car example, the compiler knows that the reference variable f is of type Car, and so the Car class static method is run with no awareness or concern for the Car instance at the other end of the f reference. In other words, the compiler cares only that reference variable f is declared as type Car.

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 isn’t the same thing. Let’s take a look at an example of a redefined (remember, not overridden), static method:

class Car {
static void drive() {
System.out.print("a ");
}
}
class Ferrari extends Car {
static void drive() { // it's a redefinition & not an override
System.out.print("d ");
}
public static void main(String [] args) {
Car [] a = {new Car(), new Ferrari(), new Car()};
for(int x = 0; x < a.length; x++) a[x].drive(); // invoke the static method } } Running this code produces the output: a a a Remember, the syntax a[x].drive() is just a shortcut (the syntax trick)...the compiler is going to substitute something like Car.drive() instead. This happens because the Array is of type Car and so the static method inside the Car class is used even though there is an instance of Ferrari in the list. Previous Chapter: Chapter 12 - Constructors and Instantiation

Next Chapter: Chapter 13 - Coupling & Cohesion

Chapter 12: Constructors and Instantiation

Objects are constructed. You can’t make a new object without invoking a constructor. In fact, you can’t make a new object without invoking not just the constructor of the object’s actual class type, but also the constructor of each of its superclasses including the Object class itself! Constructors are the code that runs whenever you use the keyword new. To be a bit more accurate, there can also be initialization blocks that run when you say new (init blocks), but we’re going to cover them, and their static initialization counterparts, in the next chapter.
We already have a lot to discuss here. So let’s get started.

Constructor Basics

Every class, including abstract classes, MUST have a constructor. Hard Code that into your brain. But just because a class must have one, doesn’t mean the programmer has to type it. A constructor looks like this:

class Car {
Car() { } // The constructor for the Car class
}

You notice anything missing in the declaration above? There’s no return type! Two key points to remember about constructors are that they have no return type and their names must exactly match the class name. Typically, constructors are used to initialize instance variable state, as follows:

class Car {
int size;
String name;
Car(String name, int size) {
this.name = name;
this.size = size;
}
}

In the preceding code example, the Car class does not have a no-arg constructor. That means the following will fail to compile:
Car f = new Car(); // Won't compile, no matching constructor

but the following will compile:

Car f = new Car("Ford", 43); // No problem. Arguments match
// the Car constructor.

So it’s very common for a class to have a no-arg constructor, regardless of how many other overloaded constructors are in the class (constructors can be overloaded just like methods). You can’t always make that work for your classes; occasionally you have a class where it makes no sense to create an instance without supplying information to the constructor. A java.awt.Color object, for example, can’t be created by calling a no-arg constructor, because that would be like saying to the JVM, “Make me a new Color object, and I really don’t care what color it is....” Do you seriously want the JVM making your color choices?

Constructor Chaining

We know that constructors are invoked at runtime when you say new on some class type as follows:
Lamborghini h = new Lamborghini();

But what really happens when you say new Lamborghini() ? (Assume Lamborghini extends Car and Car extends Object.)

1. Lamborghini constructor is invoked. Every constructor invokes the constructor of its superclass with an (implicit) call to super(),
2. Car constructor is invoked (Car is the superclass of Lamborghini).
3. Object constructor is invoked (Object is the ultimate superclass of all classes, so class Car extends Object even though you don’t actually type “extends Object” into the Car class declaration. It’s implicit.) At this point we’re on the top of the hierarchy.
4. Object instance variables are given their explicit values. By explicit values, we mean values that are assigned at the time the variables are declared, like “int x = 27”, where “27” is the explicit value (as opposed to the default value) of the instance variable.
5. Object constructor completes.
6. Car instance variables are given their explicit values (if any).
7. Car constructor completes.
8. Lamborghini instance variables are given their explicit values (if any).
9. Lamborghini constructor completes.

Rules for Constructors

The following list summarizes the rules you’ll need to know about Constructors. There are very important and you MUST remember these to answer the questions related to Constructors in the SCJP Exam.

• Constructors can use any access modifier, including private. (We will deal with private constructors in one of the later chapters)
• The constructor name must match the name of the class. (100% Case Sensitive)
• Constructors must not have a return type.
• It’s legal (but probably stupid) to have a method with the same name as the class, but that doesn’t make it a constructor. If you see a return type, it’s a method and not a constructor. In fact, you could have both a method and a constructor with the same name—the name of the class—in the same class, and that’s not a problem for Java. Be careful not to mistake a method for a constructor—be sure to look for a return type.
• If you don’t type a constructor into your class code, a default constructor will be automatically generated by the compiler.
• The default constructor is ALWAYS a no-arg constructor. (Obviously the compiler has no clue what all arguments you might want for your class. So it takes the safe way out with a no argument constructor)
• If you want a no-arg constructor and you’ve typed any other constructor(s) into your class code, the compiler won’t provide the no-arg constructor (or any other constructor) for you. In other words, if you’ve typed in a constructor with arguments, you won’t have a no-arg constructor unless you type it in yourself!
• Every constructor has, as its first statement, either a call to an overloaded constructor “this()” or a call to the superclass constructor “super()”. (You cant do both in the same constructor)
• If you do type in a constructor, and you do not type in the call to super() or a call to this(), the compiler will insert a no-arg call to super() for you, as the very first statement in the constructor.
• A call to super() can be either a no-arg call or can include arguments passed to the super constructor. (The compiler will not insert the super with arguments call by itself. You have to do it manually)
• A no-arg constructor is not necessarily the default (i.e., compiler-supplied) constructor, although the default constructor is always a no-arg constructor. The default constructor is the one the compiler provides! While the default constructor is always a no-arg constructor, you’re free to put in your own no-arg constructor.
• You cannot make a call to an instance method, or access an instance variable, until after the super constructor runs.
• Only static variables and methods can be accessed as part of the call to super() or this(). (Example: super(Car.NAME) is OK, because NAME is declared as a static variable.)
• Abstract classes have constructors, and those constructors are always called when a concrete subclass is instantiated.
• Interfaces do not have constructors. Interfaces are not part of an object’s inheritance tree.
• The only way a constructor can be invoked is from within another constructor. In other words, you can’t write code that actually calls a constructor explicitly as follows:

class Lamborghini {
Lamborghini() { } // constructor
void doStuff() {
Lamborghini(); // calling the constructor - illegal!
}
}

Determine Whether a Default Constructor Will Be Created

The following example shows a Lamborghini class with two constructors:
class Lamborghini {
Lamborghini() { }
Lamborghini(String name) { }
}

Will the compiler put in a default constructor for the class above? “No!” What about for the following variation of the class?
class Lamborghini {
Lamborghini(String name) { }
}

Now will the compiler insert a default constructor? “No Again!” What about this class?
class Lamborghini { }

Now we’re talking. The compiler will generate a default constructor for the preceding class, because the class doesn’t have any constructors defined. OK, what about this one below?
class Lamborghini {
void Lamborghini() { }
}

You might be tempted to say that, the compiler won’t create one, since there already is a constructor in the Lamborghini class? Take another look at the Lamborghini class.
What’s wrong with the Lamborghini() constructor? It isn’t a constructor at all! It’s simply a method that happens to have the same name as the class. Remember, the return type is a dead straight way to tell us that we’re looking at a method, and not a constructor. So, here again the compiler will put the default no-arg constructor in the class.

Some Questions:

Q: How do you know for sure whether a default constructor will be created?
A: Because you didn’t write any constructors in your class.

Q: How do you know what the default constructor will look like?
A: Because...
• The default constructor has the same access modifier as the class.
• The default constructor has no arguments.
• The default constructor includes a no-arg call to the super constructor (super()).

What happens if the super constructor has arguments?

Constructors can have arguments just as methods can, and if you try to invoke a method that takes, say, an int, but you don’t pass anything to the method, the compiler will complain.
So if your super constructor (that is, the constructor of your immediate superclass/parent) has arguments, you must type in the call to super(), supplying the appropriate arguments. Crucial point: if your superclass does not have a no-arg constructor, you must type a constructor in your class (the subclass) because you need a place to put in the call to super with the appropriate arguments.
The following is an example of the problem:
class Car {
Car(String name) { }
}

class Lamborghini extends Car {
Lamborghini() {
super(); // Problem!
}
}

And once again the compiler treats us with the stunningly lucid:
Lamborghini.java:7: cannot resolve symbol
symbol : constructor Car ()
location: class Car
super(); // Problem!
^

If you’re lucky (and it’s a full moon), your compiler might be a little more explicit. But again, the problem is that there just isn’t a match for what we’re trying to invoke with super()—an Car constructor with no arguments.
Another way to put this is that if your superclass does not have a no-arg constructor, then in your subclass you will not be able to use the default constructor supplied by the compiler. It’s that simple. Because the compiler can only put in a call to a no-arg super(), you won’t even be able to compile something like this:

class Dress {
Dress(String s) { }
}
class Skirt extends Dress { }

Trying to compile this code gives us exactly the same error we got when we put a constructor in the subclass with a call to the no-arg version of super():

Dress.java:4: cannot resolve symbol
symbol : constructor Dress ()
location: class Dress
class Skirt extends Dress { }
^

In fact, the preceding Dress and Skirt code is implicitly the same as the following code, where we’ve supplied a constructor for Skirt that’s identical to the default constructor supplied by the compiler:

class Dress {
Dress(String s) { }
}
class Skirt extends Dress {
// Constructor identical to compiler-supplied
// default constructor
Skirt() {
super(); // Won't work!
} // Invokes a no-arg Dress() constructor,
} // but there isn't one!

One last point on the whole default constructor thing, constructors are never inherited. They aren’t methods. They can’t be overridden (because they aren’t methods and only instance methods can be overridden). So the type of constructor(s) your superclass has in no way determines the type of default constructor you’ll get. Some folks mistakenly believe that the default constructor somehow matches the super constructor, either by the arguments the default constructor will have (remember, the default constructor is always a no-arg), or by the arguments used in the compiler-supplied call to super().

So, although constructors can’t be overridden, you’ve already seen that they can be overloaded, and typically are.

Overloaded Constructors

Overloading a constructor means typing in multiple versions of the constructor, each having a different argument list, like the following examples:

class Car {
Car() { }
Car(String s) { }
}

The preceding Car class has two overloaded constructors, one that takes a string, and one with no arguments. Because there’s no code in the no-arg version, it’s actually identical to the default constructor the compiler supplies, but remember—since there’s already a constructor in this class (the one that takes a string), the compiler won’t supply a default constructor. If you want a no-arg constructor to overload the with-args version you already have, you’re going to have to type it yourself, just as in the Car example.

Overloading a constructor is typically used to provide alternate ways for clients to instantiate objects of your class. For example, if a client knows the Car name, they can pass that to a Car constructor that takes a string. But if they don’t know the name, the client can call the no-arg constructor and that constructor can supply a default name. Here’s what it looks like:

1. public class Car {
2. String name;
3. Car(String name) {
4. this.name = name;
5. }
6.
7. Car() {
8. this(makeRandomName());
9. }
10.
11. static String makeRandomName() {
12. int x = (int) (Math.random() * 5);
13. String name = new String[] {"Ferrari", "Lamborghini",
"Rover", "Spyker",
"Lotus"}[x];
14. return name;
15. }
16.
17. public static void main (String [] args) {
18. Car a = new Car();
19. System.out.println(a.name);
20. Car b = new Car("Proton");
21. System.out.println(b.name);
22. }
23. }

Running the code four times produces this output:

% java Car
Lotus
Proton

% java Car
Ferrari
Proton

% java Car
Rover
Proton

% java Car
Ferrari
Proton

There’s a lot going on in the preceding code. Figure 2-7 shows the call stack for constructor invocations when a constructor is overloaded. Take a look at the call stack, and then let’s walk through the code straight from the top.

• Line 2 Declare a String instance variable name.
• Lines 3–5 Constructor that takes a String, and assigns it to instance variable name.
• Line 7. Assume every Car needs a name, but the client (calling code) might not always know what the name should be, so you’ll assign a random name. The no-arg constructor generates a name by invoking the makeRandomName() method.
• Line 8 The no-arg constructor invokes its own overloaded constructor that takes a String, in effect calling it the same way it would be called if client code were doing a new to instantiate an object, passing it a String for the name. The overloaded invocation uses the keyword this, but uses it as though it were a method name, this(). So line 8 is simply calling the constructor on line 3, passing it a randomly selected String rather than a client-code chosen name.
• Line 11 Notice that the makeRandomName() method is marked static! That’s because you cannot invoke an instance (in other words, nonstatic) method (or access an instance variable) until after the super constructor has run. And since the super constructor will be invoked from the constructor on line 3, rather than from the one on line 7, line 8 can use only a static method to generate the name. If we wanted all Cars not specifically named by the caller to have the same default name, say, “Ford,” then line 8 could have read this("Ford"); rather than calling a method that returns a string with the randomly chosen name.
• Line 12 This doesn’t have anything to do with constructors, but since we’re all here to learn...it generates a random integer between 0 and 4.
• Line 13 We’re creating a new String object (just a single String instance), but we want the string to be selected randomly from a list. Except we don’t have the list, so we need to make it. So in that one line of code we

1. Declare a String variable, name.
2. Create a String array (anonymously—we don’t assign the array itself to anything).
3. Retrieve the string at index [x] (x being the random number generated on line 12) of the newly created String array.
4. Assign the string retrieved from the array to the declared instance variable name. We could have made it much easier to read if we’d just written
5. String[] nameList = {"Ferrari", "Lamborghini", "Rover", "Spyker","Lotus"};
6. String name = nameList[x];
• Line 18 We’re invoking the no-arg version of the constructor (causing a random name from the list to be passed to the other constructor).
• Line 20 We’re invoking the overloaded constructor that takes a string representing the name.

The key point to get from this code example is in line 8. Rather than calling super(), we’re calling this(), and this() always means a call to another constructor in the same class. OK, fine, but what happens after the call to this()? Sooner or later the super() constructor gets called, right? Yes indeed. A call to this() just means you’re delaying the inevitable. Some constructor, somewhere, must make the call to super().

Key Rule: The first line in a constructor must be a call to super() or a call to this().
No exceptions. If you have neither of those calls in your constructor, the compiler will insert the no-arg call to super(). In other words, if constructor A() has a call to this(), the compiler knows that constructor A() will not be the one to invoke super().

The preceding rule means a constructor can never have both a call to super() and a call to this(). Because each of those calls must be the first statement in a constructor, you can’t legally use both in the same constructor. That also means the compiler will not put a call to super() in any constructor that has a call to this().

Thought question: What do you think will happen if you try to compile the following code?
class A {
A() {
this("Car");
}
A(String s) {
this();
}
}

Your compiler may not actually catch the problem (it varies depending on your compiler, but most won’t catch the problem). It assumes you know what you’re doing. Can you spot the flaw? Given that a super constructor must always be called, where would the call to super() go? Remember, the compiler won’t put in a default constructor if you’ve already got one or more constructors in your class. And when the compiler doesn’t put in a default constructor, it still inserts a call to super() in any constructor that doesn’t explicitly have a call to the super constructor—unless, that is, the constructor already has a call to this(). So in the preceding code, where can super() go? The only two constructors in the class both have calls to this(), and in fact you’ll get exactly what you’d get if you typed the following method code:

public void go() {
doStuff();
}

public void doStuff() {
go();
}

Now can you see the problem? Of course you can. The stack explodes! Two overloaded constructors both calling this() are two constructors calling each other. Over and over and over, resulting in

% java A
Exception in thread "main" java.lang.StackOverflowError

The benefit of having overloaded constructors is that you offer flexible ways to instantiate objects from your class. The benefit of having one constructor invoke another overloaded constructor is to avoid code duplication. In the Car example, there wasn’t any code other than setting the name, but imagine if after line 4 there was still more work to be done in the constructor. By putting all the other constructor work in just one constructor, and then having the other constructors invoke it, you don’t have to write and maintain multiple versions of that other important constructor code. Basically, each of the other not-the-real-one overloaded constructors will call another overloaded constructor, passing it whatever data it needs (data the client code didn’t supply).

Constructors and instantiation become even more exciting (just when you thought this chapter is going to end), when you get to inner classes, but I know you can stand to have only so much fun in one chapter, so I am holding the rest of the discussion on instantiating inner classes until a later point in time (A Future Chapter)

Previous Chapter: Chapter 11 - Legal Return Types

Next Chapter: Chapter 13 - Statics

Chapter 11: Legal Return Types

In the previous chapters we have seen many methods and classes. Every method in java has a return type which specifies the kind of data that would be returned by the current method. It is mandatory for all java methods to return something and if it is not going to return anything, we have to mark the method with a “void” return type to let the JVM know that it must not expect anything from the method. The purpose of this article is to take a look at what you can declare as a return type and as values. We will also cover a few other nuances of returning data with respect to other scenarios that we had covered in the previous chapters.

Return Type Declarations

This section looks at what you’re allowed to declare as a return type, which depends primarily on whether you are overriding, overloading, or declaring a new method.

Return Types on Overloaded Methods

Remember that method overloading is nothing more than name reuse. The overloaded method is a completely different method from any other method of the same name in the current class. So if you inherit a method but overload it in a subclass, you’re not subject to the restrictions of overriding. This essentially means that you can declare any return type you want. What you can’t do is change only the return type. To overload a method, remember, you must change the arDriveent list. The following code shows an overloaded method:

public class Car{
void go() { }
}

public class Ferrari extends Car {
String go(int x) {
return null;
}
}

Notice that the Ferrari version of the method uses a different return type. That’s perfectly fine. As long as you’ve changed the arDriveent list, you’re overloading the method, so the return type doesn’t have to match that of the superclass version. What you’re NOT allowed to do is this:

public class Car{
void go() { }
}
public class Ferrari extends Car {
String go() { //Illegal! Can't change only the return type
return null;
}
}

Overriding and Return Types, and Covariant Returns

When a subclass wants to change the implementation of an inherited method (override), the subclass must define a method that matches the inherited version exactly. Or, as of Java 5, you’re allowed to change the return type in the overriding method as long as the new return type is a subtype of the declared return type of the super-class method. (This is called Co-variant Returns)

Let’s look at a covariant return in action:

class Car {
Car drive(char c) {
return new Car();
}
}

class Lamborghini extends Car {
Lamborghini drive(char c) { // legal override as of Java 1.5
return new Lamborghini();
}
}

As of Java 5, this code will compile. If you were to attempt to compile this code with a 1.4 compiler or with the source flag as follows:
javac -source 1.4 Lamborghini.java

You would get a compiler error something that would look simething like this:
attempting to use incompatible return type

There are many other rules that apply to overriding, including those for access modifiers and declared exceptions, but those rules aren’t relevant to the return type discussion and we have already seen them in the chapter where we discussed about Overriding.
For the exam, be sure to remember that overloaded methods can change the return type, but overriding methods can do so only within the bounds of covariant returns.

Returning a Value

There are 6 golden rules for returning values from a method. Be sure to remember these clearly:
1. You can return NULL in a method that has an Object as return type
public Button drive() {
return null;
}

2. An Array is a perfectly legal return type
public String[] go() {
return new String[] {"Anand", "Rocky", "Austin"};
}

3. In a method with a primitive return type, you can return any value or variable that can be implicitly converted to the declared return type.
public int Car() {
char c = 'c';
return c; // char is compatible with int
}

4. In a method with a primitive return type, you can return any value or variable that can be explicitly cast to the declared return type.
public int Car () {
float f = 32.5f;
return (int) f;
}

5. You must not return anything from a method with a void return type.
public void Ferrari() {
return "this is it"; // You cant do this. Code wont compile
}

6. In a method with an object reference return type, you can return any object type that can be implicitly cast to the declared return type.
public Car getCar() {
return new BMW(); // Assume BMW extends Car
}

public Object getObject() {
int[] nums = {1,2,3};
return nums; // Return an int array,
// which is still an object
}

public interface Drivable { }
public class Drive implements Drivable { }

public class TestDrivable {
// Method with an interface return type
public Drivable getDrivable() {
return new Drive(); // Return interface implementer
}
}

Exam Tip:
Watch for methods that declare an abstract class or interface return type, and know that any object that passes the IS-A test (in other words, would test true using the instanceof operator) can be returned from that method—for example:
public abstract class Car { }
public class Lexus extends Car { }
public class Test {
public Car go() {
return new Lexus(); // OK, Lexus "is-a" Car
}
}
This code will compile, the return value is a subtype.


Previous Chapter: Chapter 10 - Implementing an Interface

Next Chapter: Chapter 12 - Constructors and Instantiation

Saturday, January 8, 2011

Chapter 10: Implementing an Interface

We have been using references to the term “Implementing an Interface” throughout the preceding chapters and we havent yet actually dug deep into this topic. As you might remember, an Interface is nothing but a contract as to how a class should behave. It just declares the behavior as empty methods and the implementing class actually writes the code that will determine the behavior.

When you implement an interface, you’re agreeing to adhere to the contract defined in the interface. That means you’re agreeing to provide legal implementations for every method defined in the interface, and that anyone who knows what the interface methods look like can rest assured that they can invoke those methods on an instance of your implementing class. (Thy need not bother much about how you have implemented it. All they bother about is whether a method of the name mentioned in the interface is available or not)

Now, you might stop me and ask, what if I implement an interface and opt not to write code for a method that I am supposed to? The answer is simple. The compiler wouldn't let you do that. You cannot successfully implement an interface without providing method implementation for all the methods declared inside the interface. This is how the java system ensures that when someone knows a certain method name in an interface and has an instance of a class that implements it, can actually call that method without fear that the method isnt implemented inside the class.
Assuming an interface, Convertible, with two methods: openHood(), and setOpenHoodFactor(), the following class will compile:

public class Ball implements Convertible { // Keyword 'implements'
public void openHood() { }
public void setOpenHoodFactor(int bf) { }
}

Ok, I know what you are thinking now. “This has got to be the worst implementation class that you have seen”. Though it compiles and runs as well, it is actually doing nothing… the interface contract guarantees that the class implementing it will have a method of a particular name but it never guaranteed a good implementation. In other words, the compiler does not bother whether you have code inside your method or not. All it cares is if you have methods of the matching names as in the interface. That's all…

Implementation classes must adhere to the same rules for method implementation as a class extending an abstract class. In order to be a legal implementation class, a nonabstract implementation class must do the following:
• Provide concrete (nonabstract) implementations for all methods from the declared interface.
• Follow all the rules for legal overrides.
• Declare no checked exceptions on implementation methods other than those declared by the interface method, or subclasses of those declared by the interface method.
• Maintain the signature of the interface method, and maintain the same return type (or a subtype).
• It does not have to declare the exceptions declared in the interface method declaration.

Tip: What if an implementing class does not want to provide implementation for all methods? Can we make that class compile? Of course yes, just make the class abstract. This means that the compiler wont check if all the methods are implemented.
Ex:
abstract class SuperCar implements Convertible { }

Notice anything missing? We never provided the implementation methods. And that’s OK. If the implementation class is abstract, it can simply pass the buck to its first concrete subclass.
You can have a class like:
Public class SuperSuperCar extends SuperCar {
public void openHood() {
System.out.println(“Opening the Hood”);
}
public void setOpenHoodFactor(int bf) {
System.out.println(“Opening the hood at speed: “ + bf);
}
}
This class SuperSuperCar is the first concrete (or non-abstract) class that extends the SuperCar class and actually provides the implementation for the methods in the interface Convertible that the SuperCar class implements.

Exam Tip: You may have questions wherein a class implements an interface but does not provide all the method implementations (check for method signatures too) Unless the implementing class is abstract, the implementing class must provide implementations for all the methods defined in the interface. You should be careful to spot such instances and answer them appropriately.

There are two more rules you need to know before we can wrap up this chapter:
1. A class can implement more than one interface. It’s perfectly legal to say, for example, the following:
public class Car implements Convertible, Serializable, Runnable
{ ... }

You can extend only one class, but implement many interfaces. But remember that subclassing defines who and what you are, whereas implementing defines a role you can play or a hat you can wear, despite how different you might be from some other class implementing the same interface (but from a different inheritance tree).

2. An interface can itself extend another interface, but never implement anything. The following code is perfectly legal:

public interface Convertible extends Moveable { } // ok!

What does that mean? The first concrete (nonabstract) implementation class of Convertible must implement all the methods of Convertible, plus all the methods of Moveable! The subinterface, as we call it, simply adds more requirements to the contract of the superinterface. You’ll see this concept applied in many areas of Java, especially J2EE where you’ll often have to build your own interface that extends one of the J2EE interfaces.

i.e., public class A extends B, C {…} is illegal whereas
public Interface A extends B, C {…} is perfectly legal

Exam Tip: Watch out for legal/illegal usage of extends and implements. There might be quite a few questions on this.
1. class Car {} - No Problems
2. class Ferrari Implements Car {} – Not Ok. Car is a class not an Interface
3. interface Convertible {} – No problems
4. interface Moveable {} – No problems
5. interface CarTop implements Convertible {} – Not Ok. An Interface cannot implement another interface
6. interface CarTop implements Car {} – Not Ok. An Interface cannot implement a class
7. interface CarTop extends Car {} – Not Ok. An Interface cannot extend a class
8. interface CarTop extends Convertible {} - No Problems. An Interface can extend another Interface
9. class Ferrari extends Car, Automobile – Not Ok. A Class cannot extend multiple classes
10. class Ferrari implements Convertible, Moveable {} – No Problems. A Class can implement multiple interfaces
11. class Ferrari extends Car implements Convertible {} – No Problems. A Class can both extend a class and implement an interface
12. class Ferrari implements Convertible extends Car {} - Not Ok. The extends should come first.

Burn these in, and watch for incorrect usage in the questions you get on the exam. Regardless of what the question appears to be testing, the real problem might be the class or interface declaration. Before you get caught up in, lets say, tracing a complex threading flow, check to see if the code will even compile first. (You’ll be really impressed by the effort the exam developers put into distracting you from the real problem.) You take the bait, you choose a wrong answer that would look perfectly legitimate while the code won’t compile in the first place.

Previous Chapter: Chapter 9: Reference Variable Casting

Next Chapter: Chapter 11 - Legal Return Types

Chapter 9: Reference Variable Casting

In the previous chapter we took a detailed look at polymorphism, overloading and overriding. While going through contents about Inheritance & overloading you would have seen that objects of one type were being considered or used as another. Java has a feature called Casting, wherein an object of one type can be cast into an object of another type (As long as its valid)

For example, this line of code should be second nature by now:

Car Car = new Ferrari();

But what happens when you want to use that Car reference variable to invoke a method that only class Ferrari has? You know it’s referring to a Ferrari, and you want to do a Ferrari-specific thing? In the following code, we’ve got an array of Cars, and whenever we find a Ferrari in the array, we want to do a special Ferrari thing. Let’s agree for now that all of this code is OK, except that we’re not sure about the line of code that invokes the brake method.

class Car {
void drive() {System.out.println("generic noise"); }
}
class Ferrari extends Car {
void drive() {System.out.println("drive"); }
void brake() { System.out.println("brake hard"); }
}

class CastTest2 {
public static void main(String [] args) {
Car [] a = {new Car(), new Ferrari(), new Car() };
for(Car Car : a) {
Car.drive();
if(Car instanceof Ferrari) {
Car.brake(); // try to do a Ferrari behavior ?
}
}
}
}

When we try to compile this code, the compiler says something like this:

cannot find symbol

The compiler is saying, “Hey, class Car doesn’t have a brake() method”. Let’s modify the if code block:
if(Car instanceof Ferrari) {
Ferrari d = (Ferrari) Car; // casting the ref. var.
d.brake();
}

The new and improved code block contains a cast, which in this case is sometimes called a downcast, because we’re casting down the inheritance tree to a more specific class. Now, the compiler is happy. Before we try to invoke brake, we cast the Car variable to type Ferrari. What we’re saying to the compiler is, “We know it’s really referring to a Ferrari object, so it’s okay to make a new Ferrari reference variable to refer to that object.” In this case we’re safe because before we ever try the cast, we do an instanceof test to make sure.

It’s important to know that the compiler is forced to trust us when we do a downcast, even when we screw up:

class Car { }
class Ferrari extends Car { }
class FerrariTest {
public static void main(String [] args) {
Car Car = new Car();
Ferrari d = (Ferrari) Car; // compiles but fails later
}
}

It can be maddening! This code compiles! When we try to run it, we’ll get an exception something like this:
java.lang.ClassCastException

Why can’t we trust the compiler to help us out here? Can’t it see that Car is of type Car? All the compiler can do is verify that the two types are in the same inheritance tree, so that depending on whatever code might have come before the downcast, it’s possible that Car is of type Ferrari. The compiler must allow things that might possibly work at runtime. However, if the compiler knows with certainty that the cast could not possibly work, compilation will fail.

The following replacement code block will NOT compile:
Car Car = new Car();
Ferrari d = (Ferrari) Car;
String s = (String) Car; // Car can't EVER be a String

In this case, you’ll get an error something like this:
inconvertible types

Unlike downcasting, upcasting (casting up the inheritance tree to a more general type) works implicitly (i.e., you don’t have to type in the cast) because when you upcast you’re implicitly restricting the number of methods you can invoke, as opposed to downcasting, which implies that later on, you might want to invoke a more specific method. For instance:

class Car { }
class Ferrari extends Car { }

class FerrariTest {
public static void main(String [] args) {
Ferrari d = new Ferrari();
Car a1 = d; // upcast ok with no explicit cast
Car a2 = (Car) d; // upcast ok with an explicit cast
}
}

Both of the previous upcasts will compile and run without exception, because a Ferrari IS-A Car, which means that anything a Car can do, a Ferrari can do. A Ferrari can do more, of course, but the point is—anyone with a Car reference can safely call Car methods on a Ferrari instance. The Car methods may have been overridden in the Ferrari class, but all we care about now is that a Ferrari can always do at least everything a Car can do. The compiler and JVM know it too, so the implicit upcast is always legal for assigning an object of a subtype to a reference of one of its supertype classes (or interfaces). If Ferrari implements Convertible, and Convertible defines openHood(), then a Ferrari can be implicitly cast to a Convertible, but the only Ferrari method you can invoke then is openHood(), which Ferrari was forced to implement because Ferrari implements the Convertible interface.

One more thing...if Ferrari implements Convertible, then if FerrariF12011 extends Ferrari, but FerrariF12011 does not declare that it implements Convertible, FerrariF12011 is still a Convertible! FerrariF12011 is a Convertible simply because it extends Ferrari, and Ferrari’s already taken care of the Convertible parts of itself, and all its children. The FerrariF12011 class can always override any methods it inherits from Ferrari, including methods that Ferrari implemented to fulfill its interface contract.

And just one more thing...if FerrariF12011 does declare it implements Convertible, just so that others looking at the FerrariF12011 class API can easily see that FerrariF12011 IS-A Convertible, without having to look at FerrariF12011’s superclasses, FerrariF12011 still doesn’t need to implement the openHood() method if the Ferrari class (FerrariF12011’s superclass) has already taken care of that. In other words, if FerrariF12011 IS-A Ferrari, and Ferrari IS-A Convertible, then FerrariF12011 IS-A Convertible, and has already met its Convertible obligations for implementing the openHood() method since it inherits the openHood() method. The compiler is smart enough to say, “I know FerrariF12011 already IS a Ferrari, but it’s OK to make it more obvious.”

So don’t be fooled by code that shows a concrete class that declares that it implements an interface, but doesn’t implement the methods of the interface. Before you can tell whether the code is legal, you must know what the superclasses of this implementing class have declared. If any superclass in its inheritance tree has already provided concrete (i.e., non-abstract) method implementations, then, regardless of whether the superclass declares that it implements the interface, the subclass is under no obligation to re-implement (override) those methods.

Tip: Sometimes, the exam questions are jammed into little spaces and that might add to a little confusion to the exam taker (YOU). So be on the watch out for stuff like this:
Car a = new Ferrari();
Ferrari d = (Ferrari) a;
d.doFerrariStuff();

Can be replaced with this easy-to-read bit of fun:
Car a = new Ferrari();
((Ferrari)a).doFerrariStuff();

In this case the compiler needs all of those parentheses, otherwise it thinks it’s been handed an incomplete statement.

Previous Chapter: Chapter 8: Object Oriented Concepts - Polymorphism

Next Chapter: Chapter 10: Implementing An Interface

Friday, January 7, 2011

Chapter 8: Object Oriented Concepts - Polymorphism:

Polymorphism can be considered as the ability of one thing being multiple other things (though partially or fully). Am I confusing you? I believe yes. To put it in simpler words, any java object that can pass more than one Is-A test can be considered polymorphic. (Remember the Is-A and Has-A relationships that we looked at in the previous chapter?)
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.

In the previous chapter on Inheritance we crdriveed a class Car that was extended by two other classes Ferrari and Porsche. Now lets say you want to add a fdriveure “open hood” to the cars. Not all cars have a retractable hood but at the same time you want this fdriveure for certain sports models of Ferrari and Porsche. How would you implement this?

Can we create a class with the openHood() method and only some of the subclasses of Ferrari or Porsche inherit from them? If we can do that then we can implement the feature wherein only selected models of Ferrari or Porsche sports cars can do that. But, unfortunately that wont work in Java. Remember the part on Multiple Inheritance towards the end of the last chapter? You cannot have a class that extends from two classes at the same time. So a code like this would never work:

Public class Porsche911TurboConvertible extends Porsche, Convertible {

}

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.

So if that doesn't work, what else options do we have? We could simple put the openHood() code inside Car class and disable the method in cars that cant open their hood. But, that is really bad design choice owing to multiple reasons. It makes the code error-prone, makes the class Cars less cohesive and it means that as per the code inside the Car class, all cars can open their hoods but the fact is only certain models can do that.

So what else could you do? You already know the answer—crdrivee a Convertible interface, and have only the Car subclasses that can open their hoods implement that interface. Here’s the interface:

public interface Convertible {
public void openHood();
}

And here’s the modified Porsche class that implements the interface:

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

So now we have a Porsche that passes the IS-A test for both the Car class and the Convertible interface. That means a Porsche can be trdriveed 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 Car (since Porsche extends Car)
• A Porsche (since that’s what it really is)
• An Convertible (since Porsche implements Convertible)

The following are all legal declarations. Look closely:
Porsche porscheCar = new Porsche();
Object o = porscheCar;
Car shape = porscheCar;
Convertible mover = porscheCar;

There’s only one object here—an instance of type Porsche—but there are four different types of reference variables, all referring to that one object on the heap.
This is polymorphism – the scenario where one object can be perceived or considered as multiple things.

There are two other important topics that we shall cover in this chapter:
• Method Overloading and
• Method Overriding

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 in the earlier chapters, 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 Porsche subclass of Car overriding the Car version of the drive() method:

public class Car {
public void drive() {
System.out.println("Generic Car Driving Generically");
}
}

class Porsche extends Car {
public void drive() {
System.out.println("Porsche driving Full Throttle");
}
}

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

public class TestCars {
public static void main (String [] args) {
Car a = new Car();
Car b = new Porsche(); //Car ref, but a Porsche object
a.drive(); // Runs the Car version of drive()
b.drive(); // Runs the Porsche version of drive()
}
}
class Car {
public void drive() {
System.out.println("Generic Car Driveing Generically");
}
}
class Porsche extends Car {
public void drive() {
System.out.println("Porsche driving Full Throttle");
}
public void brake() { }
}

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

Car c = new Porsche();
c.brake(); // Can't invoke brake();
// Car 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 private). Think about it: if the Car class advertises a public drive() method and someone has an Car reference (in other words, a reference declared as type Car), that someone will assume it’s safe to call drive() on the Car reference regardless of the actual instance that the Car 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 (Porsche) version of the method rather than the reference type’s (Car) version—the program would die a horrible death. Let’s modify the polymorphic example we saw earlier in this section:

public class TestCars {
public static void main (String [] args) {
Car a = new Car();
Car b = new Porsche(); //Car ref, but a Porsche object
a.drive(); // Runs the Car version of drive()
b.drive(); // Runs the Porsche version of drive()
}
}
class Car {
public void drive() {
System.out.println("Generic Car Driveing Generically");
}
}
class Porsche extends Car {
private void drive() { // whoa! - it's private!
System.out.println("Porsche driving Full Throttle");
}
}
If this code compiled (which it doesn’t), the following would fail at runtime:
Car b = new Porsche(); // Car ref, but a Porsche
// object , so far so good
b.drive(); // Chaos at runtime!


The variable b is of type Car, which has a public drive() 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. A Car reference can always refer to a Porsche instance, because Porsche IS-A Car. 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 Porsche instance overrides the inherited methods of Car or simply inherits them, anyone with a Car reference to a Porsche instance is free to call all accessible Car 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 that you didn’t intend on creating.
• The return type must be the same as, or a subtype of, the return type declared in the original overridden method in the superclass.
• The access level can’t be more restrictive than the overridden method’s. (public to private not allowed)
• The access level CAN be less restrictive than that of the overridden method. (private to public allowed)
• 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.
• If a method can’t be inherited, you cannot override it. Remember that overriding implies that you’re re-implementing a method you inherited! For example, the following code is not legal, and even if you added an drive() method to Porsche, it wouldn’t be an override of Car’s drive() method.

public class TestCars {
public static void main (String [] args) {
Porsche h = new Porsche();
h.drive(); // Not legal because Porsche didn't inherit drive()
}
}
class Car {
private void drive() {
System.out.println("Generic Car Driveing Generically");
}
}
class Porsche extends Car { }

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.” It’s easy to do in code using the keyword super as follows:

public class Car {
public void drive() { }
public void changeGear() {
// Useful change gear code goes here
}
}
class Porsche extends Car {
public void changeGear() {
// Take advantage of Car code, then add some more
super.changeGear(); // Invoke the superclass (Car) code
// Then do Porsche-specific change gear 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. Let’s take a look at an example:
class Car {
public void drive() throws Exception {
// throws an Exception
}
}
class Car2 extends Car {
public void drive() { /* no Exceptions */}
public static void main(String [] args) {
Car a = new Car2();
Car2 d = new Car2();
d.drive(); // ok
a.drive(); // compiler error - unreported exception
}
}

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

Examples of Illegal Method Overrides

Let’s take a look at overriding the drive() method of Car:
public class Car {
public void drive() { }
}

Let us take a look at a few examples of overridden drive() methods taking the above version of the method in the Car Class

1. private void drive() {} – Access Modifier is more restrictive
2. public void drive() throws IOException {} – Declares a checked exception that is not defined by the super class
3. public void drive (String road) {} – A legal overload but not an override because the arguments to the method has changed (Don't bother about overload just yet, that is the next paragraph)
4. public String drive() {} – Not an override because of the return type and at the same time, not an overload either because there is no change in the argument list.

Overloaded Methods

Experienced java programmers can clearly identify the difference between overloaded methods and the overridden ones. We just had a detailed look at overridden methods and it is time to take a look at the overloaded ones.

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.

Tip: 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 Car {
public void drive(int y, String s) { }
public void brake(int x) { }
}
class Ferrari extends Car {
public void drive(int y, long s) throws IOException { }
}
It’s tempting to see the IOException as the problem, because the overridden drive() method doesn’t declare an exception, and IOException is checked by the compiler. But the drive() method is not overridden! Subclass Ferrari overloads the drive() method, by varying the argument list, so the IOException is fine.

Legal Overloads

Let us say we have the Ferrari class with a method drive() as below:
Public class Ferrari extends Car {
Public void drive() {…}
}

Below are the legal overload method declarations:

1. public void drive(String destination, String roadToTake) {…}
2. public void drive(String destination, int timeToTake) {…}
3. public void drive(String destination) throws RouteNotFoundException {…}
Assuming that the Ferrari class has the above 3 methods, below are is an illegal overload:
1. public String drive (String destination, String roadToTake) {…} – You cannot have two methods which differ just in the return type. This is not allowed

Invoking Overloaded Methods

When you have multiple methods that have the same name, it is sometimes confusing for the programmer who is analysing the code to determine which method would get called and when. But, the good news is that the compiler does not have this dilemma.

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 Ferrari class might have three methods with the same name but with different argument lists, which means the method is overloaded. (Check example methods above)

The compiler checks the list of arguments passed to the method before deciding which method to call. Let us say you call the drive method with only the String argument “Destination” the compiler knows exactly that the 3rd method that takes only one String as argument is the method to be invoked. The other 2 methods wouldn't be touched at all during program execution.
Example:

Public class Ferrari extends Car {
public void drive(String destination, String roadToTake) {…}
public void drive(String destination, int timeToTake) {…}
public void drive(String destination) throws RouteNotFoundException {…}
}
Let us say we have the above Ferrari class.

Public class FerrariTest {
Public static void main(String[] args) {
Ferrari car = new Ferrari();
Car.drive(“Central Railway Station”);
}
}

In the preceding code, the FerrariTest class invokes a drive method with just one String argument. So the compiler scans the Ferrari class to see if there is a method drive() that takes one string argument and since it finds one, it invokes it.

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 Car and one takes a Porsche (subclass of Car). If you pass a Porsche object in the method invocation, you’ll invoke the overloaded version that takes a Porsche. Or so it looks at first glance:

class Car { }
class Porsche extends Car { }
class UseCars {
public void doStuff(Car a) {
System.out.println("In the Car version");
}
public void doStuff(Porsche h) {
System.out.println("In the Porsche version");
}
public static void main (String [] args) {
UseCars ua = new UseCars();
Car CarObj = new Car();
Porsche PorscheObj = new Porsche();
ua.doStuff(CarObj);
ua.doStuff(PorscheObj);
}
}

The output is what you expect:
in the Car version
in the Porsche version

But what if you use an Car reference to a Porsche object?
Car CarRefToPorsche = new Porsche();
ua.doStuff(CarRefToPorsche);

Which of the overloaded versions is invoked? You might want to say, “The one that takes a Porsche, since it’s a Porsche object at runtime that’s being passed to the method.” But that’s not how it works. The preceding code would actually print:
in the Car version

Even though the actual object at runtime is a Porsche and not an Car, 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 a Car reference to a Porsche object, the compiler knows only about the Car, so it chooses the overloaded version of the method that takes an Car. It does not matter that at runtime there’s actually a Porsche 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 Car reference, the overloaded method that takes an Car will be invoked, even if the actual object passed is a Porsche. Once the Porsche masquerading as Car gets in to the method, however, the Porsche object is still a Porsche despite being passed into a method expecting an Car. 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 Car and Porsche classes look like this:

public class Car {
public void drive() {
System.out.println("Generic Car Driving Generically");
}
}
public class Porsche extends Car {
public void drive() {
System.out.println("Porsche driving Fast ");
}
public void drive(String s) {
System.out.println("Porsche driving " + s);
}
}

Notice that the Porsche class has both overloaded and overridden the drive() method.

Tip: 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 Car {
void drive() { }
}
class Ferrari extends Car{
void drive(String s) { }
}

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


Differences between Overloaded and Overridden Methods:

  Overloaded Methods Overridden Methods
Arguments Must Change Must Not Change
Return Type Can Change Cannot Change (Except for Covariant Returns)
Access Can Change Cannot Change to 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.
Constructor Overloading is actually another topic that would be a part of this polymorphism/overloading discussion but we will be covering that as part of one of the subsequent chapters.

Previous Chapter: Chapter 7: Object Oriented Concepts - Inheritance

Next Chapter: Chapter 9: Reference Variable Casting
© 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