一文讲透抽象类和接口

什么是抽象类和接口

抽象类:简而言之,用abstract关键词修饰的类就是抽象类,抽象类不能创建实例对象,即不能new对象。

接口:接口就是一种特殊的抽象类,接口中的所有方法都必须是抽象的且默认是public abstaract类型的。

接口的思想是什么

Java为什么在有了抽象类还需要提出接口?

因为抽象类依然没有摆脱类的概念,也就是说抽象类还必须由继承它的子类去实现抽象类中的抽象方法,本质上还是面向对象中的继承思想,而在现实世界中继承的关系虽然随处可见,但更多的思想是“对某种功能的实现“,比如客户提出我想要一个可以通信的工具,于是很多商家针对这种需求开发了对讲机,手机,固话等,可以明显的发现对讲机,手机,固话并不是对通信工具的继承,因为通信工具甚至没有一个具体的概念,也就是说它的抽象层次非常高,仅仅只是对”通信“这个功能的描述,而如果是传统的类就需要定义具体的属性,方法等。

所以,继面向对象后Java提出了面向接口编程,接口只定义模块之间的通信契约,而抽象类在代码实现方面发挥了具体作用,两者的应用范围是不一样的。

在jdk源码中随处可见的更多的是接口和抽象类,Java用接口的方式间接的实现了“多继承”,而声明接口创建实现类也是多态的一种体现。

public interface Signal{}
public SignalImpl implements Signal{}
public class Test(){
    Signal signal = new SignalImpl();
}

深入两者的各种区别

1.抽象类可以有构造方法,接口中不能有。

2.抽象类中可以有普通成员变量,接口中不能有。

3.抽象类可以包含非抽象的普通方法,接口在jdk中也可以,但必须用default修饰方法。

public interface Test {
        default int sum(int i,int j) {
        return i * j;
    }
}

但不推荐这么做,应该尽可能的写成

public interface Test {
        int sum(int i,int j);        
    }
}

以供实现类去实现这个方法。

4.抽象类中的抽象方法的访问类型可以是public,protected,默认,但静态抽象方法不能是默认的,而接口默认即为public abstract。

5.抽象类中可以包含静态方法,但接口中不能包含静态方法。

6.抽象类和接口中都可以包含静态成员变量,抽象类中静态成员变量访问类型可以任意,但接口中定义的成员变量只能是public static final类型,并且默认如此。

7.一个类可以实现多个接口,但只能继承一个抽象类。

一个抽象类的经典应用

模板方法设计模式是抽象类的一个典型应用,假设某个项目中所有的Servlet类都要 用相同的方式进行权限判断,记录访问日志,异常处理,那么就可以定义一个抽象的基类,在抽象基类的service方法中完成所有的逻辑。

例如:

localhost:8080/store/productServlet?method=addProduct

我们可以在访问productServlet传入一个方法addProduct,定义一个BaseServlet继承自HttpServlet抽象类。

采用底层字节码技术就可以实现通用的逻辑设计

public class abstract BaseServlet extends HttpServlet {
    @Override
    public void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {

        // localhost:8080/store/ProductServlet?method=findProductByPid&pid=1
        String method = req.getParameter("method");

        if (null == method || "".equals(method) || method.trim().equals("")) {
            method = "execute";
        }

        Class clazz = this.getClass();
        try {
            Method md = clazz.getMethod(method, HttpServletRequest.class, HttpServletResponse.class);
            if(null!=md){
                String jspPath = (String)md.invoke(this, req, resp);
                if (null != jspPath) {
                    req.getRequestDispatcher(jspPath).forward(req, resp);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    // 默认方法
    public String execute(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        return null;
    }
public class ProductServlet extends BaseServlet {
    public String findProductByPid(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        //获取商品pid
        String pid = req.getParameter("pid");
        //根据商品pid查询商品信息
        IProductService prodectService = new ProductServiceImpl();
        Product product = prodectService.findByProductByPid(pid);
        //将获取到的商品放入request
        req.setAttribute("product", product);
        //转发/jsp/product_info.jsp
        return "/jsp/product_info.jsp";
    }
}

如此一来就不用直接继承自HttpServletRequest写大量的doGet,doPost方法,看起来就立马清爽了许多。


  转载请注明: MyBlog 一文讲透抽象类和接口

 上一篇
递归和尾递归 递归和尾递归
一.什么是尾递归在之前的的第一篇文章中深入的探讨了什么递归,并在文末引出了一种新的递归方式:尾递归。 接下来我们先给出定义:如果一个函数中所有递归形式的调用都出现在函数的末尾,即当递归调用是整个函数体中最后执行的语句且它的返回值不属于表达式
2019-06-15 统行
下一篇 
一文讲透hashCode和equals方法 一文讲透hashCode和equals方法
本文主要回答一下几个问题,意在消除所有关于HashCode和equals方法的模糊地带,彻底掌握这个知识点,虽然HashCode和equals是Java中的基础概念但是包含的内容却一点也不少,所谓基础不牢,地动山摇,所以大家还是重视。 0.
2019-03-13 统行
  目录