前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >3分钟快速阅读-《Effective Java》(二)

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

作者头像
cwl_java
发布2019-10-26 20:47:37
4270
发布2019-10-26 20:47:37
举报
文章被收录于专栏:cwl_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.复合优先于继承

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

代码语言:javascript
复制
//需求是要记录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;
    }
}

测试用例

代码语言:javascript
复制
//我们期望的结果应该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.类层次优先于标签类

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

代码语言:javascript
复制
//标签类
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;
    }
}

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

代码语言:javascript
复制
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;
    }
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019/05/06 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 11.慎重覆盖clone方法
  • 12.考虑实现Comparable接口
  • 13.尽量使类和成员的可访问性最小化
  • 14.在公有类中使用访问方法而非公有域
  • 15.使可变性最小化
  • 16.复合优先于继承
  • 17.要么为继承而设计,并提供文档说明,要么就要禁止继承
  • 18.接口优于抽象类
  • 19.接口只用于定义类型
  • 20.类层次优先于标签类
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档