6

I have started with JAVA programming recently and have one question to ask. Let's say I have one SuperClass and one SubClass which extends SuperClass and try to Override a method defined in SuperClass as follows:

  public class SuperClass{
    public void method1(int val){
      System.out.println("This is method in SuperClass.Val is:" + val);
      }
  }

I try to extend the SuperClass in my SubClass and override the method with only one exception, instead of type int declared in method1, I use the type for the argument as Integer, as follows:

  public class SubClass extends SuperClass{
    @Override 
    public void method1(Integer val){     ///compiler gives an error

     }
  }  

This declaration of SubClass method is not allowed by the compiler(I am using eclipse IDE). Why is this so? Integer is essentially wrapper of int then why such a declaration is prohibited?

Thanks

theimpatientcoder
  • 1,184
  • 3
  • 19
  • 32
  • There is no problem here with respect to different parameter types, since you are just declaring two overloads of a method called `method1`. *However*, you have several syntax errors apart from this, like missing `class` before `SubClass`, using `void` instead of `class` before `SuperClass`, missing `;` etc. – Andy Turner Dec 02 '15 at 13:49
  • 2
    Do you have an `@Override` annotation in the sub-class method1? If you don't, there shouldn't be a problem. – Eran Dec 02 '15 at 13:50
  • missed the @Override annotation.....corrected. – theimpatientcoder Dec 02 '15 at 13:51

4 Answers4

3

The formal explanation, as you probably already understand, is that the two functions have different signatures, (as Andrew Tobilko has already pointed out,) so one may not override the other.

So, I presume that by asking this question, what you really mean to ask is "why is this so", or "why can't the compiler figure things out so as to allow me to do this".

So, the practical explanation is as follows:

This is because you may have some method somewhere, (of some unrelated class even) which accepts a SuperClass as a parameter, and attempts to invoke its method1() like this:

public void someMethod( SuperClass s )
{
    s.method1( 7 );
}

When the compiler finds this, it will pass 7 as a parameter to method1(), it will not pass a wrapped 7. However, s may not really be an instance of SuperClass, it may be an instance of SubClass, like this:

/* some code somewhere */
someMethod( new SubClass() );

This is valid because there is a principle in OOP known as the Liskov Substitution Principle which says that

if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.).

This is the same principle which allows you to assign a new ArrayList<String>() to a variable of type List<String>, and without it, nothing would work in OOP.

So, the compiler would have to pass a plain primitive 7, but the receiving method of SubClass would be expecting a wrapped 7, and that would not work. So, the language stipulates that an implicit conversion of this kind is invalid, to ensure that nonsensical situations of this kind may not arise.

Amendment

You might ask, "why would it not work?" The answer is that primitives in java correspond to machine data types of the underlying hardware, while wrapped primitives are objects. So, on the machine stack, a 7 would be represented by a machine word with the value of 7, while a wrapped 7 would be represented by something like 0x46d7c8fe, which would be a pointer to an object which contains the wrapped 7.

Mike Nakis
  • 56,297
  • 11
  • 110
  • 142
  • I think your response it slightly confusing for a newbie. 'Overriding' with different parameter types is called 'Overloading' and behaves very different. When compiling the shown code (upper block) the only thing the compiler knows that s will be a SuperClass - this includes any sub class of s. As the compiler can not know in advance which sub class of s will be provided at runtime it can not link to any overloaded method only available in specific sub classes of s (for investigation: there is a dynamic dispatch for overridden methods but not for overloaded ones). – Sebastian Dec 02 '15 at 14:20
  • @Sebastian the OP spoke of overriding right from the beginning, and I spoke of overriding too, so I do not see why you are mentioning overloading. I thought overloading is off topic. As for the rest of your comment, it is of course correct, and eloquent, but I am not sure whether it is less confusing to a newbie. C-:= – Mike Nakis Dec 02 '15 at 14:25
  • @Sebastian I thought that the correct answer to this question absolutely ought to mention the Liskov Substitution Principle, (get the newbies started on solid foundations, right?) so I figured I had to do all that explaining around it so as to not just throw a plain LSP on him and let him figure things out. – Mike Nakis Dec 02 '15 at 14:27
  • Yepp, I not really satisfied by my comment myself. It is also confusing. However I did not write an own answer as yours is already good and has the main point. OP does not spoke of overloading but I think that is due to him being not so familiar with Java. The shown code (override method method1(int) with method1(Integer)) is actually overloading as indicated in some answers / comments). Hence the difference between these two should be clarified. Your answer focusses on LSP but IMHO and explains why it can not be overriding. But as a newbie I would have problems to understand your answer – Sebastian Dec 04 '15 at 07:45
  • Continuation of previous comment: Furthermore your answer does not explicitly state that the shown code (method1(Integer)) must be overloading as it is no overriding and that thus the annotation results in a compiler error. From the point of view of a JVM overloading is just an arbitrary method with a name coincidentally identical to the one of another method. – Sebastian Dec 04 '15 at 07:49
2

It is just because you have added @Override syntax above the method public void method1(Integer val) which asks compiler to look for the method with same signature in the base class which it can not find, thus it gives compile time error stating The method method1(Integer) of type SubClass must override a superclass method.

To understand the problem you asked

Integer is essentially wrapper of int then why such a declaration is prohibited?

Just because in any class you can declare method with these signatures

class SuperClass
{
    public void method1(int val){
        System.out.println("This is method in SuperClass.Val is:" + val);
    }

    public void method1(Integer val){
        System.out.println("This is method in SuperClass.Val is:" + val);
    }
}

The above declaration is valid and therefore the @override will try to match the method with exact signature in base class.

Deepak Bhatia
  • 6,230
  • 2
  • 24
  • 58
2

Why should it matter that Integer is a wrapper for int? They are still different types. You can have to methods with same name, that just differ by one having a primitive type and the other the matching wrapped type.

The only relation between int and Integer is: the compiler insert a conversion from one to the other when in any situation one is given but the other required.

So when you have a reference to the super type and call method1 the compiler generates byte code that essentially passes a primitive. If at runtime you use an actual class of SubClass, the overridden method won't match that call.

Of course the compiler could be written in a style that allows for this kind of overrides, but it would cause other problems:

If the decision was made at runtime, calling overriden methods would become expensive to to boxing/unboxing and checks, they might even trigger NullPointerExceptions

If done by converting everything to the boxed type at compile time, such calls would trigger constant boxing unboxing.

Also this would forbid constructs where you have a method that is overloaded to either take a type parameter or a primitive, because the type parameter might end up being the boxed type for that primitive, resulting to both methods being the same.

Jens Schauder
  • 77,657
  • 34
  • 181
  • 348
-3

Integer and int are different.You could change Integer to int,or remove the "@Override"