《Thinking in JAVA》日常笔记整理

这本书很早之前就开始看了,但一直也没完整的看完,这个周末终于把剩余的内容都补上了。抓紧把读书笔记一齐整理下。

前面十几章的内容其实在开发过程中都已经理解得比较到位了,但关于容器部分特别是容器的深入使用相关内容还是掌握不够,所以先整理容器:

  1. LinkedHashSet按照元素插入的顺序保存元素,而TreeSet按照排序顺序维护元素
  2. SortedSet:Comparator comparator()返回当前set使用的Comparator,或者返回null,表示自然方式排序;Object first()返回容器总的第一个元素;Object last()返回容器中的最末一个元素;SortedSet subSet(fromElement, toElement)生成此Set的自己,范围从fromElement(包含)到toElement(不包含);SortedSet headSet(toElement)生成此Set的子集,由小于toElement的元素组成;SortedSet tailSet(fromElement)生成此Set的子集,由大于或等于fromElement的元素组成
  3. SortedSet的意思是“按对象的比较函数对元素排序”,而不是指“元素插入的次序”。插入顺序可以用LinkedHashSet来保存
  4. Queue在java se5中只有两个实现,LinkedList和PriorityQueue,他们的差异在排序行为
  5. 双向队列:就像是一个队列,但是可以在任何一端添加或移除元素,在LinkedList中包含支持双向队列的方法,但是在java标准类库中没有任何显式地用于双向队列的接口。因此可以使用组合来创建一个Deque类,并直接从LinkedList中暴露
  6. 映射表(也称为关联数组)的基本思想是它维护的是键值(对)关联,因此你可以使用键来查找值。标准的java类库中包含了Map的几种基本实现,包括
    1. HashMap:使用了hashCode()来进行散列,hashCode为java的Object根类的方法,插入和查询“键值对”的开销是固定的,可以通过构造器设置容量和负载因子以调整容器的性能:默认的Object.equals()比较的是对象的地址,HashMap使用equals()判断当前键是否与表中存在的键相同,正确的equals应满足以下5个条件
      1. 对任何不是null的x,x.equals(null)一定返回false
      2. 一致性:对于任意x和y,如果对象中用于等价比较的信息没有改变,那么无论调用x.equals(y)多少次,返回结果总是一致地
      3. 传递性:对任意x,y,z若x.equals(y)=true,且y.equals(z)=true,则x.equals(z)=true
      4. 对称性:若x.equals(y)= true,则y.equals(x)=true
      5. 自反性:x.equals(x) = true
      6. 如果要使用自己的类作为HashMap的键,必须同时重载hashCode()和equals()方法
    2. TreeMap:基于红黑树的实现,查看“键”或“键值对”时,他们会被排序(次序由Comparable或Comparator)决定。TreeMap的特点在于,所得到的结果是经过排序的。TreeMap是唯一带有subMap()方法的Map,可以返回一个子树。
    3. LinkedHashMap:类似于HahsMap,但是迭代遍历它取得“键值对”的顺序是其插入次序,或者是LRU次序,只比HashMap慢一点,而在迭代访问时反而更快,因为它使用链表维护内部次序。
    4. WeakHashMap:弱键(weak key)映射,允许释放映射所指向的对象;这是为解决某类特殊问题而设计的。如果映射之外没有引用指向“某个键”,则此“键”将被GC回收。
    5. ConcurrentHashMap:一种线程安全的Map,他不涉及同步加锁
    6. IdentityHashMap:使用==代替equals()对“键”进行比较的散列映射,专门为解决特殊问题而设计的
  7. 如果不覆盖hashCode()和equals()将无法使用散列的数据结构有:HashSet、HashMap、LinkedHashSet、LinkedHashMap
  8. 设计hashCode()时最重要的因素就是:无论何时,对同一个对象,调用hashCode()都应该生成同样的值
  9. Set可被实现为:
    1. TreeSet:HashSet最常用,查询速度最快。它唯一原因是它可以维持元素的排序状态。TreeSet迭代通常比用HashSet要快
    2. HashSet:基于TreeMap。生成一个总是处于排序状态的Set。性能基本上总是比TreeSet好,特别是在添加和查询元素时,而这两个操作也是最重要的操作。
    3. LinkedHashSet:保持元素插入的次序。对于插入操作LinkedHashSet比HashSet的代价还高,这是由维护链表所带来额外开销造成的
  10. Map可被实现为:
    1. IdentityHashMap:所有的Map实现的插入操作都会随着Map尺寸的变大而明显变慢。查找的代价通常比插入要小得多
    2. HashTable的性能大体上与HashMap相当,HashMap是用来替代HashTable的
    3. TreeMap:通常比HashMap慢,与TreeSet一样,TreeMap是一种创建有序队列的方式
    4. LinkedHashMap:在插入时比HashMap慢一点,因为它维护散列数据结构的同时还要维护链表,正是由于这个列表,使得其迭代速度更快
  11. HashMap的性能因子:
    1. 容量:表中的桶位数
    2. 初始容量:表在创建时所拥有的桶位数。HashMap和HashSet都具有允许你指定初始容量的构造器
    3. 尺寸:表中当前存储的项数
    4. 负载因子:尺寸/容量。默认负载因子0.75,这个因子在时间和空间代价之间达到了平衡,更高的负载因子可以降低表所需的空间,但是会增加查找代价
  12. SoftReference、WeakReference和PhantomReference由强到弱排列,对应不同级别的“可获得性”
    1. SoftReference:用以实现内存敏感的高速缓存
    2. WeakReference:为实现“规范映射”而设计的,它不妨碍垃圾回收器回收映射的“键”(或“值”)。规范映射中对象的实例可以在程序的多处被同时使用,以节省存储空间
    3. PhantomReference:用一调度会收钱的清理工作,它比Java终止机制更灵活

 其余内容整理:

 访问控制权限:1.Java访问权限修饰词:public、protected、包访问权限(默认访问权限)和private

