From: Android Advanced Study Guide

Key contributors:

  • Milo
  • Struggle
  • shixinzhang

After reading this article, you will know:

  • background
  • What are abstract classes and interfaces
  • Features and differences
    • Abstract class characteristics
    • Interface features
    • chestnuts
    • summary
  • How to choose
  • Abstraction and polymorphism
    • Interface oriented programming
    • polymorphism
    • Inheritance and composition
  • conclusion
  • Thanks

background

Hello, this article is the first in the Java Basics series, part one of the Android Advanced Skill Tree Project.

Distance on a trailer “Java based ramming series online notice” in the past for a long time, so slowly, because we do this activity, in addition to guarantee knowledge comprehensive, complete, also want to let every article has its own thinking, as far as possible to combine knowledge and practice, efforts to let the readers to read. Every friend has a job, and every knowledge point needs to go through many processes, such as thinking, learning, writing, submission, review, modification, editing, publishing, etc., so the overall time will be slower. I apologize to you first.

“Java Foundation Series” has about 12 chapters, the main contents are as follows. :

  1. Abstract classes and interfaces
  2. The inner class
  3. The modifier
  4. The split open a case using the
  5. annotations
  6. reflection
  7. The generic
  8. abnormal
  9. A collection of
  10. IO
  11. string
  12. other

In the first article, we’ll talk about abstract classes and interfaces.

“Abstract classes and interfaces” sound very common, some friends will think: this is too basic, what to say, you are fooling me again.

In fact, not once did I get asked this question in an interview:

  • What’s the difference between abstract classes and interfaces?
  • When is an abstract class created? When is an interface created?
  • How to choose when designing a framework?

I like these questions, which can be answered in depth or in depth, and reflect our thinking about our daily work.

When do we create an abstract class? When will an interface be created? When you change your thinking, not only to complete the function, but to ensure the stability, flexibility and scalability of the entire project architecture, what will you choose?

In this post we try to answer those questions, and we hope you can give us your answers.

What are abstract classes and interfaces

Abstract methods are methods that use the abstract keyword modifier and only declare methods without a method body.

public abstract void f(a);// No contentCopy the code

An abstract class is a class that contains abstract methods.

If a class contains one or more abstract methods, the class must be qualified as abstract. Abstract classes may not contain abstract methods.

public abstract class BaseActivity {
    private final String TAG = this.getClass().getSimpleName(); // Abstract classes can have members

    void log(String msg){   // Abstract classes can have concrete methods
        System.out.println(msg);
    }

// abstract void initView(); // An abstract class can also have no abstract methods
}Copy the code

An interface is a special form of abstract class that uses the interface modifier.

public interface OnClickListener {
    void onClick(View v);
}Copy the code

Features and differences

Abstract class characteristics

Abstract classes are intended to be “abstract,” that is, to specify what the class “is.” The concrete implementation is uncertain and incomplete, so direct instance creation is not allowed.

  • Abstract classes are abstracted from subclasses that share the same class characteristics, which can also be described as their base class or parent class
  • The abstract method must be either public or protected (because if it is private, it cannot be inherited by subclasses, which cannot implement the method), and public by default
  • Abstract classes cannot be used to create objects
  • Abstract methods must be implemented by subclasses
  • If a class inherits from an abstract class, the subclass must implement the parent’s abstract methods, and if the subclass does not implement the parent’s abstract methods, the subclass must also be defined as an abstract class
  • Abstract classes are also useful refactoring tools because they make it easy to move public methods up the inheritance hierarchy

Interface features

Java does not allow multiple inheritance for data security, meaning that a class has only one parent class.

But interfaces are different. A class can implement multiple interfaces at the same time, regardless of whether the interfaces are related to each other, so interfaces make up for the disadvantage that abstract classes cannot inherit more than one another.

An interface is an extension of an abstract class that defines methods without a method body and requires implementers to implement them.

  • All method access permissions for the interface are automatically declared public
  • The interface can define “member variables”, which are automatically changed to public static finalStatic constants

    • Implementclass.name can be accessed directly by the class name: implementClass.name
    • Using interfaces to create constant classes is not recommended
  • A non-abstract class that implements an interface must implement all of the methods in the interface; an abstract class may not implement all of them
  • An interface cannot create an object, but can declare an interface variable for easy invocation
  • Fully decoupled, you can write more reusable code

chestnuts

I said too much, so let’s go straight to the code.

Let’s say we’re starting a new project and we need to write a bunch of activities that have some common properties and methods, so we create a base class to put those common methods in:

public class BaseActivity extends Activity {
    private final String TAG = this.getClass().getSimpleName(); 

    void toast(String msg) {   
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
    }  
    // Other repetitive tasks, such as setting the title bar, immersive status bar, checking network status, etc
}Copy the code

In this case, BaseActivity is a base class that encapsulates repeated content.

As we wrote, we found that some of our colleagues’ code was so bad that hundreds of lines of code in one method were too painful to look at. Following the principle of “separation of responsibilities”, we created some abstract methods in BaseActivity that subclasses must implement:

