Java Reference
In-Depth Information
You can write the following snippet of code:
P p = // get an object reference of P or its descendant;
try {
Employee emp = p.getEmp(10);
}
catch (EmpNotFoundException e) {
// Handle the exception here
}
There are two points that need to be considered in the above snippet of code. First, the variable p, which is of
type
P
, can point to an object of type
P
or to an object of any descendant of class
P
. Second, when
p.getEmp(10)
method
is called, the compiler verifies that the declared type of variable
p
(
P
class) has a
getEmp()
method, which accepts
one parameter of type
int
, returns an
Employee
type object and throws
EmpNotFoundException
. These pieces of
information are verified by the compiler with class
P
. The assumption made (and verified, too) by the compiler about
the
getEmp()
method should never be invalidated at runtime. Otherwise, it will result in a chaos; code compiles,
but might not run.
Let's consider one of the possible cases of overriding the
getEmp()
method as shown:
public class Q extends P {
public Manager getEmp(int empId) {
// code goes here
}
}
If the variable
p
is assigned an object of class
Q
, the code
Employee emp = p.getEmp(10);
inside the
try-catch
block is still valid. In this case, the variable p will refer to an object of class
Q
whose
getEmp()
method returns a
Manager
object and does not throw any exception. Returning a
Manager
object from the
getEmp()
method is fine because you can assign a
Manager
object to the
emp
variable, which is a case of upcasting.
Not throwing an exception from the
getEmp()
method is also fine because the code was ready to handle the exception
(by using a
try-catch
block) in case the exception was thrown.
What is the reason behind the access level rules for overriding methods? Note that when a variable
p
accesses
the
getEmp()
method, the compiler verifies that the code, where
p.getEmp()
is used, has access to the
getEmp()
method of class
P
. If the subclasses of
P
reduces the access level, the same code,
p.getEmp()
, may not work at runtime,
because the code executing the statement may not have access to the
getEmp()
method in the descendant of class
P
.
Let's consider the following definition of class
Q2
, which inherits from class
P
. It overrides the
getEmp()
method
and replaces the
EmpNoFoundException
with another checked exception named
BadEmpIdException
.
// Won't compile
public class Q2 extends P {
public Manager getEmp(int empId) throws BadEmpIdException {
// code goes here
}
}