Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When Interface A defines Interface B in its method signature

... how can I restrict an implementation of A to use a certain implementation of B in the method signature?

Use Case

Here is a Unit interface and two enums that implement it:

public interface Unit { ... }

public enum ForceUnit implements Unit { ... }
public enum MassUnit implements Unit { ... }

Which is used by the Property interface:

public interface Property {

    public void setUnit( Unit unit );    // for example
}

public class Force implements Property { ... }
public class Mass implements Property { ... }

Here I want to be able to enforce that:

  • Force uses only ForceUnit in the setUnit signature
  • Mass uses only MassUnit in the setUnit signature

When I try to do this, Eclipse complains:

The type Mass must implement the inherited abstract method Property.setUnit(unit)

And promptly suggests two quick fixes:

  • make the class abstract, which is not an option since I want to be able to do stuff like Mass mass = new Mass();
  • add the unimplemented methods with an @Override annotation. I don't know if this is the right fix, but to me this smacks of clumsiness.

Questions

  • What options do I have to achieve what I want? Would the use of generics help here?
  • Why does marking the class as abstract resolve the issue?
like image 931
Zaid Avatar asked Feb 18 '16 19:02

Zaid


People also ask

What is method signature in interface?

Definition of a Java Method Signature It's the combination of the method name and the parameter list. The reason for the emphasis on just the method name and parameter list is because of overloading. It's the ability to write methods that have the same name but accept different parameters.

CAN interfaces declare method signatures?

Like a class, an interface can have methods and variables, but the methods declared in an interface are by default abstract (only method signature, no body). Interfaces specify what a class must do and not how.

How do you define an interface?

An interface is declared by using the interface keyword. It provides total abstraction; means all the methods in an interface are declared with the empty body, and all the fields are public, static and final by default. A class that implements an interface must implement all the methods declared in the interface.

What happens when a constructor is defined for an interface?

8. What happens when a constructor is defined for an interface? Explanation: Constructor is not provided by interface as objects cannot be instantiated. 9.


1 Answers

You can use generics

public interface Property<U extends Unit> {

    public void setUnit(U unit );    // for example
}

public class Force implements Property<ForceUnit> {
    @Override
    public void setUnit(ForceUnit unit) { }
}

public class Mass implements Property<MassUnit> {
    @Override
    public void setUnit(MassUnit unit) { }
}

Note: This does mean you can still do

Property raw = new Mass();
raw.setUnit(ForceUnit.NEWTON); // ClassCastException

however this will cause a class cast exception as the compiler is unable to check the raw type at run time.

What you should do is

Property<Mass> raw = new Mass();
raw.setUnit(ForceUnit.NEWTON); // doesn't compile.

Why does marking the class as abstract resolve the issue?

Making the classes abstract means that setUnit(Unit) hasn't actually been implemented but for an abstract class this is ok.

like image 183
Peter Lawrey Avatar answered Oct 21 '22 04:10

Peter Lawrey