• Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

narrowing of type and interfaces

 
Joe Khan
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Consider the following situation:
----------------
interface A{
void a();
}
----------------
interface B{
void b(A av);
}
----------------
class myA implements A
{
public void a() {

}
}
-----------------------

class myB implements B{

public void b(myA av) {


}
------------------
The last class doesn't complie. It gives me this error:
myB is not abstract and does not override abstract method b(A) in B


The problem is myA is of type A since it's implementing interface A, so I guess there shouldn't be the error theoretically. or is it a bug with JDK compiler? I'm using JDK 1.6.0_02.
[ December 15, 2007: Message edited by: Joe Khan ]
 
Stan James
(instanceof Sidekick)
Ranch Hand
Posts: 8791
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The compiler is pretty picky when matching signatures. Your myA class is indeed an A, but it's a special kind of A. Other users of myB would see implements B and expect to call your method with any implementation of A. The compiler requires you to accept any kind of A, not just myA.

Experiment with making the myA method use A or a supertype of A, say Object. Do any of those work better? Do they make sense?
 
Jesper de Jong
Java Cowboy
Saloon Keeper
Posts: 15459
42
Android IntelliJ IDE Java Scala Spring
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
This is not a compiler error, and it's correct that you get an error message here. If a non-abstract class implements an interface, then it must provide implementations for all methods in the interface with the correct method signature (method name and argument types). You cannot implement an interface and change the method signature by changing the type of the arguments. I'll try to explain why.

Suppose you declare a variable 'obj' like this:

B obj = new myB();

And now you want to call the method 'b' on 'obj'. Since the type of 'obj' is B, the compiler will check if the arguments you pass to method 'b' are of the type as specified in interface B. According to interface B, you can pass anything that implements A to the method. But your class myB has more strict requirements; it requires that the argument is an instance of myA or of a subclass of myA.

The compiler can't be sure at compile time that 'obj' refers to a myB, and so it cannot check the more strict requirement.

You might now ask "Why can't the compiler check that 'obj' refers to a myB? The compiler knows that if I do B obj = new myB();, doesn't it?".

In this case the compiler maybe could have known it, but that's not so in the more general case. You could for example have instantiated a class via reflection:

Class cls = new Class("myB");
B obj = cls.newInstance();


If you do that, there's no way the compiler could have known at compile-time to what kind of object 'obj' refers at runtime.
[ December 15, 2007: Message edited by: Jesper Young ]
 
Ilja Preuss
author
Sheriff
Posts: 14112
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In short, being able to do that would violate Liskov's Substitution Principle: http://en.wikipedia.org/wiki/Liskov_substitution_principle
 
Joe Khan
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey thanks you guys for responses.
According to Ilja
(1)A is not substitutable by myA(A is a super type not a sub type of myA).
(2)myA is substitutable by A(myA is a sub type of A).

I tried to test second rule of substitution. Here's the code:

interface A{
void a();
}
-----------------
class myA implements A
{
public void a() {}

}
-----------------------
interface B{
void b(myA a);
}
--------------------------
class myB implements B{


public void b(A a) {


}
}

The news is I'm still having the error:
myB is not abstract and does not override abstract method b(myA) in B
 
Jim Yingst
Wanderer
Sheriff
Posts: 18671
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
[Joe]: The news is I'm still having the error:
myB is not abstract and does not override abstract method b(myA) in B


If you look carefully, that's a slightly different error than your original one. And like the first error, it tells you exactly what is wrong with the current code. Quite simply, if you need to override b(myA), then b(A) is not close enough. (And vice versa, in the original problem.) To override a method, you need to use the exact same parameter types, period. (Well, it gets more complicated if generics are involved, but that's not relevant here.) If you change the parameter types - even if the ypes are related - you will get errors. So, don't change the parameter types.
 
Joe Khan
Greenhorn
Posts: 15
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Oh yea Jim, you are right..
sorry I missed that overriding stuff.
There's no such thing auto-conversion with method overriding . The return type and arguments list have to be exactly same.
Auto-conversion only occurs on assignements or on method calls with arugments.
Thank you all for replies.

[ December 17, 2007: Message edited by: Joe Khan ]
[ December 17, 2007: Message edited by: Joe Khan ]
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic