美文网首页EffectiveJava笔记
EffectiveJava第4章-类和接口

EffectiveJava第4章-类和接口

作者: wangcanfeng | 来源:发表于2017-06-18 21:18 被阅读0次

    第13条:使类和成员的可访问性最小化

    这个被称为信息隐藏或封装。它可以解耦,使模块可以独立开发、测试、优化、使用、理解和修改。可以让开发人员单独调试自己的程序,提高开发系统的速度,程序有问题的时候,可以准确的定位在哪个模块出现问题,降低了构建大型系统的风险。

    访问控制机制决定了类、接口和成员的可访问性。
    第一个规则:尽可能地使每个类或者成员不被外界访问。类和接口只有两种访问级别:包级私有(private)和公有的(public)。

    对于成员(域、方法、嵌套类和嵌套接口)有四种可能的访问级别,按访问性递增顺序罗列:

    1. 私有的(private),只有在声明该成员的顶层类内部才可以访问这个成员。
    2. 包级私有的(package-private),声明改成员的包内部的任何类都可以访问这个成员。从技术上讲,它被称为“缺省(default)访问级别”,如果没有为成员指定访问修饰符,就采用这个访问级别。
    3. 受保护的(protected),声明该成员的类的子类可以访问这个成员,并且,声明该成员的包内部的任何类也可以访问这个成员。
    4. 公有的(public),在任何地方都可以访问该成员。

    如果方法覆盖了超类的一个方法,子类中的访问级别就不允许低于超类中的访问级别。这样可以确保任何使用超类的实例的地方都可以使用子类的实例。
    接口中的方法默认就是共有的,所以一个类实现了一个接口,那么接口中所有的类方法在这个类中也都必须声明为公有的。

    实例域绝对不能是公有的(第14条:在公有类中使用访问方法而非公有域)。

    长度非零的数组总是可变的,

    public static final String[] VALUES = {};  
        //公有数组变成私有的,并增加一个公有的不可变列表
        private static final String[] VALUES = {...};
        public static final List<Thing> VALUES =               Collections.unmodifiableList(Arrays.asList(PRIVATE_VALUES));
        //或者返回私有数组的克隆
        private static final String[] VALUES = {...};
        public static final Thing[] values(){
            return PRIVATE_VALUES.clone();
        }
    }
    

    第14条:在公有类中使用访问方法而非公有域

    如果类可以在它所在的包的外部进行访问,就提供访问方法,以保留将来改变该类的内部表示法的灵活性。

    如果类是包级私有的,或者私有的嵌套类,直接暴露它的数据域并没有本质的错误。

    第15条:使可变性最小化

    不可变类只是其实例不能被修改的类,例如String,基本类型的包装类、BigInteger和BigDecimal。不可变的类比可变的类更加易于设计、实现和使用。它们不容易出错,且更加安全。

    要使类成为不可变,要遵守下面五条规则:

     1. 不要提供任何会修改对象状态的方法。
    
     2. 保证类不会被扩展。一般是把类定义为final的,或者将类的所有构造器都变成私有的或者是包级私有的,并添加静态工厂来代替共有的构造器。
    
     3. 使所有的域都是final的。
    
     4. 使所有的域都成为私有的。
    
     5. 确保对于任何可变组件的互斥访问。确保客户端无法获得对象的引用。
    

    不可变对象本质上是线程安全的,它们不要求同步。

    不可变对象可以被自由地共享,不仅可以共享不可变对象,甚至也可以共享它们的内部信息。

    不可变对象为其他对象提供了大量的构件

    不可变对象真正唯一的缺点是,对于每个不同的值都需要一个单独的对象。

    不可变的对象内部可以拥有一个或者多个非final得域,来缓存一些值(hashcode,String中就有),不变形保证了这个值永远都不会变。
    基本类型的域不能用final,因为在初始化的时候,会被赋初始值。

    第16条:复合优先于继承

    本书使用的继承指的是实现继承,即一个类扩展另一个类的时候。

    继承打破了封装性。子类依赖超类的特定功能的实现,如果超类发生变化,子类必须跟着超类一起改变。这样的子类是非常脆弱的。

    只有当子类和超类之间确实存在子类型关系时(is-a),使用继承才是恰当的。

    第17条:要么为继承而设计,并提供文档说明,要么就禁止继承

    文档必须精确地描述覆盖每个方法所带来的影响。

    对于每个公有的或者受保护的方法或者构造器,它的文档必须指明该方法或者构造器调用了哪些可覆盖的方法,是以什么顺序调用的,每个调用的结果又是如何影响后续的处理过程的。

    好的API文档应该描述一个给定的方法做了什么工作,而不是描述它是如何做到的。

    为了继承而设计的类,唯一的测试方法就是编写子类。

    为了允许继承,类还必须遵守其他一些约束:
    1.构造器不能调用可被覆盖的方法
    2.如果为了继承而设计的类实现了Cloneable或者Serializable接口,clone和readObject都不可以调用可覆盖的方法,不管是以直接还是间接的方式。
    3.如果为了继承而设计的类实现了Serializable接口,并且该类有一个readResolve或者writeReplace方法,就必须使readResolve或者writeReplace成为受保护的方法,而不是私有的方法。

    消除类中可覆盖方法的自用特性。就可以安全的子类化。

    第18条:接口优于抽象类

    1.现有的类可以很容易被更新,以实现新的接口。比如Comparable
    2.接口是定义混合类型的理想选择。混合类型表明具有某个可供选择的行为。
    3.接口允许我们构造非层次结构的类型框架。

    骨架实现类就是一个抽象类继承了某一个接口

    第19条:接口只用于定义类型

    常量接口:没有包含任何方法,只包含了一些静态的final域,每个域都导出一个常量。常量模式是对接口的不良使用

    如果要导出常量,就应该把这些常量添加到这个类。
    使用枚举类型或者不可实例化的工具类。

    第20条:类层次优于标签类

    类层次可以反映类型之间本质上的层次关系。

    第21条:用函数对象表示策略

    函数指针的只要用途就是实现策略模式。
    在java中实现这种模式,首先要声明一个接口来表示该策略,并且为每个具体策略声明一个实现了该接口的类。当一个具体策略只被调用一次的时候,通常使用匿名类来声明和实例化这个具体的实现类。当一个具体策略是设计用来重复使用的时候,它的类通常就要被实现为私有的静态成员类,并通过公有的静态final域被导出,其类型为该策略接口。

    第22条:优先考虑静态成员类

    见另一篇文章《Java嵌套类》。

    相关文章

      网友评论

        本文标题:EffectiveJava第4章-类和接口

        本文链接:https://www.haomeiwen.com/subject/ywrwqxtx.html