Analysis of g
method
Note that f
is an instance method, while g
is a static method. Static methods are associated with class
.
Hence, because you declare b1
, a1
and a2
as A
, calling b1.g()
, a1.g()
and a2.g()
will all call A.g()
.
Here's another good SO question on Java static methods: Why doesn't the compiler complain when I try to override a static method?
Analysis of f
method
Java instance methods are by default virtual
methods, which can be overridden by sub classes. So what f()
actually does depends on what the instance is (that is, depends on the type following the new
keyword).
b1
is an instance of B
, so b1.f()
will call the f
method defined on B
, that is, B.f()
.
i1
is also an instance of B
, so i1.f()
will also call the f
method defined on B
, that is, B.f()
.
i2
is an instance of A
, so i2.f()
will call the f
method defined on A
, that is, A.f()
.
Then what about a2.f()
? As I stated above, a2
is an instance of B
(you create it with the new
keyword), so a2.f()
will call B.f()
.
More on method overridding
You might wonder why they work like that? Why a2.f()
is not designed to call A.f()
in Java? Here's why:
Assume you have a module which will do complex calculation against a list of records. These records might be retrieved from database, or from web api provided by third party rest api. How to make your module as extensible as possible?
Here's your module code:
public class MyModule {
public void doComplexWork() {
// Where to get the records?
List<Record> records = ???;
// Do complex computation here
}
}
An extensible way to do this is to define an interface (or abstract class) as a contract of 'record retrieving':
public interface IRecordRetriever {
List<Record> retrieveRecords();
}
Then you implement two IRecordRetriever
s, one to retrieve records from database, while the other one retrieve records from rest api.
public class DatabaseRecordRetriever implements IRecordRetriever {
@Override
public List<Record> retrieveRecords() {
// Connect database and fetch database records here
}
}
public class RestApiRecordRetriever implements IRecordRetriever {
@Override
public List<Record> retrieveRecords() {
// Access the rest api to fetch records here
}
}
Now let's change our module code a little bit:
public class MyModule {
private IRecordRetriever _recordRetriever;
// Inject IRecordRetriever from contructor
public MyModule(IRecordRetriever retriever) {
_recordRetriever = retriever;
}
public void doComplexWork() {
// Where to get the records?
// From the IRecordRetriever
List<Record> records = _recordRetriever.retrieveRecords();
// Do complex computation here
}
}
Now our MyModule
is extensible now. Because no matter where to retrieve the records, no code in MyModule
need to be changed. If now you retrieve records from database, but later you decide to change to retrieve records from rest api, still nothing in MyModule
need to be changed! You just need to change the runtime IRecordRetriever
instance passed to MyModule
constructor.
Why can we achieve this extensibility? It's because of the method overriding. We declare the private field _recordRetriever
as IRecordRetriever
, so the actual behavior depends on the actual runtime instance (created by the new
keyword). So to change record retrieving behavior we only need to change the runtime IRecordRetriever
instance passed to the MyModule
constructor. If method overriding is not available, that is:
IRecordRetriever retriever = new DatabaseRecordRetriever();
retriever.retrieveRecords();
If the call to retriever.retrieveRecords()
is not calling the retrieveRecords()
method defined on DatabaseRecordRetriever
, but calling the retrieveRecords()
method defined on IRecordRetriever
, we are not able to achieve the extensibility. (Of course, IRecordRetriever
is an interface, so you are not able to call IRecordRetriever.retrieveRecords()
, but this also holds for virtual methods).
What I mentioned above also hold for other object oriented programming languages.
The way I pass IRecordRetriever
to MyModule
through constructor is called Constructor Dependency Injection
. You can read more materials on object oriented programming, method overriding and GoF design patterns.