1
class B {
    void process()throws Exception{
        System.out.println("hi sh");
    }

}
class C extends B {
    void process(){
        System.out.println("hhhhhh");
    }

    public static void main(String args[]){
        B a=new C();
        try{
             a.process();
        }
        catch(Exception e)
        {
        }
    }
}

Here while calling the process method, we have to use a try catch block. But, if I store the object of C in reference variable of C only i.e. C a=new C() then try catch block is not needed.

Can anyone tell me the reason why?

1

6 Answers 6

5

The compiler can't (in general) tell which type the variable a will have during run-time. Thus, it (always) takes the safe route, and requires you to put try/catch around the call.

When you do

C a = new C();

instead, the compiler can be sure that B.process() is not called at run-time, thus you are allowed to call it without try/catch.

Sign up to request clarification or add additional context in comments.

Comments

1

Assignment to reference will be done at run time.

And exception declaration checking is done at compile time.

If you write

B a=new C();//

Here compiler knows that method of a can also be called it is run time decision so it forces us to handle exception.

But if you use

C a=new C() ;

Compiler is pretty sure that C's method is going to be called so it doesn't declared to throw exception so it allows

Comments

0

Because the signature of B.process() is void process() throws Exception.

In your C class, you've narrowed the signature to void process().

When you declare a reference to be of type B, you need to handle the (checked) exception that B.process() is declared to throw.

When you declare the reference to be of type C, there is no exception that C.process() is declared to throw.

When you instantiate an object as B a = new C(), then a is of runtime type C but the declaration type is B. The compiler treats a as a type B because you declared it to be B. This is polymorphism at work.

Comments

0

This only happens with checked exceptions and this is due to polymorphism.

In you case C is-a B so when you call process() you might throw a checked exception (the one you have to handle).

The safest to handle the exception is forcing the developer to handle this exception whenever process() is called on a B (which could also be a C but you don't know that before runtime).

Comments

0

here while calling the process method we have to use a try catch block but if i store the object of C in reference variable of C only i.e. C a=new C() then try catch block is not needed.Can anyone tell me the reason why?

You need to keep in mind that the run-time type of a reference is not necessarily the same as the declared type. For example:

Number n = new Integer(1);

This declares n to be a reference of declared type java.lang.Number to reference a subclass of java.lang.Number of specific class/type java.lang.Integer.

Information about the actual run-time type is (typically) only available at run-time. But the compiler only operates at compile time. At compile time, the compiler (typically) only knows about the declared types.

Since it typically only knows about declared types, it can only go with that for making decisions on what can compile and what cannot. That is, javac can only enforce rules based on what it knows (or can infer) at compile time.

Going back to your code example:

The compiler is looking at the declared type of the reference (in this case the reference a is of type B). Based on that, the compiler knows that the method B.process() throws a checked exception that it needs to enforce.

That is, either

B a=new C();

or

B a=new B();

declare a of being of type B whose process() method throws a checked exception. However, if you have the following:

C a = new C();

then, the declared type of a is C, not B. Since subclasses can weaken the preconditions of its inherited methods, then C is free to weaken the preconditions of process(). Namely, it can declare C.process() to throw a subset of the set of exceptions thrown by B.process (and in C.process() case, it is the null set.)

This is somewhat related to the Liskov substitution principle and Design by Contract, with the former (thanks wikipedia) stating the following principles (3 and 4 being directly related to what you observed in your java code):

  1. Contravariance of method arguments in the subtype.
  2. Covariance of return types in the subtype.
  3. No new exceptions should be thrown by methods of the subtype, except where those exceptions are themselves subtypes of exceptions thrown by the methods of the supertype.
  4. Preconditions cannot be strengthened in a subtype.
  5. Postconditions cannot be weakened in a subtype.
  6. Invariants of the supertype must be preserved in a subtype.

The Java compiler is simply attempting to enforce some of these principles, and by practical purposes, it uses the declared types of reference variables to determine how to enforce them.

Comments

0

When we write :

B a=new C();

we are implicitly type casting object of C to object B.

a.process();

in Run time it will call process() of C but while compiling, for compiler a is still the object of B and as B has process() throwing exception so it must be catch using try/catch.

if we use :

C a = new C();
a.process();

while compiling, for compiler a is still the object of C (and may contain reference to other subclass object) and as C's has process() is not throwing any exception so NO NEED to catch using try/catch.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.