2.包访问权限:当前包中的所有其他类对那个成员具有访问权限,但对于这个包之外的所有类,这个成员却是private。

3.protected:继承访问权限。有时基类的创建者会希望有某个特定成员,把对它的访问权限赋予派生类而不是所有类。这就需要protected来完成这一工作。protected也提供包访问权限,也就是说,相同包内的其他类都可以访问protected元素。protected指明“就类用户而言,这是private的,但对于任何继承于此类的导出类或其他任何位于同一个包内的类来说,它却是可以访问的”。比如:
基类:

package access.test ;
public class Test {
    public Test () {
        System.out.println("Test Constructor");
    }

    void func1() {  // 包访问权限,其它包即使是子类也不能访问它
        System.out.println("func1");
    }
}


子类:

import access.test.Test ;

public class Chip extends Test {

    public Chip() {
        System.out.println("Chip constructor");
    }

    public void func2() {
        func1();  // error, the method func1() from the type Test is not visible
    }
}

可以发现子类并不能访问基类的包访问权限方法。此时可以将Test 中的func1指定为public,但这样做所有的人就都有了访问权限,为了只允许子类访问,可以将func1指定为protected即可。

组合和继承之间的选择:1.组合和继承都允许在新的类中放置子对象,组合是显式的这样做,而继承则是隐式的做。2.组合技术通常用于想在新类中使用现有类的功能而非它的接口这种情形。即在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的只是为新类所定义的接口,而非所嵌入对象的接口。为取得此效果,需要在新类中嵌入一个现有类的private对象。但有时,允许类的用户直接访问新类中的组合成分是极具意义的,即将成员对象声明为public。如果成员对象自身都隐藏了具体实现,那么这种做法是安全的。当用户能够了解到你正在组装一组部件时,会使得端口更加易于理解。比如Car对象可由public的Engine对象、Wheel对象、Window对象和Door对象组合。但务必要记得这仅仅是一个特例,一般情况下应该使域成为private。3.在继承的时候,使用某个现有类,并开发一个它的特殊版本。通常,这意味着你在使用一个通用类,并为了某种特殊需要而将其特殊化。稍微思考一下就会发现,用一个“交通工具”对象来构成一部“车子”是毫无意义的,因为“车子”并不包含“交通工具”,它仅是一种交通工具(is-a关系)。4.“is-a”(是一个)的关系是用继承来表达的,而“has-a”(有一个)的关系则是用组合来表达。5.到底是该用组合还是继承,一个最清晰的判断方法就是问一问自己是否需要从新类向基类进行向上转型,需要的话就用继承,不需要的话就用组合方式。

 final关键字:

1.对final关键字的误解:当final修饰的是基本数据类型时,它指的是数值恒定不变(就是编译期常量,如果是static final修饰,则强调只有一份),而对对象引用而不是基本类型运用final时,其含义会有一点令人迷惑,因为用于对象引用时,final使引用恒定不变,一旦引用被初始化指向一个对象,就无法再把它指向另一个对象。然而,对象其自身却是可以被修改的,Java并未提供使任何对象恒定不变的途径(但可以自己编写类以取得使对象恒定不变的效果),这一限制同样适用数组,它也是对象。

2.使用final方法真的可以提高程序效率吗:将一个方法设成final后,编译器就可以把对那个方法的所有调用都置入“嵌入”调用里。只要编译器发现一个final方法调用,就会(根据它自己的判断)忽略为执行方法调用机制而采取的常规代码插入方法(将自变量压入堆栈;跳至方法代码并执行它;跳回来;清除堆栈自变量;最后对返回值进行处理)。相反,它会用方法主体内实际代码的一个副本来替换方法调用。这样做可避免方法调用时的系统开销。当然,若方法体积太大,那么程序也会变得雍肿,可能受到到不到嵌入代码所带来的任何性能提升。因为任何提升都被花在方法内部的时间抵消了。

 策略设计模式与适配器模式的区别:

  • 策略设计模式
    创建一个能够根据所传递的参数对象的不同而具有不同行为的方法,被称为策略设计模式,这类方法包含所要执行的算法中固定不变的部分,而“策略”包含变化的部分。策略就是传递进去的参数对象,它包含要执行的代码。
  • 适配器模式
    在你无法修改你想要使用的类时,可以使用适配器模式,适配器中的代码将接受你所拥有的接口,并产生你所需要的接口。

转载于:https://my.oschina.net/u/3729361/blog/1606963

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值