Is there more to an interface than having the corr

2018-12-31 19:31发布

So lets say I have this interface:

public interface IBox
{
   public void setSize(int size);
   public int getSize();
   public int getArea();
  //...and so on
}

And I have a class that implements it:

public class Rectangle implements IBox
{
   private int size;
   //Methods here
}

If I wanted to use the interface IBox, i can't actually create an instance of it, in the way:

public static void main(String args[])
{
    Ibox myBox=new Ibox();
}

right? So I'd actually have to do this:

public static void main(String args[])
{
    Rectangle myBox=new Rectangle();
}

If that's true, then the only purpose of interfaces is to make sure that the class which implements an interface has got the correct methods in it as described by an interface? Or is there any other use of interfaces?

17条回答
时光乱了年华
2楼-- · 2018-12-31 20:06

This is the reason why Factory Patterns and other creational patterns are so popular in Java. You are correct that without them Java doesn't provide an out of the box mechanism for easy abstraction of instantiation. Still, you get abstraction everywhere where you don't create an object in your method, which should be most of your code.

As an aside, I generally encourage people to not follow the "IRealname" mechanism for naming interfaces. That's a Windows/COM thing that puts one foot in the grave of Hungarian notation and really isn't necessary (Java is already strongly typed, and the whole point of having interfaces is to have them as largely indistinguishable from class types as possible).

查看更多
呛了眼睛熬了心
3楼-- · 2018-12-31 20:10

What makes interfaces useful is not the fact that "you can change your mind and use a different implementation later and only have to change the one place where the object is created". That's a non-issue.

The real point is already in the name: they define an interface that anyone at all can implement to use all code that operates on that interface. The best example is java.util.Collections which provides all kinds of useful methods that operate exclusively on interfaces, such as sort() or reverse() for List. The point here is that this code can now be used to sort or reverse any class that implements the List interfaces - not just ArrayList and LinkedList, but also classes that you write yourself, which may be implemented in a way the people who wrote java.util.Collections never imagined.

In the same way, you can write code that operates on well-known interfaces, or interfaces you define, and other people can use your code without having to ask you to support their classes.

Another common use of interfaces is for Callbacks. For example, java.swing.table.TableCellRenderer, which allows you to influence how a Swing table displays the data in a certain column. You implement that interface, pass an instance to the JTable, and at some point during the rendering of the table, your code will get called to do its stuff.

查看更多
余生无你
4楼-- · 2018-12-31 20:10