public abstract class BaseActivity extends Activity {
    private final String TAG = this.getClass().getSimpleName();

    @Override
    protected void onCreate(final Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(getContentViewLayoutId());

        initView(); // Initialize the layout here
        loadData(); // Load data here
    }

    /** * requires subclass implementation of the method * @return* /
    protected abstract int getContentViewLayoutId(a);protected abstract void initView(a);protected abstract void loadData(a);void toast(String msg) {
        Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); }}Copy the code

The defined abstract method access modifiers can be public protected and default, but cannot be private because subclasses would not be able to implement them.

BaseActivity now becomes an abstract class because of its abstract methods. It defines the specification and forces subclasses to conform to the standard. If abstract methods are called, rules are also made for the order of execution.

Classes that inherit from BaseActivity can keep their code as clean as the parent class by implementing these methods and providing the required content for the parent class.

public class MainActivity extends BaseActivity{

    private TextView mTitleTv;

    @Override
    protected int getContentViewLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    void initView() {
        mTitleTv = (TextView) findViewById(R.id.main_title_tv);
        mTitleTv.setOnClickListener(this);
    }

    @Override
    protected void loadData() {
        // Load data here}}Copy the code

Later, if you find a feature that is repeated more often in different activities, you can include the implementation of that feature in BaseActivity. But be careful not to add abstract methods too easily, because this will affect the previous subclasses.

As the project was writing, I found that many pages had re-requests for data based on location information changes. For ease of management, I put such code into BaseActivity again. That’s fine, but then the code that doesn’t need to be location-specific gets “polluted” and the BaseActivity becomes a hodgepodge of redundant logic.

We want to put position-dependent objects in another class, but Java only has single inheritance, so we can use interfaces.

We create an interface to represent listening on a geographic location:

interface OnLocationChangeListener {
    void onLocationUpdate(String locationInfo);
}Copy the code

The interface defaults to public and cannot use other modifiers.

Then hold a reference to this interface in a position observer:

public class LocationObserver {

    List<OnLocationChangeListener> mListeners;

    public LocationObserver setListeners(final List<OnLocationChangeListener> listeners) {
        mListeners = listeners;
        return this;
    }

    public List<OnLocationChangeListener> getListeners() {
        return mListeners;
    }

    public void notify(String locationInfo) {
        if(mListeners ! =null) {
            for(OnLocationChangeListener listener : mListeners) { listener.onLocationUpdate(locationInfo); }}}interface OnLocationChangeListener {
        voidonLocationUpdate(String locationInfo); }}Copy the code

So we implement this interface in the page we want to locate:

public class MainActivity extends BaseActivity implements View.OnClickListener.LocationObserver.OnLocationChangeListener {

    private TextView mTitleTv;

    @Override
    protected int getContentViewLayoutId() {
        return R.layout.activity_main;
    }

    @Override
    public void onClick(final View v) {
        int id = v.getId();
        if (id == R.id.main_title_tv) {
            toast("You hit title."); }}@Override
    void initView() {
        mTitleTv = (TextView) findViewById(R.id.main_title_tv);
        mTitleTv.setOnClickListener(this);
    }

    @Override
    protected void loadData() {
        // Load data here
    }

    @Override
    public void onLocationUpdate(final String locationInfo) {
        mTitleTv.setText("The current position is:"+ locationInfo); }}Copy the code

This gives MainActivity the ability to listen for position changes.

If you need to add additional functionality to MainActivity, you can create the corresponding interface and implement it.

summary

From the code example above, we can see clearly what the following figure summarizes.

Pictures from: www.jianshu.com/p/8f0a7e22b…

We can see these differences between abstract classes and interfaces:

  • Different levels of abstraction

    • An abstract class is an abstraction from a class, whereas an interface is an abstraction from behavior
    • An abstract class abstracts the class as a whole, including properties and behaviors, whereas an interface abstracts the local behavior of a class
  • Cross domain different

    • Abstract classes span domains with similar characteristics, whereas interfaces can span domains with different classes
    • Abstract classes embody an inheritance relationship that considers whether a subclass and its parent class are essentially the same class
    • Interfaces do not require the implementation of the same nature of the class and interface, there is only a “have this ability” relationship between them
  • Different design levels

    • Abstract classes are designed from the bottom up, and work repeated in subclasses is abstracted into abstract classes
    • Interfaces are top-down, defining behaviors and specifications

How to choose

Now we know that abstract classes define “what is” and can have non-abstract properties and methods; Interfaces are purer abstract classes that can implement multiple interfaces in Java, so interfaces stand for “what are you capable of?”

When making a selection, you can refer to the following points:

  • With interfaces, we get the benefits of both abstract classes and interfaces
  • So if you want to create a base class that doesn’t have any method definitions or member variables, would you rather use an interface than an abstract class anyway
  • If you know in advance that something is going to be a base class, the first option is to turn it into an interface
  • You should consider using abstract classes only when you must use method definitions or member variables

And one of the most important reasons to use interfaces: implementing interfaces allows a class to transition up to multiple base classes.

Common interfaces, such as Serializable and Cloneable, can be treated as Serializable and Cloneable if a class is implemented to represent these capabilities.

It is recommended to use both interfaces and abstract classes to ensure data security and achieve multiple inheritance.

Abstraction and polymorphism

As the saying goes: “do things leave a line, good meet in the future”.

Program development, too, is an incremental or cumulative process and cannot be perfect all at once, so we need to leave as much room as possible for later changes, which requires us to use the fabled “three characteristics of Object orientation” – inheritance, encapsulation, and polymorphism.

Whether you use abstract classes or interfaces, and ultimately separate responsibilities as much as possible, you abstract the business, that is, “programming to interfaces.”

Interface oriented programming

When making an appointment with someone in your daily life, don’t be too specific. It’s like when someone asks us when we’re free. “Around winter” is a little more flexible than “this Saturday noon.” Who knows what might happen on that Saturday.

When we write code, we aim for “the same as the same”, which can be achieved by changing the code as little as possible when requirements change.

This requires modules to rely on each other’s abstract interfaces, rather than concrete implementations.

This is known as the “dependency inversion principle” in design patterns, and dependency inversion can be implemented in three ways:

  1. Pass dependent objects through constructors

    • For example, the parameters that need to be passed in a constructor are implemented in an abstract class or interface
  2. Pass dependent objects through setter methods

    • That is, we set the parameters in the setXXX method to be abstract classes or interfaces to implement passing dependent objects
  3. Interface declarations implement dependent objects, also known as interface injection

    • That is, the parameters in the function declaration are abstract classes or interfaces to achieve the transfer of dependent objects, so as to achieve the purpose of using dependent objects directly.

As you can see, when “interface oriented programming” refers to “interfaces”, it also refers to abstract classes. In fact, it means base classes. The simpler the better.

polymorphism

Polymorphism refers to the fact that only one person is known at compile time, and exactly what kind of person needs to be determined at run time. The same parameter may have different implementations.

To ensure the system’s expansibility and flexibility, the specification can be established through abstraction and replaced by concrete objects at runtime.

There are three main ways to achieve polymorphism:

  1. Interface implementation

  2. Inherits the parent overriding method

  3. Method overloading in the same class

Either way, the caller holds the base class, and the different implementations are considered base classes to him and used as such.

This is called “upcasting,” where subclasses are called from the bottom of the inheritance relationship to the top.

Upward transformation is a process of reducing power, and compilers can help us achieve it; However, “downward transformation” is a process of strengthening capabilities, which requires strong transformation.

Take the above code for example:

public class LocationObserver {

    List<OnLocationChangeListener> mListeners;

    public LocationObserver setListeners(final List<OnLocationChangeListener> listeners) {
        mListeners = listeners;
        return this;
    }

    public List<OnLocationChangeListener> getListeners() {
        return mListeners;
    }

    public void notify(String locationInfo) {
        if(mListeners ! =null) {
            for(OnLocationChangeListener listener : mListeners) { listener.onLocationUpdate(locationInfo); }}}}Copy the code

The LocationObserver holds a reference to the OnLocationChangeListener, which can be invoked as long as the interface is implemented, regardless of whether MainActivity or another Activity is passed in at runtime.

Knowing which method to call at compile time is called “pre-binding” (also known as “static binding”) and is implemented by the compiler and linker.

Calling the correct method at run time is a process called “dynamic binding,” which requires a mechanism to call the appropriate method at run time based on the type of the object. This mechanism is implemented by virtual machines. The Invokevirtual directive resolves symbolic references to class methods in a constant pool into different references. This process is called “dynamic dispatch” and we won’t discuss the implementation.

Inheritance and composition

Just because inheritance gets a lot of emphasis in learning OOP doesn’t mean it should be used everywhere possible.

On the contrary, use it very carefully, because inherit a class, means you need to accept its everything, whether rich or poor, old or sick, you have to accept it, can you do that?

Most people can’t grow old together, so only consider it if you know you need to inherit all the methods.

One alternative to inheritance is composition.

Composition means owning everything about a class by holding a reference to it, rather than inheriting it, passing in references when it needs to call its methods, then calling them, and otherwise clearing them.

Composition is more flexible than inheritance because the relationship is looser. Inheritance represents the “IS-A” relationship, which is stronger. Composition is has-A.

One of the easiest ways to determine whether you should use composition or inheritance is to consider whether you need to transition from the new class up to the base class.

If you do need to go up, use inheritance; But if you don’t need to go back, you should remind yourself to prevent the abuse of inheritance.

conclusion

The purpose of this article is to help readers understand the characteristics and different usage scenarios of abstract classes and interfaces.

The purpose of this series is to help you systematically and completely lay a solid foundation and gradually deepen your learning. If you are already familiar with these, please do not hesitate to give your comments and point out the problems, we will do better together!

The article is sent to the wechat public number: Android evolution, welcome to pay attention to, the first time to get the new article.

Thanks

  • Ideas for Java Programming
  • www.jianshu.com/p/8f0a7e22b…