Java - Declaring from Interface Type Instead of Class

Java - declaring from Interface type instead of Class

When there is a choice between referring to an object by their interface or a class, the former should be preferred, but only if an appropriate type exists.

Consider StringimplementsCharSequence as an example. You should not just blindly use CharSequence in preferrence to String for all cases, because that would deny you simple operations like trim(), toUpperCase(), etc.

However, a method that takes a String only to care about its sequence of char values should use CharSequence instead, because that is the appropriate type in this case. This is in fact the case with replace(CharSequence target, CharSequence replacement) in the String class.

Another example is java.util.regex.Pattern and its Matcher matcher(CharSequence) method. This lets a Matcher be created from Pattern for not just String, but also for all other CharSequence there are out there.

A great example in the library of where an interface should've been used, but unfortunately wasn't, can also be found in Matcher: its appendReplacement and appendTail methods accept only StringBuffer. This class has largely been replaced by its faster cousin StringBuilder since 1.5.

A StringBuilder is not a StringBuffer, so we can not use the former with the append… methods in Matcher. However, both of them implementsAppendable (also introduced in 1.5). Ideally Matcher's append… method should accept any Appendable, and we would then be able to use StringBuilder, as well as all other Appendable available!

So we can see how when an appropriate type exists referring to objects by their interfaces can be a powerful abstraction, but only if those types exist. If the type does not exist, then you may consider defining one of your own if it makes sense. In this Cat example, you may define interface SelfBathable, for example. Then instead of referring to a Cat, you can accept any SelfBathable object (e.g. a Parakeet)

If it does not make sense to create a new type, then by all means you can refer to it by its class.

See also

  • Effective Java 2nd Edition, Item 52: Refer to objects by their interfaces

    If appropriate interface types exist, then parameters, return values, and fields should all be declared using interface types. If you get into the habit of using interface types, your program will be much more flexible. It is entirely appropriate to refer to an object by a class if no appropriate interface exists.

Related links

  • Bug ID: 5066679 - java.util.regex.Matcher should make more use of Appendable

Writing a method to accept interface type instead of class type

Method declaration like following should work -

