• java的类继承(与c++对比)


    1. interface的引入

      使用interface来定义某一类通用操作,而又不强制规定其实现,对于Java的流行真是太重要了。  

      以JDBC举例。在Java之前,C++与数据库建立连接,常用的一个技术是OLEDB。这个技术我刚才搜索了一下,已经找不到太有效的内容了。我只记得开发比较复杂,如果我的应用要使用不同的数据库,就得为不同的数据库编写适配的代码。这是一件很头疼的事情。

      JDBC是怎么做的呢?java 提供了一个名为 java sql 的包,大家可以去看一下源码,这个包里的Statement, ResultSet 等等其实都是 interface。这些 interface 就定义了个标准,每个数据库厂商要支持Java连接,就得遵守这个标准。就是说,Oracle,要支持Java连接,就得提供自己的JDBC库,mysql要支持Java连接,也不例外,也得提供自己的JDBC库。这些由厂商提供的库,都严格遵守JDBC的标准。那么,我们在写数据库应用的时候,就使用这些标准的接口进行编程,当需要换一个数据库的时候,只需要换成这个数据库的JDBC就行了。我们看具体的例子:

    public class MysqlExample {
        public static void main(String[] args) throws Exception {
            Connection conn = null;
            String sql;
            String url = "jdbc:mysql://localhost:3306/javademo?" + "user=root&password=root&useUnicode=true&characterEncoding=UTF8";
     
            try {
                Class.forName("com.mysql.jdbc.Driver");
                conn = DriverManager.getConnection(url);
                Statement stmt = conn.createStatement();
                sql = "create table student(NO char(20),name varchar(20),primary key(NO))";
                int result = stmt.executeUpdate(sql);
                if (result != -1) {
                    sql = "select * from student";
                    ResultSet rs = stmt.executeQuery(sql);                
                    while (rs.next()) {
                        System.out.println(rs.getString(1) + "	" + rs.getString(2));
                    }
                }
            } catch (SQLException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                conn.close();
            }
         }
     }

    上面这个程序中除了创建连接的URL,其他的地方都是遵守JDBC标准,而与具体的数据库没有关系了。这样一来,我们就可以为不同的数据库连接只写一份代码了。有了JDBC标准,数据库的具体实现与应用程序就真正做到了解耦。而JDBC标准,正是由 java.sql 这个package 里定义的各个 interface 来具体体现的。

    2. 多态

    其实在Java之前,大规模流行的面向对象编程语言,大概只有C++了。Java中有多种针对C++的改进,多态就是其中之一。对比两段代码。

    #include<iostream>
    using namespace std;
    
    class Shape {
    public:
    //  virtual void draw() {
        void draw() {
            cout << "draw Shape" << endl;
        }   
    };
    
    class Circle : public Shape {
    public:
    //  virtual void draw() {
        void draw() {
            cout << "draw Circle" << endl;
        }   
    };
    
    int main() {
        Shape * s = new Circle();
        s->draw();
    }

    这段C++代码的输出是"draw Shape"。要使得它输出"draw Circle",就要把draw函数变成virtual,如注释中所写。这个功能,看上去使得C++的类机制更加灵活,因为静态绑定和运行时动态绑定两种机制都支持,而我们知道静态绑定,运行效率更高,C++程序可以自由地根据情况来使用两种绑定机制。

    Java抛弃了静态绑定。Java认为,既然实现了继承,并且在子类中又提供了实现,那就应该是覆写。在Java中实现同样的代码,看看效果。

    public class Main {
        public static void main(String args[]) throws IOException {
            Shape s = new Circle();
            s.draw();
        }   
    }
    
    class Shape {
        public void draw() {
            System.out.println("draw Shape");
        }   
    }
    
    class Circle extends Shape {
        public void draw() {
            System.out.println("draw Circle");
        }   
    }

    嗯,这次输出的是draw Circle。用C++的术语来说,Java中所有的成员方法都自动是virtual的。所有的子类方法会自动覆写父类的同名方法。

    3. 抽象类和抽象方法

    这一点,其实没什么特别的,C++中,如果一个类中定义了纯虚函数(没有实现,只有声明的虚函数),那这个类也是不能被实例化的。Java的类中,如果定义了一个抽象方法(以abstract修饰,不提供方法实现),那这个类就是抽象类,也不能实例化的。这一点上,两者是对应的。例如:

    public class Main {
        public static void main(String args[]) throws IOException {
            Shape s = new Circle();
            s.draw();
        }   
    }
    
    abstract class Shape {
        public void draw() {
            System.out.println("draw Shape");
        }   
    
        public abstract double area();
    }
    
    class Circle extends Shape {
        public void draw() {
            System.out.println("draw Circle");
        }   
    
        public double area() {
            return 3.14;
        }   
    }

    1. Shape类前面的abstract不加,会报什么错?

    如果Shape类不加abstract,则无法拥有abstract方法.

    2. shape中的area的定义前不加abstract会怎么样? 

    如果area方法不加abstract,则必须提供该方法的实现.

    3. 如果Circle中没有实现area会怎么样?

    如果Circle类没有实现area方法,则Circle必须指定为abstract,因为从基类得到abstract方法的类要么实现该方法,要么声明为abstract类.

    4. 拒绝操作符重载

    我们提到了,Java中是拒绝操作符重载的。理由是,如果实现了这个功能,用户就会定义出奇奇怪怪不可读的操作符。这一点,我是赞同的,看看scala中的flatMap这么清晰的一个函数,变成Haskell中的(>>=),可读性确实是下降了。

    但有些地方,操作符重载也确实能提供更清晰的语法,比如BigInteger。这个类是Java中的高精度整型类。我们看一下,它的例子。

    public class Main {
        public static void main(String args[]) {
            BigInteger one = BigInteger.valueOf(1);
            BigInteger two = BigInteger.valueOf(2);
            BigInteger three = one.add(two);
            System.out.println(three);
        }   
    }

    可以看到,Java中只能用 add 来表示两个大整数的相加。如果支持了操作符重载呢?我们用C++举个例子。

    class BigInteger {
    public:
        int value;
    
        BigInteger(int v) : value(v) {}
    
        BigInteger operator + (BigInteger & that) {
            return BigInteger(this->value + that.value);
        }   
    };
    
    int main() {
        BigInteger one(1);
        BigInteger two(2);
        BigInteger three = one + two;
        cout << three.value << endl;
    }

    在这个例子中,使用+比使用add方法更简洁清晰。但是,允许了操作符重载,开发者为了图方便,就有可能写出这种东西来:

    class BigInteger {
    public:
        int value;
    
        BigInteger(int v) : value(v) {}
    
        int operator >>= (int v) {
            return this->value + v;
        }   
    };
    
    int main() {
        BigInteger one(1);
        int a = one >>= 3;
        cout << a << endl;
    }

    这就失去了操作符重载原有的简洁性,而使代码变得不可读了。在这一点上,做得比较好是Python,它限制了可以重载的操作符的类型。

    class BigInteger(object):
        def __init__(self, v): 
            self.value = v 
    
        def __add__(self, that):
            return BigInteger(self.value + that.value)

    一个定义了 __add__ 方法的类,是可以直接使用 + 操作符的。但你不能定义乱七八糟意义不明的操作符。Python中是受限的操作符重载。这是我认为的最好的机制。退而求其次,应该是Java的做法,而不是C++的做法。

  • 相关阅读:
    零基础学python-2.6 数字与字符串
    零基础学python-2.5 变量与赋值
    零基础学python-2.4 操作符
    零基础学python-2.3 注释
    js原型和原型链
    ES6数据结构Set、Map
    JS高阶函数--------map、reduce、filter
    vue-cli3.0以上项目中引入jquery的方法
    vue项目中使用echarts map报错Cannot read property 'push' of undefined nanhai.js
    js 将时间戳转成时间格式化
  • 原文地址:https://www.cnblogs.com/msymm/p/9395924.html
Copyright © 2020-2023  润新知