书名
《Java核心技术卷1 基础知识》(原书第10版)
基本信息
- 作者:霍斯特曼
- 出版社:机械工业出版社
- 阅读进度:80%
重点摘录
- Java中所有数值类型和平台无关,所以byte:1字节,short:2字节,int:4字节,long:8字节,float:4字节,double:8字节
- 程序注释中的\u会被识别为转义字符,导致语法错误
- 码点:编码表中某个字符对应的值,代码单元:每个字符用16位的编码表示。一般的unicode码点只需要一个代码单元,但是一些特殊字符需要两个,所以不要使用char类型,可以通过string的codePoint相关方法查看码点
- StrictMath库的准确性大于Math库
- StringBuilder线程不安全,StringBuffer线程安全
- Arrays.copy(oldArray.length)浅拷贝,返回新数组
- Java中都是按值调用
- 方法返回值不是方法签名的一部分
- 优先使用不可变类
- 子类继承父类的方法调用顺序:子类签名完全匹配>向上转型>拆装箱
- 用
Objects.equals()
能够避免npe - Java要求equals具有以下特性:
- 自反性:x!=null则x.equals(x)
- 对称性:x.equals(y)为true则y.equals(x)为true
- 传递性:x.equals(y)为true,y.equals(z)为true,则x.equals(z)为true
- 一致性:x.equals(y)为true,如果引用的对象没有变化,则反复调用依然是true
- 非空引用equals(null)为false
- Number类型包括6个派生:Long,Integer,Short,Float,Double,Byte
- 自动拆装箱是在编译期执行
getXXX
和tDeclaredXXX
的区别是:前者包含了本类以及从超类继承过来的公有元素,后者是本类所有元素- setAccessible可以为调试、持久存储和类似机制提供访问权限
- 方法引用三种格式:
- 实例::实例方法
- 类::静态方法
- 类::实例方法
- lambda表达式中的值必须是最终量
- 函数式接口列表:p240 p241
- 内部类的static域都必须是final,即每个外部对象会分别有一个单独的内部类实例
- 内部类是一种编译器现象,在编译阶段就编译成外部类$内部类的形式
- 不建议使用
new ArrayList<String>()双大括号add("")双大括号
的形式:- 效率:每个大括号都是一个匿名内部类
- 安全:内部类会持有外部类引用(静态内部类除外,其本身就相当于一个外部类,不会持有外部类引用)
- 目前来说,null标识默认类加载器
- 代理类一定是public 和final的
- 强烈建议用
e.getCause
的方式或者new Exception("",e)
的方式包装子系统中抛出的高级异常 - 推荐使用
try{try{}finally{}}catch(){}
的形式,因为外层会捕获内层的异常,同时内层finally又保证了资源释放 try(AutoCloseable)
的形式可以自动关闭资源- 未被任何变量引用的日志记录器可能会被垃圾回收,因此用一个静态变量存储日志记录器的一个引用
- 带有子类限定通配符的泛型对象允许读取,带有超类限定通配符的泛型对象允许写入
- Java的迭代器remove能删除当前位置的左侧元素,并且不能同时调用两次remove
- 迭代器如果发现他的集合被另一个迭代器修改了或者被集合自身方法修改了,会抛出
ConcurrentModificationException
,因为另一个迭代器和方法自身迭代都会修改modifiedcount
- 链表在访问某个元素时,通常需要从头开始搜索元素,如果该元素索引大于size/2,则从尾部搜索
- 索引值=
hashcode % total
,每个位置会有一个链表,java 8会在满了以后变成平衡二叉树 - 最好散列表的桶数(一个链表标识一个桶)设置为预计元素的0.75或者1.5倍+1
- 备注:guava的
Maps.newHashMapWithExpectedSize()
已经实现该算法
- 备注:guava的
- Java标准库给散列表的默认值是16,人为赋值会自动转成2的下一次幂(通过无符号右移+位或运算产生,本身就是2的次幂除外)
WeakHashMap
的键使用的是WeakReference
,将散列键引用保存到另外一个对象中,垃圾回收器回收时,会首先将该弱引用放到一个队列中,WeakHashMap周期性地检查该队列然后移除对应键- 视图技术:
Map.keySet(),Arrays.asList(),Collections.singleton(),List.subList()
等返回的都是一个集合的视图,对视图的操作都将映射到原始集合上,但是部分视图(例如asList返回的视图)不提供修改操作 - 包装器技术:
Arrays,Collections
等都是包装器,具有以下功能:- 提供
unmodifiablexxx
等方法获得不可修改视图 - 提供
synchronizedxxx
等方法获得同步视图 - 提供
heckListxxx
等方法获得受查视图(用于运行时检查)
- 提供
- 没有可以强制终止线程的办法,只有请求终止线程的办法
interrupt()
,该方法会将线程状态置为终止,被终止和睡眠的线程不能调用isInterrupt()
方法检测状态 - 线程状态:
- new 新建
- runnable 就绪/运行中
- waiting object.wait(),thread.join(),lock.tryLock或者condition.await
- blocked 获取内部的对象锁,而该锁被其他线程持有时
- timedWaiting 带有计时参数的方法thread.sleep(),object.wait(),thread.join(timeout),,lock.tryLock或者condition.await
- terminated 方法执行完成 线程执行中出现异常
- 守护线程不应该用户访问资源 比如文件、数据库,而应该给其他线程提供服务
- 并发编程:
- 锁对象,被一个锁保护的对象可以访问另外一个使用相同锁的方法
- 条件对象,条件对象调用await以后,需要其他线程调用signalAll方法通知等待线程退出阻塞状态,然后通过竞争实现对对象的访问
- Java的synchronized关键字可以单独用来修饰方法,但实际上实现方式是每一个对象有一个内部的锁和条件
- Volatile:解决实例同步访问 避免指令重排序
AtomicXXX
等类提供了一些原子性(通过高效的机器级指令实现)的自增,以及对应XXXAdder
来实现计算函数- 线程的stop方法被弃用,因为它会导致未完成的线程终止,suspend同样被弃用,假如suspend挂起了一个还没释放锁的线程,会导致死锁:被挂起的等待恢复,将其挂起的等待锁
- 多线程完成同一任务:
阻塞队列/并行流 > synchorized > lock/condition
- 公平队列和公平锁都会减低性能,只有在确定时才能使用
- 队列的常用操作方法:
- offer 添加一个元素
- peek 返回头元素
- poll 返回并移出头元素
- 队列常用的线程管理方法:
- put 添加一个元素,如果队列满则阻塞
- take 移出并返回头元素
- 不要使用
Executors.newFixedThreadPool
等方法创建线程池,因为java 8默认的线程队列是无界队列,并且不知道线程创建细节会容易踩坑 FixedRate
(固定速率)是两次开始之间固定周期,FixedDelay
(固定延迟)是结束到下次开始之间的固定周期- 一般的WEB服务器都是IO密集型,通常可以按照一个CPU两个线程来处理;计算密集型可以一个CPU一个线程
- fork-join框架:工作密取法,每一个工作线程维护了一条deque,它只会从队头获取任务执行,其他线程空闲时会从该工作线程的队尾获取任务执行
- 同步器:
- CyclicBarrie`r 允许线程集等待直到其中预定数目的线程到达一个公共障栅,然后选择一个处理障栅的动作
Phaser
循环障栅,但是有一个可变计数控制参与的线程数量CountDownlatch
线程集等到直到计数变为0Exchange
两个线程在可交换变量就绪时交换数据,例如同一个缓冲区的两个实例里的线程,一个往缓冲区填入数据,另一个消费,当两个实例就绪时交换缓冲区实例Semaphone
信号量,限制访问的线程总数SynchronousQueue
同步队列,提供生产者与消费者匹配机制,生产者put后会一直阻塞到消费者take为止