Interfaces allow statically typed languages to support polymorphism. An Object Oriented purist would insist that a language should provide inheritance, encapsulation, modularity and polymorphism in order to be a fully-featured Object Oriented language. In dynamically-typed - or duck typed - languages (like Smalltalk,) polymorphism is trivial; however, in statically typed languages (like Java or C#,) polymorphism is far from trivial (in fact, on the surface it seems to be at odds with the notion of strong typing.)

Let me demonstrate:

In a dynamically-typed (or duck typed) language (like Smalltalk), all variables are references to objects (nothing less and nothing more.) So, in Smalltalk, I can do this:

|anAnimal|    
anAnimal := Pig new.
anAnimal makeNoise.

anAnimal := Cow new.
anAnimal makeNoise.

That code:

  1. Declares a local variable called anAnimal (note that we DO NOT specify the TYPE of the variable - all variables are references to an object, no more and no less.)
  2. Creates a new instance of the class named "Pig"
  3. Assigns that new instance of Pig to the variable anAnimal.
  4. Sends the message makeNoise to the pig.
  5. Repeats the whole thing using a cow, but assigning it to the same exact variable as the Pig.

The same Java code would look something like this (making the assumption that Duck and Cow are subclasses of Animal:

Animal anAnimal = new Pig();
duck.makeNoise();

anAnimal = new Cow();
cow.makeNoise();

That's all well and good, until we introduce class Vegetable. Vegetables have some of the same behavior as Animal, but not all. For example, both Animal and Vegetable might be able to grow, but clearly vegetables don't make noise and animals cannot be harvested.

In Smalltalk, we can write this:

|aFarmObject|
aFarmObject := Cow new.
aFarmObject grow.
aFarmObject makeNoise.

aFarmObject := Corn new.
aFarmObject grow.
aFarmObject harvest.

This works perfectly well in Smalltalk because it is duck-typed (if it walks like a duck, and quacks like a duck - it is a duck.) In this case, when a message is sent to an object, a lookup is performed on the receiver's method list, and if a matching method is found, it is called. If not, some kind of NoSuchMethodError exception is thrown - but it's all done at runtime.

But in Java, a statically typed language, what type can we assign to our variable? Corn needs to inherit from Vegetable, to support grow, but cannot inherit from Animal, because it does not make noise. Cow needs to inherit from Animal to support makeNoise, but cannot inherit from Vegetable because it should not implement harvest. It looks like we need multiple inheritance - the ability to inherit from more than one class. But that turns out to be a pretty difficult language feature because of all the edge cases that pop up (what happens when more than one parallel superclass implement the same method?, etc.)

Along come interfaces...

If we make Animal and Vegetable classes, with each implementing Growable, we can declare that our Cow is Animal and our Corn is Vegetable. We can also declare that both Animal and Vegetable are Growable. That lets us write this to grow everything:

List<Growable> list = new ArrayList<Growable>();
list.add(new Cow());
list.add(new Corn());
list.add(new Pig());

for(Growable g : list) {
   g.grow();
}

And it lets us do this, to make animal noises:

List<Animal> list = new ArrayList<Animal>();
list.add(new Cow());
list.add(new Pig());
for(Animal a : list) {
  a.makeNoise();
}

The advantage to the duck-typed language is that you get really nice polymorphism: all a class has to do to provide behavior is provide the method. As long as everyone plays nice, and only sends messages that match defined methods, all is good. The downside is that the kind of error below isn't caught until runtime:

|aFarmObject|
aFarmObject := Corn new.
aFarmObject makeNoise. // No compiler error - not checked until runtime.

Statically-typed languages provide much better "programming by contract," because they will catch the two kinds of error below at compile-time:

// Compiler error: Corn cannot be cast to Animal.
Animal farmObject = new Corn();  
farmObject makeNoise();

--

// Compiler error: Animal doesn't have the harvest message.
Animal farmObject = new Cow();
farmObject.harvest(); 

So....to summarize:

  1. Interface implementation allows you to specify what kinds of things objects can do (interaction) and Class inheritance lets you specify how things should be done (implementation).

  2. Interfaces give us many of the benefits of "true" polymorphism, without sacrificing compiler type checking.

查看更多
大哥的爱人
5楼-- · 2018-12-31 20:11

the only purpose of interfaces is to make sure that the class which implements an interface has got the correct methods in it as described by an interface? Or is there any other use of interfaces?

I am updating the answer with new features of interface, which have introduced with java 8 version.

From oracle documentation page on summary of interface :

An interface declaration can contain

  1. method signatures
  2. default methods
  3. static methods
  4. constant definitions.

The only methods that have implementations are default and static methods.

Uses of interface:

  1. To define a contract
  2. To link unrelated classes with has a capabilities (e.g. classes implementing Serializable interface may or may not have any relation between them except implementing that interface
  3. To provide interchangeable implementation e.g. strategy pattern
  4. Default methods enable you to add new functionality to the interfaces of your libraries and ensure binary compatibility with code written for older versions of those interfaces
  5. Organize helper methods in your libraries with static methods ( you can keep static methods specific to an interface in the same interface rather than in a separate class)

Some related SE questions with respect to difference between abstract class and interface and use cases with working examples:

What is the difference between an interface and abstract class?

How should I have explained the difference between an Interface and an Abstract class?

Have a look at documentation page to understand new features added in java 8 : default methods and static methods.

查看更多
萌妹纸的霸气范
6楼-- · 2018-12-31 20:13

you could do

Ibox myBox = new Rectangle();

that way you are using this object as Ibox and you don't care that its really Rectangle .

查看更多
余生无你
7楼-- · 2018-12-31 20:14

WHY INTERFACE??????

It starts with a dog. In particular, a pug.

The pug has various behaviors:

public class Pug { 
private String name;
public Pug(String n) { name = n; } 
public String getName() { return name; }  
public String bark() { return  "Arf!"; } 
public boolean hasCurlyTail() { return true; } }

And you have a Labrador, who also has a set of behaviors.

public class Lab { 
private String name; 
public Lab(String n) { name = n; } 
public String getName() { return name; } 
public String bark() { return "Woof!"; } 
public boolean hasCurlyTail() { return false; } }

We can make some pugs and labs:

Pug pug = new Pug("Spot"); 
Lab lab = new Lab("Fido");

And we can invoke their behaviors:

pug.bark() -> "Arf!" 
lab.bark() -> "Woof!" 
pug.hasCurlyTail() -> true 
lab.hasCurlyTail() -> false 
pug.getName() -> "Spot"

Let's say I run a dog kennel and I need to keep track of all the dogs I'm housing. I need to store my pugs and labradors in separate arrays:

public class Kennel { 
Pug[] pugs = new Pug[10]; 
Lab[] labs = new Lab[10];  
public void addPug(Pug p) { ... } 
public void addLab(Lab l) { ... } 
public void printDogs() { // Display names of all the dogs } }

But this is clearly not optimal. If I want to house some poodles, too, I have to change my Kennel definition to add an array of Poodles. In fact, I need a separate array for each kind of dog.

Insight: both pugs and labradors (and poodles) are types of dogs and they have the same set of behaviors. That is, we can say (for the purposes of this example) that all dogs can bark, have a name, and may or may not have a curly tail. We can use an interface to define what all dogs can do, but leave it up to the specific types of dogs to implement those particular behaviors. The interface says "here are the things that all dogs can do" but doesn't say how each behavior is done.

public interface Dog 
{
public String bark(); 
public String getName(); 
public boolean hasCurlyTail(); }

Then I slightly alter the Pug and Lab classes to implement the Dog behaviors. We can say that a Pug is a Dog and a Lab is a dog.

public class Pug implements Dog {
// the rest is the same as before } 

public class Lab implements Dog { 
// the rest is the same as before 
}

I can still instantiate Pugs and Labs as I previously did, but now I also get a new way to do it:

Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido");

This says that d1 is not only a Dog, it's specifically a Pug. And d2 is also a Dog, specifically a Lab. We can invoke the behaviors and they work as before:

d1.bark() -> "Arf!" 
d2.bark() -> "Woof!" 
d1.hasCurlyTail() -> true 
d2.hasCurlyTail() -> false 
d1.getName() -> "Spot"

Here's where all the extra work pays off. The Kennel class become much simpler. I need only one array and one addDog method. Both will work with any object that is a dog; that is, objects that implement the Dog interface.

public class Kennel {
Dog[] dogs = new Dog[20]; 
public void addDog(Dog d) { ... } 
public void printDogs() {
// Display names of all the dogs } }

Here's how to use it:

Kennel k = new Kennel(); 
Dog d1 = new Pug("Spot"); 
Dog d2 = new Lab("Fido"); 
k.addDog(d1); 
k.addDog(d2); 
k.printDogs();

The last statement would display: Spot Fido

An interface give you the ability to specify a set of behaviors that all classes that implement the interface will share in common. Consequently, we can define variables and collections (such as arrays) that don't have to know in advance what kind of specific object they will hold, only that they'll hold objects that implement the interface.

查看更多
登录 后发表回答