Java 十万个为什么

Published: 16 Sep 2014 Category: 技术

为什么要使用接口

  • 接口有利于代码复用 代码复用的关键是将变化的地方与不变的地方分离,这样,不变的地方就会得到复用。我们可以将变化的地方抽象成一个接口,这样所有实现 这个接口的类,就都可以使用不变地方的代码。

例如 Java 中的排序算法,算法的步骤是不变的,变化的是元素之间的比较方式,我们可以 将比较方式抽象成一个接口,接口中包含一个比较方法。这样,所有实现这个接口的类,都必须实现这个比较方法,之后,他们就可以复用 排序算法。接口在这里就像排序算法与其它类型之间的契约,你实现这个接口,我就让你使用我的功能。在其它编程语言中,没有接口的概念, 但是同样会使用某种方式,实现代码的利用,例如 C 语言,排序时,需要提供一个函数指针,指向一个可以比较大小的函数。Python中,可以将 比较函数作为参数,传递给排序函数。

又例如回调函数的使用,回调函数就是在一个事件发生时,要调用的函数。在GUI编程中,我们只需要为按钮添加一个事件响应函数,这个按钮被点击时,就会调用我们的函数。我们不需要编写其它代码,其它 代码都是可以复用的,框架知道按钮点击时要调用一个函数,但是不知道这个函数具体内容。具体内容我们是知道的。这其实也是将变与不变分离 的方式。在Java中,使用接口就可以实现回调。在其它编程语言中,使用函数指针也可以实现回调。

  • 接口有利于解耦 前面说的代码复用,用抽象类也能实现,那为什么还要用接口呢?如果使用抽象类,那么所有需要排序的类都要继承这个抽象类,由于 Java 中没有 多继承,所以这些类就不能继承其它类。而使用接口就不会有这种问题。接口实际上降低了类与类之间的耦合关系,只需要实现几个方法,不进入 继承体系的时候,就没必要去继承。

为什么要使用内部类

  • 内部类可以访问外部类中的数据
    例如迭代器的实现,就是通过内部类,它可以访问外部类,在外部类的数据上迭代,也有自己的私有变量,从而可以得到不同状态的迭代器。
  • 内部类可以对其它类隐藏起来
  • 可以实现匿名类
    就一个字,方便!就定义一个对象,就没必要声明一个类了。

为什么使用栈式指令集

栈式指令集简洁,不必指定源与地址,编译器易实现。不受机器寄存器数目影响,容易移植。但所有操作都需要通过栈,需要更多的 load/store, 这意味着更多的指令分派与内存访问。

寄存器型数据访问快,利于优化程序运行速度。但代码长度会变长。

为什么需要反射

反射提供了在运行时动态操作类的能力,例如,根据类的名称加载类,创建类的实例,分析类中的域,方法,参数,构造器。

    public void testReflect(String className) throws ClassNotFoundException,
            InstantiationException, IllegalAccessException {

        Class<?> rfClass = Class.forName(className);
        Object rfObj = rfClass.newInstance();
        System.out.println("Create rfObj by " + rfObj.getClass());

        Class<?> fooClass = rfClass;

        /* get public fields */
        Field[] fields = fooClass.getFields();
        for (Field fd : fields) {
            System.out.println(fd.getName());
        }

        /* get public method, include extends */
        Method[] methods = fooClass.getMethods();
        for (Method md : methods) {
            System.out.println(md.getName() + " paramsN: "
                    + md.getParameterCount());
        }

        /* get all methods, exclude extends methods */
        Method[] declaredMethods = fooClass.getDeclaredMethods();
        for (Method md : declaredMethods) {
            System.out.println(md.getName() + "is public:"
                    + Modifier.isPublic(md.getModifiers()));
        }
    }