`
thinkingmt
  • 浏览: 24622 次
  • 性别: Icon_minigender_1
  • 来自: 桂林
社区版块
存档分类
最新评论

Deeper understanding of Abstract Class & Interface

阅读更多

 

In Java, abstract class and interface are subtle to distinguish because they have a lot features in common.

 

Firstly, I want to illustrate some obvious differences between them:

 

From the keyword perspective: 

The keyword of applying abstract class and interface are extends and implements respectively. eg:

 

 

public abstract class SuperClass
{

}

public class SubClass extends SuperClass
{

}

 

 

 

public interface ImplentedInterface
{

}

public class ImplentingClass implements ImplentedInterface
{
   
}

 

 

 

 

The keywork "extends" used for inherienting an abstract class is the same as inherienting a normal class, because the subclass will inherient some attributes and method from superclass, and override (here, I think "implement" is suitable than "override", because abstract methods are not implemented, there is no content to be overridden) the abstract methods in superclass (of course, the non-abstract method can also be overridden, and note that this time, "override" matches its meaning, because non-abstract method has previous functionality).

 

But a class implements an interface is doing something different, the implementing class can not inherient 'legacy' from interface, more than that, the implementing class need to implement the abstract methods which defined in interface, so the keyword 'implements' is very appropriate when we refer to interface.

 

Another couple of keyword: class and interface, anyway, abstract class class contain 'class' which decorated as 'abstract' whereas from keyword 'interface' you cannot recognize this entity is a class from semantics.

 

 

 

 

From the entity structure perspective:

Abstract class can have constructors which used for initialising the fields of the object (it is weird that abstract class have a constructor because abstract class itself can not be instantiated, to see why is going on? see my another article : Deeper understanding how constructor works.).

 

 

 

public abstract class SuperClass
{
    public SuperClass()
    {
    
    }
    
    public SuperClass(int x)
    {
        
    }
}

 

 

 

But interface can not have constructor. There are many conventions about interface so the declaration of attributes and method is more simple in interface. (like : all the attribute is implys to be PUBLIC, FINAL and STATIC. it's a constant.). 

 

What's more, all methods in interface is implied to be abstract, it is absoutely abstract body whereas abstract class can has some concrete part.

 

Finally, an interface only extends (NOT implements) from other interfaces, but a abstract class has more options: inherient from other class and implements interfaces.

 

 

public class c1 extends c2 implements i3, i2, i4
{

}


public interface i1 extends i4, i2, i3
{

}

 

 

 

From the use purpose of perspective:

Java allows single inherientance but multiple implementation. which means that a subclass can at most inherient one class, either norclass or abstract class. At the same time, implements several interfaces.

 

Abstract class provides a template (shared attributes and methods) and design (abstract methods) for subclass. Abstract class is more flexible and practical class which reflect the OO characteristics better than normal class (inherit from an abstract class implies inheritance and polymorphism, but inherit from a normal class can only implies inheritance if the subclass doesn't override the non-abstract methods in baseclass (if the subclass override some mthods, normal class can represent polymorphism as well, the difference is that polymorphism is mandatory in abstract class inheritence but optional in normal class inheritence, owing to abstract methods must be overridden in subclass)).

 

 

Here is a scenario just for fun:

Abstract class: "My kids (refers to subclass), here I provide some treasure [non-abstract methods], which all of you can directly inherit without any cost, if you do so, all of you would inherit same heritage; and you can also modify it if you want, where your heritage has same name (method signature) with others but different content (functionality). Additionally, there are some un-implemented treasure [abstract mehods], where you must finish them by yourself and it is mandatory to do if you inherit from me, the way you implement them is your choice, your can just walk through them (public void unimplementedMethod(){// nothing included  }), I won't blame on it because maybe those unimplemented methods make no sense for you, but even so, you must finish them; or you can truely realise value to these un-implemented methods(public void unimplementedMethod(){// some commands that really do something, make the method name worthy.  }), I like this more because those successors take full advantage of my legacy and they really need every part of my legacy!)."

 

 

public abstract class BigRich  
{  
      public BigRich()  
      {  
  
      }  
  
       public void treasure()  
       {  
             String treasure = "the original treasure";  
       }  
  
       public abstract void unImplementedTreasure();
}


public class LazySuccessorOrInefficientSuccessor extends BigRich
{  
      public LazySuccessorOrInefficientSuccessor()  
      {  
            
      }  
  
      public void unImplementedTreasure()  
      {  
  
      }  
}  


public class EfficientSuccessor extends BigRich
{  
      public EfficientSuccessor()  
      {  
          
      }  
  
      public void treasure()  
      {  
            //NOTE: it is not to say only if override the original methods can be regard as efficient. If the subclass need exactly the original method where the base class has, write nothing is more efficient!  
            //In terms of the concrete method, efficient or not is depends on the situation.   
            String treasure = "the new treasure which is modified";  
      }  
  
      public void unImplementedTreasure()  
      {  
             String unimplementedtreasure = "implemented now!";  
      }  
}  

 

 

 

 

Interface is more like a policy or contract that apply to a class, you can own the ability which is declared by me and determine how this method is operated but you need to implement it by youself, interface do nothing except provide a signature. Here is how Oracle describes interfaces:

 

 

https://docs.oracle.com/javase/tutorial/java/concepts/interface.html 写道

 

Methods form the object's interface with the outside world; the buttons on the front of your television set, for example, are the interface between you and the electrical wiring on the other side of its plastic casing. You press the "power" button to turn the television on and off.

In its most common form, an interface is a group of related methods with empty bodies.

Implementing an interface allows a class to become more formal about the behavior it promises to provide. Interfaces form a contract between the class and the outside world, and this contract is enforced at build time by the compiler. If your class claims to implement an interface, all methods defined by that interface must appear in its source code before the class will successfully compile.


 

 

What's more, interfaces are like a peripherial -able injector to repair the drawback of single inheritance. As we know, if a method needs a parameter of a certain class, we can simply provide a instance of its subclass. Interface provides this convenience too, If a method need a parameter of certain interface type, we can supply an instance of class that implements the interface. Here is a reference from Oracle:

 

 

https://docs.oracle.com/javase/tutorial/java/IandI/interfaceAsType.html 写道

 

When you define a new interface, you are defining a new reference data type. You can use interface names anywhere you can use any other data type name. If you define a reference variable whose type is an interface, any object you assign to it must be an instance of a class that implements the interface.

These methods work for any "relatable" objects, no matter what their class inheritance is. When they implement Relatable, they can be of both their own class (or superclass) type and a Relatable type. This gives them some of the advantages of multiple inheritance, where they can have behavior from both a superclass and an interface.

 

 

Here is a scenario which interface showcase the power of interface:

A company wants to perform all the print tasks in their devices that have the print function, which include printer and fax machine. Use java code and array concept to simulate this scenario.

 

The first solution is to define two classes, one is Printer and another is FaxMachine, where both of them has a method print(), which used for perform the print task. Perform all the print tasks looks easy, we just need to invoke the print() of every Printer and FaxMachine object. For convenient, we can use declare two arrays which one is a list of Printers and another is a list of FaxMachines, use two loops to invoke the print() method of each member. But there is a drawback for this solution, if there are more than two types of devices can perform print tasks, for example, 10 types of devices can print stuff, then, for this solution, we must declare 10 loops to perform all the tasks, but they all doing actually similar tasks, so it is inefficient and repeative.

 

The second solution is to define a interface called Printable which include a method print(), both Printer and FaxMachine class implements the abstract method print() from Printable. This time, we can just define one array and use one loop to perform all the print tasks using the below approach:

 

 

public interface Printable
{
    public void print();
}




public class Printer implements Printable
{
    public void print()
    {
        System.out.println("print stuff for printer");
    }
}




public class FaxMachine implements Printable
{
    public void print()
    {
        System.out.println("print stuff for fax machine");
    }
}




/**
 * In this test class, 10 print tasks is created, even for printer print      
 * task, odd for fax print task.
 */
public class ConductPrintTask
{
    public static void  main(String[] args)
    {
        Printable printTasks[] = new Printable[10];
        
        for(int i = 0; i < printTasks.length ; i ++)
        {
            if (i%2 != 0)
            {
                printTasks[i] = new Printer();
            }
            else
            {
                printTasks[i] = new FaxMachine();
            }
            
            printTasks[i].print();
        }
    }
}




//The output of running the main method:
//print stuff for fax machine
//print stuff for printer
//print stuff for fax machine
//print stuff for printer
//print stuff for fax machine
//print stuff for printer
//print stuff for fax machine
//print stuff for printer
//print stuff for fax machine
//print stuff for printer




 

 

In the above code, we don't use inheritence but implementation is because printer and fax machine is actually have little features in common, the only same is both of them can print stuffs, so inheritence is not approapriate. But this situation is suitable for interface. The interface Printable converges all the instances who implement it, the converge point is the abstract method print().

 

There are many other useful function of interface, I haven't noticed and learned. Welcome supply!

 

 

From the class relevance perspective:

Abstract class only related to classes that have a " is a " relationship with the superclass. By constrast, interface can relate to a more wider scale of instances even these instances have no common at all.(of course they have at least one in common is that they all implement a same interface).

 

One word, both abstract class and interface only know the derived stuff from them, but owing to interface are not part of class hierachy(although they work in combination with class), interface controls instances which do not have a same root(inherient from a same superclass) whereas abstract class only control their family.

 

 

 

What is similar?

 

Both abstract class and interface define abstract method and leave the implementation to the other classes.

 

Both abstract class and interface can provide great polymorphic features.

 

Both abstract class and interface reflect polymorphism by dynamic binding.

 

 

A a = B b();
A a2 = C c();

a.process(); //output is b's output;
a2.process(); //output is c's output;

 

 

 

How to decide which appraoch to use?

 

Here are some suggestions from Orable to help you decide how to choose between abstract classes and interfaces during the development:

 

 

http://docs.oracle.com/javase/tutorial/java/IandI/abstract.html 写道

 

Abstract classes are similar to interfaces. You cannot instantiate them, and they may contain a mix of methods declared with or without an implementation. However, with abstract classes, you can declare fields that are not static and final, and define public, protected, and private concrete methods. With interfaces, all fields are automatically public, static, and final, and all methods that you declare or define (as default methods) are public. In addition, you can extend only one class, whether or not it is abstract, whereas you can implement any number of interfaces.

Which should you use, abstract classes or interfaces?

Consider using abstract classes if any of these statements apply to your situation:
 - You want to share code among several closely related classes.
 - You expect that classes that extend your abstract class have many common methods or fields, or require access modifiers other than public (such as protected and private).
 - You want to declare non-static or non-final fields. This enables you to define methods that can access and modify the state of the object to which they belong.
Consider using interfaces if any of these statements apply to your situation:
 - You expect that unrelated classes would implement your interface. For example, the interfaces Comparable and Cloneable are implemented by many unrelated classes.
 - You want to specify the behavior of a particular data type, but not concerned about who implements its behavior.
 - You want to take advantage of multiple inheritance of type.
An example of an abstract class in the JDK is AbstractMap, which is part of the Collections Framework. Its subclasses (which include HashMap, TreeMap, and ConcurrentHashMap) share many methods (including get, put, isEmpty, containsKey, and containsValue) that AbstractMap defines.

An example of a class in the JDK that implements several interfaces is HashMap, which implements the interfaces Serializable, Cloneable, and Map<K, V>. By reading this list of interfaces, you can infer that an instance of HashMap (regardless of the developer or company who implemented the class) can be cloned, is serializable (which means that it can be converted into a byte stream; see the section Serializable Objects), and has the functionality of a map. In addition, the Map<K, V> interface has been enhanced with many default methods such as merge and forEach that older classes that have implemented this interface do not have to define.

Note that many software libraries use both abstract classes and interfaces; the HashMap class implements several interfaces and also extends the abstract class AbstractMap.

 

 

 

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics