Declare APIs
What is our problem?
public class FastRandom
{
public int getRandomInteger()
{
// code here
}
}
public class SecureRandom
{
public int randomInt()
{
// code here
}
}
public class UseRandom
{
private FastRandom random = new FastRandom();
public int getRandomInteger()
{
int r = random.getRandomInteger();
}
}
P.S. Typical courses explain interfaces via inheritance, we try it a little different.
public class FastRandom
{
public int getRandomInteger()
{
// code here
}
}
public class SecureRandom
{
public int randomInt()
{
// code here
}
}
public class UseRandom
{
public int getRandomInteger()
{
FastRandom random = new FastRandom();
int r = random.getRandomInteger();
}
}
public class UseRandom
{
public int getRandomInteger()
{
SecureRandom random = new SecureRandom();
int r = random.randomInt();
}
}
public class UseRandom
{
public int getRandomInteger()
{
final Random random =
RandomFactory.getGenerator();
int r = random.nextInt();
}
}
What are Interfaces?
implements
public interface Random
{
// Initial seed to use for all generators
public final int INITIALSEED = 42;
/**
* Returns a new random number
*
* @return a new random integer
*/
public int nextInt();
}
public class FastRandom implements Random
{
public int nextInt()
{
// code here
// can use that here
int a = INITALSEED;
}
}
public class SecureRandom implements Random
{
public int nextInt()
{
// code here
// can use that here
int a = INITALSEED;
}
}
public class UseRandom
{
public int getRandomInteger()
{
final Random random =
RandomFactory.getGenerator();
// random = new FastRandom();
// random = new SecureRandom();
int r = random.nextInt();
// I can use that here.
int foo = Random.INITALSEED;
}
}
Support to see what comes from where
@Override
annotation to support compiler error-checking
hashcode()
vs. hashCode()
@Override
is used for abstract classes as well
public class FastRandom implements Random
{
@Override
public int nextInt()
{
// code here
// can use that here
int a = INITALSEED;
}
}
Mostly automatically inserted by the IDE.
Kill two birds with one stone
public interface Random
{
public int nextInt();
}
public interface Resetable
{
public void reset();
}
public class XRandom implements Random, Resetable
{
@Override
public void reset()
{
// code here
}
@Override
public int nextInt()
{
// code here
}
public int moreStuff()
{
}
}
Build on existing interfaces
extend
to build on an interface and enrich it
public interface Vehicle
{
public String getLicensePlate();
}
public interface Car extends Vehicle
{
public void stopEngine();
}
public interface Convertible extends Car
{
public void closeTop();
}
public class SL500 implements Convertible
{
private String plate;
public SL500(String plate)
{
this.plate = plate;
}
public void stopEngine()
{
// code
}
public void closeTop()
{
// code
}
public String getLicensePlate()
{
return plate;
}
}
Can be used for API compatibility.
public interface Vehicle
{
public String getLicensePlate();
}
public interface Car extends Vehicle
{
public void stopEngine();
}
public interface Convertible extends Car
{
public void closeTop();
}
public class Parking
{
private Map<String, Vehicle> parkingSpaces = new HashSet<>();
public void park(Car car)
{
parkingSpaces.add(car.getLicensePlate(), car);
car.stopEngine();
}
public void park(Convertible convertible)
{
parkingSpaces.add(convertible.getLicensePlate(), convertible);
convertible.closeTop();
convertible.stopEngine();
}
public Vehicle retrieve(String plate)
{
return parkingSpaces.get(plate);
}
}
What can ruin your day
How to permit interface evolution
public interface Converter
{
public String toString(int i);
}
public interface ConverterV2 extends Converter
{
public String toString(long l);
}
public class IntConverter implements Converter
{
public String toString(int anInteger)
{
// code here
}
}
public class NumberConverter extends IntConverter implements ConverterV2
{
public String toString(long anLong)
{
// code here
}
}
A way to change interfaces
default
keyword to add implementations to avoid breaking changes
public interface Converter
{
public String toString(int i);
public default String toString(long l);
{
// code here
}
}
public interface Converter
{
public String toString(int i);
public static boolean isInteger(int i)
{
// code here
}
}
P.S: Get used to putting public
into interface definitions, because Java 9 starts to permit private
too.
What you might want to consider first
public
even though it is not needed in Java 8, but will be in Java 9
P.S. Interfaces vs. abstract classes... very grayish area. More later.