public static Frame createPlot(String title, String xAxisLabel, String yAxisLabel,
List<? extends XYPlottable> points, boolean fitLine) {

Note the change in the parameter List<XYPlottable> to List<? extends XYPlottable> - This is called as wildcards.

Read more about generic wildcards here

How to declare a variable of type Interface and then assign to the variable an object of a Class that implements the Interface, and how to test this?

(I will use uppercase for the start of class and interface names)

Is my method valid in terms of declaring a variable of interface example and then assigning to the variable an object of exampleImpl that implements example?

Yes, but in this case it isn't needed and you shouldn't do it like this anyway. You assume that the object coming via the parameter e will always be a ExampleImpl instance because you have a hard coded cast of that variable. If it is not such a class you will get a ClassCastException. In this case you can remove the

Example eInst = (ExampleImpl)e;

line and use the variable e instead.

It must also return a variable of type example, but I do not know where newVar1 and newVar2 go when this happens since they are not defined in the interface.

You already have written the code

Example summedE = new ExampleImpl(normalisedNewVar1, normalisedNewVar2);
return summedE;

which will return an object, which implements the Example interface. So everything is fine here. If you want to use newVar1 and newVar2 depends on your implementation and requirement for the manipulate method.

Can I create an object within the test class to call this test on?

Yes, that's the normal way to do so. Write

Example obj = new ExampleImpl(4, 5);

in your test method to create an Example object you can work with. You can call the manipulate() method with a different Example object like this:

Example obj = new ExampleImpl(4, 5);
Example obj2 = new ExampleImpl(10, 20);
Example obj3 = obj.manipulate(obj2);

I want to check it returns the right manipulation based on an object "this" and the new object "e". Is there a way to do this?

That depends on what other methods are defined on your Example interface. You have written that it extends from a different interface, also named Example. Base on what is defined in that interface, you might call other methods on your Example object like this:

 Assert.assertEquals(42, obj3.getDifference()); // or whatever other methods you have

Interfaces implicitly declaring public methods of Object class?

What is the purpose of this design?

Because you want to be able to call all the Object methods ( toString, equals, hashCode, and such) on every object of any type.

interface Foo {

}

Foo foo = ...;

foo.equals(otherFoo);

Doesn't matter if I actually declared the equals method in the interface.

Interface as a type in Java?

Let's declare two interfaces and a class that implements them both:

interface I1 { }

interface I2 { }

class C implements I1, I2 { }

objects can have multiple types

In the following code, it can be seen that a C instance has the type of C as well as I1 and I2:

C c = new C();

boolean isC = (c instanceof C); //true
boolean isI1 = (c instanceof I1); //true
boolean isI2 = (c instanceof I2); //true

Now let's declare a class B which implements I1 as well:

class B implements I1 { }

if a variable is declared to be the type of an interface, its value can reference any object that is instantiated from any class that implements the interface.

If we declare a variable of type I1, we can set it to an instance of C, and then reassign it to an instance of B:

I1 i1 = new C();
i1 = new B();

We can also reassign it to an instance of D, where D extends C:

i1 = new D();

...

class D extends C { }

Initialize a Java Collection in Class that was declared in Interface

Java, the language, is designed with the following ideas in mind:

  • Fields are never really considered as part of a type's "public API". Yes, a public field can be written and can be modified from the outside, but almost no java code out there does this, and many language features simply do not support it. For example, method references exists (someExpr::someMethodName is legal java), but the there is no such thing as a field reference.

  • Interfaces exist solely to convey API - to convey what a type is supposed to be able to do, it is not a thing that was intended for conveying how it is to do it. In other words, interface (hence the name) yes, implementation no.

Add these 2 concepts together and you see why what you want (put a field in an interface) is not supported. A field is not part of an interface (rule #1), therefore it must be implementation, and interfaces can not carry implementation details (rule #2), hence: You cannot put a field in an interface.

As a consequence, the java lang spec dictates that any field declaration in an interface is inherently public static final - it's a constant. You can't make it not-public-static-final - putting private on it as modifier is a compiler error. There is no modifier that means 'unstatic'.

You have 2 options:

  • You intended that field solely as implementation: You decided that all classes that implement this interface will need this field, so, might as well declare it in the interface and save the typing, right? Well, what you're doing there is grouping common aspects of the implementation together. Java supports this, but only in abstract classes. This happens all the time in java: There is java.util.List (an interface), and java.util.AbstractList (an abstract class that implements that interface, that provides a bunch of common behaviour), and java.util.ArrayList (the most commonly used implementation. It extends AbstractList).

  • You actually need the 'interface' part of that field: You want to write some code, either in the interface file itself (via default methods), or in code that receives an object whose type is your machine interface, and want to directly access the field. When in rome, act like romans. When programming java, act like other java programmers. Which means: Don't treat fields as interface - as API. If the very essence of 'a machine' (that is to say: An object that is an instance of a class, and that class implements machine) is that it can provide a list of integers representing the temp concept, then make that part of the interface: Write Vector<Integer> getTemp; in the interface, and let each implementing class provide an implementation. If you expect that all implementing classes likely just want:

private Vector<Integer> temp;

public Vector<Integer> getTemp() {
return temp;
}

Then you can put that in an abstract class which implements the interface, and have all your impls implement the abstract class.

If this is all flying over your head, I can make it simpler:

  • All field decls in interfaces are necessarily public static final, whether you write it or not. You can't declare fields that aren't, the language simply won't let you.
  • There are good reasons for that - see the above explanation.

NB:

You appear to be using some extremely outdated (at least 25 years at this point!!) guidebook. This code wouldn't pass any review as a consequence. Vector is obsolete and should not be used, and has been obsolete for 20 years: You want ArrayList, presumably. Java conventions dictate that TypesGoLikeThis, methodNamesLikeThis, variableNamesAlsoLikeThis, and CONSTANTS_LIKE_THIS. Thus, it'd be public interface Machine, not public interface machine. The compiler lets you do whatever you want, but your code is needlessly weird and inconvenient when you integrate it with any other java code if you fail to follow the conventions.

Why would you declare an Interface and then instantiate an object with it in Java?

It doesn't matter there.

Where it really matters is in other interfaces that need to operate on IVehicle. If they accept parameters and return values as IVehicle, then the code will be more easily extendible.

As you noted, either of these objects can be passed to a method that accepts IVehicle as a parameter.

If you had subsequent code that used Car or Bike specific operations that were used, then it would be advantageous to declare them as Car or Bike. The Car and Bike specific operations would be available for each of the relevant objects, and both would be usable (i.e. could be passed) as IVehicle.

When I create an object from a class that extends a specific interface, can I use this object in the place where I use this interface?

Yes, you can do that.
Interfaces are a way in Java to avoid multiple inheritance, i.e. declaring a class Foo to extend a class Bar and implement an interface Bar means that we have a "is a" relationship between Foo and Bar/Baz. So, "Foo is a Bar" and "Foo is a Baz" are true or in your case Final is a One. So, if a type is a subtype (or in Java implements an interface) the subtype can be used in place of the type or the interface (see the Liskov substitution principle).

When you declare a method m1(One one), you require the first parameter to be of type One and as Final is a One this is obviously true.

Please note, that even though you pass in an object of type Final the method only "sees" the interface part of the object without casting it.



Related Topics



Leave a reply



Submit