很早就有读此书的打算,只是每次看过题目之后都觉得太底层,最近面试的时候被面试官虐的很惨emmmmmmm,面试官建议多注重底层,注重基础。遂重新拿出此书进行拜读!下面为自己记的笔记

一、简介

二、创建和销毁对象

1.考虑使用静态工厂的方法替代构造方法
1.1 代码
public static Boolean valueOf(boolean b) {
    return b ? Boolean.TRUE : Boolean.FLASE;
}
1.2 优点
  • 不像构造方法,它是有名字的,可以进行分辨
  • 不需要每次调用的时候都创建一个新对象

    • 类似于享元模式:主要用于减少创建对象的数量,以减少内存占用和提高性能。这种类型的设计模式属于结构型模式,它提供了减少对象数量从而改善应用所需的对象结构的方式
  • 它可以返回其返回类型的任何字类型的对象
  • 返回对象的类可以根据输入参数的不同而不同
2.当构造函数参数过多的时候使用builder模式
2.1 类似于流式编程
3.使用私有构造方法或者是枚举实现Singleton属性
  • 单一的枚举类通常是实现单例的最佳方式
4.使用私有的构造方法执行非实例化
4.1 代码部分
public class UtilityClass {
    private UtilityClass() {
        throw new AssertionError();
    }
}
4.2 作用
  • 它提供了一种保证,以防在类中意外的调用构造方法。它保证类在任何情况下都不会被实例化
5.使用依赖注入取代硬连接资源
6.避免创建不必要的对象
  • 在每次需要的时候重用一个对象而不是创建一个新的相同功能的对象是比较恰当的。重用可以更快更流行
  • 优先使用基本类型而不是装箱的基本类型,也要注意无意识的自动装箱
7.消除过期的对象引用
7.1 代码
public Object pop() {
    if(size == 0)
        throw new EmptyStackException();
    Object result = elements[--size];
    elements[size] = null;// 减少空引用
    return result;
}
7.2 缓存
  • 如果使用了缓存:只要是缓存之外存在对某个项的键引用,那么这项就是有明确有关联的,可以使用weakhashmap来表示缓存,这些项在过期之后自动删除
8.避免使用finalizer和cleaner机制
8.1 好处
  • 可以作为一个安全网,以防资源的拥有者忽略了它的close方法
8.2 why
  • 及时执行finalizer和cleaner机制是垃圾收集算法的一个功能,这种算法在不同的实现中有很大的不同
9.使用try-with-resources代替try-finally语句
9.1 代码部分
static String firstLineOfFile(String path) throws IOException {
    try (BufferedReader br = new BufferedReader(
    new FileReader(path))) {
        return br.readLine();// 相当于close操作
    }
}

三、所有对象的通用方法

1.重写equals方法的时候遵守通用约定
1.1 如果不希望被重写equals
@Override
public boolean equals(Object o) {
    throw new AssertionError();// 方法不可以被调用
}
1.2 什么时候需要重写equals方法呢?
  • 如果一个类包含一个逻辑相等的概念,这个概念有别于对象标识,而且父类还没有重写过equals方法
1.3 重写equals方法的时候也需要重写hashcode方法
  • 相等的对象必须有相等的哈希码
2.始终重写toString方法
3.谨慎的重写clone方法
  • 深克隆与浅克隆
4.考虑实现Comparable接口
static Comparator<Object> hashCodeOrder = 
    Comparator.comparingInt(o -> o.hashCode());

四-五、类和接口&&泛型

1.使类和成员的可访问性最小化
  • private:成员只能在声明它的顶级类内访问
  • protected:成员可以被从声明的类的子类中访问
  • public:成员可以从任何地方被访问
2.最小化可变性
  • 不要提供修改对象状态的方法
  • 确保这个类不能被继承
  • 将所有属性设置为final
  • 把所有的属性设置为private
  • 确保对任何可变组件的互斥访问

关于不可变对象

  • 不可变对象本质上是线程安全的,它们不需要同步
  • 不可变对象可以被自由的共享
3.接口优于抽象类
  • 现有的类可以很容易的进行改进来实现一个新的接口
4.始终在尽可能最小的范围内使用SuppressWarning注解,而且每次使用的时候应该添加注释来说明为什么是安全的
5.优先考虑泛型
public class Stack<E> {
    private E[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;// 定义常量的大小
    // 构造函数进行初始化
    public Stack() {
        elements = new E[DEFAULT_INITIAL_CAPACITY];
    }
    // push操作
    public void push(E e) {
        ensureCapacity();// 确保还有足够的空间
        elements[size++] = e;// 添加到数组中
    }
    
    public E pop() {
        if(size == 0) {
            throw new EmptyStackException();// 如果大小为0,则抛出异常进行处理 
        }
        E result = elements[--size];
        elements[size] = null;// 减少引用 
        return result;
    }
}// 这也是面试欢聚时代的一道题
public static <E> Set<E> union(Set<E> s1,Set<E> s2) {
    Set<E> result = new HashSet<>(s1);
    result.addAll(s2);
    return result;
}

六-七.注解和枚举&&Lambda表达式和Stream流&&通用编程

1.注解优于命名模式
2.lambda表达式优于匿名类
  • 除非必须创建非函数式接口类型的实例,否则不要使用匿名类作为函数对象
3.明智而审慎的使用重载
  • 重载方法之间的选择是静态的,而重写方法之间的选择是动态的
  • 如果在子类中重写实例方法并且在子类的实例上调用,则无论子类实例的编译时类型如何,都会执行子类的重写方法
4.返回空的数组或者是集合的时候不要返回null
  • Collections.emptyListCollections.emptyMapCollections.emptySet
  • public List<Cheese> getCheeses() {
        return cheesesInstock.isEmpty() ? Collections.emptyList() : new ArrayList<>(cheesesInstock);
    }
5.最小化局部变量的作用域
6.需要准确的结果的时候避免使用float和double类型
7.基本类型优于装箱的基本类型
  • 基本类型只有它们的值,而包装类型具有与其值不同的标识
  • 基本类型只有功能的值,而包装基本类型除了对应的基本类型的功能值外,还有一个非功能值,即null

    • 当程序执行拆箱的时候,会抛出NullPointerException的异常
  • 基本类型比包装的基本类型更节省时间和空间

什么时候应该使用装箱的基本类型?

  • 作为集合中的元素,键和值,不能将基本类型放在集合中,必须使用装箱的基本类型
  • 在参数化类型(泛型)和方法中必须使用装箱基本类型作为类型参数
  • 在进行反射方法调用的时候,必须使用装箱基本类型
8.通过接口引用对象
  • 如果决定要切换实现,只需要在构造方法中更换类名即可
9.Native方法
  • 提供对特定于平台设备(如注册表)的访问
  • 它们提供对现有本地代码库的访问,包括提供对遗留数据库的数据访问
  • 本地方法用于以本地语言编写应用程序的性能关键部分,以提高性能
10.为所有已经公开的API元素编写文档注释

七.异常&&并发&&序列化

1.对可恢复条件使用已检查异常,对编程错误使用运行时异常
2.catch中的捕获条件不能为空
3.如果需要使用延迟初始化来提高实例属性的性能,请使用双重检查习惯用法
private volatile FieldType field;

private FieldType getField() {
    FieldType result = field;
    if(result == null) {
        synchronized(this) {
            if(field == null) {
                field = result = computeFieldValue();
            }
        }
    }
}
4.避免序列化漏洞利用的最佳方法是不要反序列化任何东西

断断续续的看完了整本书,感觉收获挺大的,规整了很多编程的风格,经典书籍应该多看!!!!


Howie
3 声望0 粉丝