专栏首页cwl_Java3分钟快速阅读-《Effective Java》(二)

3分钟快速阅读-《Effective Java》(二)

11.慎重覆盖clone方法

在日常开发当中我们可能会遇到有些需求需要对一个对象进行拷贝操作,这里就涉及到深拷贝还是浅拷贝的问题,深拷贝是在内存当中创建出一个新的内存空间用于存储原来这个对象相同的内容,浅拷贝就只是拷贝了原来对象的地址值,此时如果使用拷贝操作,那么操作的本质上依旧是原来的对象. 在JDK当中有些集合也提供了Deep Copy的操作,可以根据需要来进行操作,一般情况下建议大家使用谷歌提供的common.lang3下的BeanUtils当中通过反射来对对象进行拷贝操作,这样是相对比较安全的

12.考虑实现Comparable接口

在日常开发当中遇到对象集合需要根据特定顺序来进行排序时,就可以考虑实现Comparable接口,这个接口是JDK比较早出的在java.lang包下的一个接口,当中只有一个比较方法,为了让所有实现这个接口的类都能具有比较的功能,然而效果并不好, 所以后来在JDK1.8中java.util包下面加强了Comparator的接口,这个接口的可以实现的功能更多,事实上对于顺序比较的接口Spring社区也出了很多对于这个接口的封装,在谷歌的工具类当中也有,开发者可以根据自己的需要来选择对象需要实现的接口

13.尽量使类和成员的可访问性最小化

好处:访问性越小,低耦合性和高内聚性越好,更利于模块化开发,方便于我们独立的开发,测试,优化,使用,理解,修改.

14.在公有类中使用访问方法而非公有域

总结一句话就是所有字段私有化,提供对应的setter和getter方法来进行访问

15.使可变性最小化

原文当中对于这段的描述是根据java.math下的一些类来进行阐述的,所以提出了以下5个观点的要求,我们在开发当中对于这样的一些工具实用类,也是需要遵从这样的设计原则,有兴趣的请详细参照Bigdecimal或者是Integer等类.

  • 15.1 不要提供任何会修改对象状态的方法
  • 15.2 保证类不会被拓展(不应该被继承)
  • 15.3 使所有的域都是final的(字段使用final修饰)
  • 15.4 使所有的域成为私有的(字段使用private修饰)
  • 15.5 确保对于任何可变组件的互斥访问(如果这个类当中包含其他对象的引用,那么要保证其他类对当前类无法修改)

16.复合优先于继承

复合就是先实现接口创建一个父类,然后再继承这个实现类.继承的好处是提升了代码的重用性,但是也会破坏了封装性.除此之外继承还会导致父类当中有代码相互调用时产生了误差,具体请看下面的代码示例

//需求是要记录Hashset当中添加了多少个元素,所以继承了HashSet,并且新增了字段count
public class ChildHashSet<T> extends HashSet<T> {

    private int count = 0;

    public ChildHashSet() {
    }

    public ChildHashSet(int initCap , int loadFactory) {
        super(initCap,loadFactory);
    }

    @Override
    public boolean add(T t) {
        count++;
        return super.add(t);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {
        count = c.size();
        return super.addAll(c);
    }

    public int getCount() {
        return count;
    }
}

测试用例

//我们期望的结果应该count=3,但是结果是count=6,因为父类的addAll是根据add方法实现的,所以结果就多了一倍
public class Test {

    public static void main(String[] args) {
        ChildHashSet<String> strings = new ChildHashSet();
        strings.addAll(Arrays.asList("1", "2", "3"));
        int count = strings.getCount();
        System.out.println(count);
    }
}

解决方案就是自己先实现Set接口,然后自己写它对应的add和addAll方法,避免他们之间的相互调用,再使用一个想要实现具体类去继承实现类,并且也可以拓展自己想要的一些方法

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

简单来说继承可能带来的问题在第16条已经有说明,所以当我们在对继承体系进行设计的时候必须要给出相对应的说明文档,说明哪些方法可以覆盖,哪些方法覆盖了会有怎样的危害,让开发者更加简洁的明白,要进行继承的时候应该注意什么

18.接口优于抽象类

在原文当中主要想说明的就是抽象类只能被继承,但不能被实现.在Java当中支持多实现,但是不支持多继承.所以在拓展性上抽象类要比接口差,但是抽象类当中可以写普通方法的拓展比接口好一些.事实在JDK1.8开始,为了支持对接口的拓展,接口当中已经可以写默认方法和静态方法,用于弥补这部分的缺陷,可以说接口基本上完全可以取代抽象类了

19.接口只用于定义类型

在JDK1.5之前很多人会使用接口来替代现在的枚举类,也就是我们所常说的常量接口,这样的接口是对接口的不良使用.我们并不提倡这样的方法来写常量.接口应该只是用于定义实现了这个接口的类型是什么样的

20.类层次优先于标签类

类层次就是抽象类和普通类搭配形成的一个类的结构,标签类就是将抽象类和普通类柔和成一个类,并且一个类当中存在着多种类型的一种做法,大大降低了可读性的一种写法.具体请看下面的代码示例

//标签类
public class Figure {

