• Effective java -- 3 类和接口


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

    一个设计良好的模块会将实现细节隐藏起来,只将暴露API。模块之间调用并不知道对象的细节。这个概念成为信息隐藏或封装。
    要注意一点,设计的一个方法或者其他什么,只要不是私有的,外面能访问,那么以后在重构重写的过程中,这个方法就不能删掉,即使只是某个方法中的一个过程。
    非零数组总是可变的,即使加了final,里面的内容也是可变的:

    public static final Thirteenth[] values = {new Thirteenth(), new Thirteenth(), new Thirteenth()};

    用这种方法想声明一个不可变的数组是错误的,这只能说明values改不了,但是里面的每个成员还是可变的。用以下方法:

    方法一:
    private static final Thirteenth[] values = {new Thirteenth(), new Thirteenth(), new Thirteenth()}; public static final List<Thirteenth> VALUES = Collections.unmodifiableList(Arrays.asList(values2));
    方法二:  
    private static final Thirteenth[] values = {new Thirteenth(), new Thirteenth(), new Thirteenth()}; public static final Thirteenth[] values(){ return values.clone(); }

    四种访问权限,private(私有的),默认的(包级私有的),protected,public。要做到访问权限最小化,每个成员声明最开始应该都是私有地,同一包中其他类调用时将私有的换成包级私有的,如果程序很多地方都这么解决了问题,那么重新考虑一下设计的有没有问题。

    第十四条:在共有类中使用访问方法而非共有域

    就是提供set,get方法而不是将属性设成public的。在设计类的时候,考虑一下内部类。

    第十五条:使可变性最小化

    设计类的时候第一的想法就是将类设计成不可变的,属性私有、final,除非有明确的理由说服在将修饰符改掉。
    如果明确的就是设计一个不可变类,如String、BigInteger。要遵循下面无条规则

    • 不要提供任何会修改对象状态的方法
    • 保证类不会被扩展。一种方法类加上final,另一种做法不提供共有的构造器。
    • 所有的域都是final的
    • 使所有的域都是私有的
    • 确保对于任何可变组件的互斥访问。如果类具有指向课表对象的域,则必须保证该类的客户端无法获取指向这些对象的引用。并且永远不要用客户端提供的对象引用来初始化这样的域。

    不可变对象本质是线程安全的,他们不要求同步。
    不可变对象的缺点是,对于每个不同的值都需要创建一个单独的对象。
    类的构造器应该是完全初始化的对象。不要在构造器或静态工厂方法之外在提供额外的初始化方法,除非有令人信服的理由。

    第十六条:组合由于集成

    见过太多次的组合由于集成,看看是为什么。
    集成打破了封装性,换句话说,子类依赖于其超类中特定贡呢给你的实现细节。如果超类发生了变化,子类可能会遭到破坏。

    class InstruHashSet<E> extends HashSet<E> {
      private int count = 0;
    
      @Override
      public boolean add(E e) {
        count++;
        return super.add(e);
      }
    
      @Override
      public boolean addAll(Collection<? extends E> c) {
        count += c.size();
        return super.addAll(c);
      }
    
      public int getCount() {
        return count;
      }
    
      public static void main(String[] args) {
        InstruHashSet<String> instruHashSet = new InstruHashSet<String>();
        instruHashSet.addAll(Arrays.asList("f", "z", "k"));
        System.out.println(instruHashSet.getCount());
      }
    }

    最终的结果会是6。因为HashSet的addAll是循环调用add方法。
    还有一个问题,有可能自定义的一个方法,在之后的版本中,自定义的方法名和超类的方法重名了,这时如果返回值不同,那么就尴尬了。
    并不是说继承就应该不用,继承的正确用法应该是子类和父类就是一种层级的关系就像人-男人,这种情况下用继承是最好的。组合在这里用到了装饰者模式。

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

    如果允许继承,构造器决不能调用可覆盖的方法。

    class Seventeenth1{
      public Seventeenth1(){
        overrideMe();
      }
      
      public void overrideMe(){}
    }
    
    class Seventeenth2 extends Seventeenth1{
      Date date;
      public Seventeenth2(){
        date = new Date();
      }
      
      @Override
      public void overrideMe() {
        System.out.println(date);
      }
    
      public static void main(String[] args) {
        Seventeenth2 seventeenth2 = new Seventeenth2();
      }
    }

    输出的结果是null。
    对于实现了Cloneable或者Serializebale接口的类,也注意上面的问题。clone和readObject方法和构造器类似,因此都不可以调用可被覆盖的方法。

    第十八条:接口优于抽象类

    反正书上是这么说,但是用接口的利弊自己想吧,接口可以多实现,抽象类只能单继承,如果接口一开始设计有了问题,要修改接口是需要巨大代价的,但是抽象类单集成。

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

    在接口中定义各种常量,让实现类实现这个接口获取常量的做法不可取。可以定义常量类。如果是通过常量类的方式,导包的时候可以在包前加上static,这样就不用类名.常量名,直接常量名就可以了。

    public class ConstantClass{
      public static final String A = "a";
    }
    
    import static ConstantClass.*;
    class Test{
      String getA(){
        return A;
      }
    }

    第二十条:类层次优于标签类

    就是有层次结构的类就用集成的方式,别将一个类中定义各种乱七八糟的字段、方法让这个类既可以表示圆形又可以表示长方形。

    第二十一条:用函数对象表示策略

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

    嵌套类是指被定义在类内部的类。分为四种,静态成员类,非静态成员类,匿名类,局部类。除了第一种,其他三种都是内部类。
    静态成员类就是类内部的static生命的类,非静态成员类就是类内部非static生命的类,匿名类意会一下,局部类一般就是在方法中生命的类,出了方法就没有了。
    静态成员类和静态变量方法什么的一样,可以脱离外部类而存在的。非静态成员类想创建出来必须先城建外部类的实例,在创建内部类。

  • 相关阅读:
    服务器实现跨域
    quartz定时任务cron表达式详解
    mysql分区/分片
    微信小程序 之三元运算符代替wx:if 来解决背景图片显示隐藏
    微信小程序 本地缓存保持登录状态之wx.setStorageSync()使用技巧
    微信小程序 赋值问题
    微信小程序 wx.navigateTo()传参及多个参数方法
    js 循环遍历数组
    VUE之Router命令行警告:Named Route 'Home' has a default child route. 解决办法
    VUE之命令行报错:Component template should contain exactly one root element. If you are using v-if on multiple elements, use v-else-if to chain them instead 解决办法
  • 原文地址:https://www.cnblogs.com/badboyf/p/6289773.html
Copyright © 2020-2023  润新知