    public Figure(Shape shape) {
        this.shape = shape;
    }

    private enum Shape {RECTANGLE,CIRCLE};
    private final Shape shape;
    private double length;
    private double wideth;
    private double radius;

    public Figure(double radius) {
        shape = Shape.CIRCLE;
        this.radius = radius;
    }

    public Figure(double length, double wideth) {
        shape = Shape.RECTANGLE;
        this.length = length;
        this.wideth = wideth;
    }

    double area(){
        switch(shape){
            case RECTANGLE :
                return length * wideth;
            case CIRCLE :
                return radius * radius;
            default:
                throw new AssertionError();
        }
    }

    public double getLength() {
        return length;
    }

    public void setLength(double length) {
        this.length = length;
    }

    public double getWideth() {
        return wideth;
    }

    public void setWideth(double wideth) {
        this.wideth = wideth;
    }

    public double getRadius() {
        return radius;
    }

    public void setRadius(double radius) {
        this.radius = radius;
    }
}

类层次代码示例,在实际开发当中将抽象类转成接口会更好一些,这里为了更好解释原文当中的类层次,所以使用了抽象类来进行描述

abstract class FigureTest{

    abstract double area();
}

class Rectangle extends FigureTest{
    private double length;
    private double wideth;
    
    @Override
    double area() {
        return length * wideth;
    }
}

class Circle extends FigureTest{
    private double radius;
    @Override
    double area() {
        return radius * radius;
    }
}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • JDK1.9-常用函数式接口

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

    cwl_java
  • 速读原著-TCP/IP(常用命令)

    到目前为止,我们已经讨论了链路层和 I P层,现在可以介绍 T C P / I P对网络接口进行配置和查询的命令了。i f c o n f i g( 8 )命令...

    cwl_java
  • 快速学习-RestFul接口设计

    随着互联网的发展, 尤其是移动互联为代表的Web3.0时代. 客户端层出不穷, 以APP、微信、PC浏览器为代表, 服务端业务逻辑是基本一致的。那么有没有一种方...

    cwl_java
  • Api接口设计需要考虑到de因素呢

    设计接口是一件容易的事,也是件困难的事。设计接口每个人都会,每个人都能设计,也由此产生了各种各样的理念的接口。工作这么多年,我也很有感悟。很多人会说,设计接口多...

    php007
  • php如何做接口

    一个类可以一次性实现多个接口。语法用implements实现,然后在把接口的功能实现;

    叫我可儿呀
  • PHP接口类(interface)的定义、特点和应用示例

    本文实例讲述了PHP接口类(interface)的定义、特点和应用。分享给大家供大家参考,具体如下:

    砸漏
  • (19) 接口的本质 / 计算机程序的思维逻辑

    数据类型的局限 之前我们一直在说,程序主要就是数据以及对数据的操作,而为了方便操作数据,高级语言引入了数据类型的概念,Java定义了八种基本数据类型,而类相当...

    swiftma
  • 微信JSSDK那些事

    好长时间没对微信的H5进行开发,不过感觉微信基本已经废弃了JSSDK的更新,把更多的精力向小程序那边转移。不过刚好要维护一个以前写的微信H5所以重新拿了起来,如...

    谭广健
  • 接口工具分析

    系统对外的接口:比如你要从别的网站或服务器上获取资源或信息,别人肯定不会把 数据库共享给你,他只能给你提供一个他们写好的方法来获取数据,你引用他提供的接口就能使...

    用户7880705
  • 面向对象的7种设计原则(2)-接口隔离原则

    其实通俗来理解就是,不要在一个接口里面放很多的方法,这样会显得这个类很臃肿。接口应该尽量细化,一个接口对应一个功能模块,同时接口里面的方法应该尽可能的少,使接口...

    一觉睡到小时候

扫码关注云+社区

领取腾讯云代金券