java核心技术卷一(10th)笔记
三、基本程序设计
- Char能否表示中文字符:一些BMP(基本多语言级别)可以,char描述了用UTF16编码表示unicode的一个代码单元(unicode、UTF16)
- 0.125=2^-3可以表示成8x1.0p-3
- 整数除0异常,浮点数NaN
- Strictfp:使用严格浮点运算来生产可再生的运算结果
- >>>:0填充高位,>>符号位填充高位
- 空字符串是一个对象,String还可以存放一个名为null的特殊值
- %s:实现Formmattable接口的对象将调用formatTo方法,否则调用toString
- Int[][]os=newint[9][]
- 所有的java对象存储在堆中
- 必须使用clone方法获得对象的完整拷贝
四、对象与类
- Return(Date)hireDay.clone()
- 一个方法可以访问所属类的所有对象的私有数据
五、继承
- 反射是指在程序运行期间发现更多的类及其属性的能力。
- 子类不能直接访问超类的私有域
- 一个对象变量可以指示多种实际类型的现象被称为多态,在运行是能够自动地选择调用哪个方法的现象被称为动态绑定。
- 在程序运行期间,Java运行时系统始终为所有的对象维护一个被称为运行时的类型标识。这个信息跟踪着每个对象所属的类。虚拟机利用运行时类型信息选择相应的方法执行。然而,可以通过专门的Java类访问这些信息。保存这些信息的类被称为Class。
六、接口、Lambda与内部类
- Lambda可以捕获外围作用域中变量的值,但只能是不会改变的变量,必须是实际上的最终变量。
- 以上this指Application。
- Lambda延迟执行
- 内部类可以访问内外部类所有作用域的数据,包括私有数据;内部类对同一个包中的其他类隐藏
- Static内部类没有外围对象的隐式引用,可以有静态域和方法
- 编译器修改了所有的内部类的构造器,添加一个外围类引用的参数
- 只有内部类可以是私有类,常规类只可以包可见或者公有
- 内部类的静态域必须是final。原因:一个静态类只有一个实例,不过对于每个外部对象,会分别有一个单独的内部类实例。如果这个域不是final,便可能不是唯一的。
- 内部类不能有static方法。
- 虚拟机中不存在私有类,因此编译器将会利用私有的构造器生成一个包可见的类
- 局部类不能用public或private访问说明符进行声明
- 局部类有一个优势,即对外部世界可以完全地隐藏起来。即使TalkingClock类中的其他代码也不能访问它。除start方法之外,没有任何方法知道TimePrinter类的存在。
- 局部类还有一个优点。它们不仅能够访问包含它们的外部类,还可以访问局部变量。不过,那些局部变量必须事实上为final。
- 局部类不能用public或者private访问说明符进行声明
- 编译器必须检查对局部变量的访问,为每一个变量建立相应的数据域,并将局部变量拷贝到构造器中,以便将这些数据域初始化为局部变量的副本。
- 局部类的方法只可以引用定义为final的局部变量。
- 匿名类不能有构造器,将构造器参数传递给超类构造器
- invite(newArrayList<String>0{{add("Harry");add("Tony");}});
- 利用代理可以在运行时创建一个实现了一组给定接口的新类:这种功能只有在编译时无法确定需要实现哪个接U时才冇必要使用
- 无论何时调用代理对象的方法,调用处理器的invoke方法都会被调用,并向其传递Method对象和原始的调用参数
- 代理类是在程序中创建的,一旦创建变成了常规类
- 一个代理类只有一个实例域—调用处理器,它定义在Proxy的超类中。为了履行代理对象的职责,所需要的任何附加数据都必须存储在调用处理器中。
- 代理类一定是public和final。如果代理类实现的所有接口都是public,代理类就不属于某个特定的包;否则,所有非公有的接口都必须属于同一个包,同时,代理类也属于这个包。
七、异常、(断言、日志跳过)
- 异常对象都是派生与Throwable类的一个实例
- 如果在子类中覆盖了超类的一个方法,子类方法中声明的受查异常不能比超类方法中声明的异常更通用(也就是说,子类方法中可以抛出更特定的异常,或者根本不抛
- 出任何异常)
- 如果finally语句也有一个return语句,这个返回值将会覆盖原始的返回值
九、集合
- 如果需要一个循环数组队列,就可以使用ArrayDeque类。如果需要一个链表队列,就直接使用LinkedList类,这个类实现了Queue接口。
- “foreach”循环可以与任何实现了Iterable接口的对象一起工作
- 可以调用forEachRemaining方法并提供一个lambda表达式(它会处理一个元素)。将对迭代器的每一个元素调用这个lambda表达式,直到再没有元素为止。
- 应该将Java迭代器认为是位于两个元素之间。当调用next时,迭代器就越过下
- 一个元素,并返回刚刚越过的那个元素的引用
- 对next方法和remove方法的调用具有互相依赖性。如果调用remove之前
- 没有调用next将是不合法的。
- Java类库提供了一个类AbstractCollection,
- 它将基础方法size和iterator抽象化了,但是在此提供了例行方法
- 所有链表实际上都是双向链接的
- 集合类库提供了子接口Listlterator,其中包含add方法:
- 在Java中,散列表用链表数组实现。
- 标准类库使用的桶数是2的幂,默认值为16(为表大小提供的任何值都将被自动地转换为2的下一个幂)。
- 如果装填因子为0.75(默认值,)而表中超过75%的位置已经填人元素,这个表就会用双倍的桶数自动地进行再散列。
- Java集合类库提供了一个HashSet类,它实现了基于散列表的集。
- 在更改集中的元素时要格外小心。如果元素的散列码发生了改变,元素在数据结构中的位置也会发生变化。
- 正如TreeSet类名所示,排序是用树结构完成的(当前实现使用的是红黑树)
- 从JavaSE6起,TreeSet类实现了NavigableSet接口。
- 在JavaSE6中引人了Deque接口,并由ArrayDeque和LinkedList类实现。这两个类都提供了双端队列,而且在必要时可以增加队列的长度。
- 优先级队列使用了一个优雅且高效的数据结构,称为堆(heap)。堆是一个可以自我调整的二叉树,对树执行添加(add)和删除(remore)操作,可以让最小的元素移动到根,而不必花费时间对元素进行排序。
- counts.merge(word,1,Integer::sum);
- keySet不是HashSet或TreeSet,而是实现了Set接口的另外某个类的对象。
- 当对键的唯一引用来自散列条目时,这一数据结构将与垃圾回收器协同工作一起删除键/值对
- WeakHashMap使用弱引用(weakreferences)保存键。WeakReference对象将引用保存到另外一个对象中
- LinkedHashSet和LinkedHashMap类用来记住插人元素项的顺序。这样就可以避免在散列表中的项从表面上看是随机排列的。
- 受到影响的条目将从当前的位置删除,并放到条目链表的尾部
- 由于枚举类型只有有限个实例,所以EnumSet内部用位序列实现。
- 类IdentityHashMap有特殊的作用。在这个类中,键的散列值不是用hashCode函数计算的,而是用System.identityHashCode方法计算的。这是Object.hashCode方法根据对象的内存地址来计算散列码时所使用的方式。
- keySet方法返回一个实现Set接口的类对象,这个类的方法对原映射进行操作。这种集合称为视图
- 由于视图只是包装了接口而不是实际的集合对象,所以只能访问接口中定义的方法。
- unmodifiableCollection方法(与本节稍后讨论的synchronizedCollection和checked
- Collection方法一样)将返回一个集合,它的equals方法不调用底层集合的equals方法。相反,它继承了Object类的equals方法,这个方法只是检测两个对象是否是同一个对象。如果将集或列表转换成集合,就再也无法检测其内容是否相同了。•视图就是以这种方式运行的,因为内容是否相等的检测在分层结构的这一层上没有定义妥当。视图将以同样的方式处理hashCode方法。然而,unmodifiableSet类和unmodifiableList类却使用底层集合的equals方法和hashCode方法
十、并发
- 多线程和多线程:本质的区别在于每个进程拥有自己的一整套变量,而线程则共享数据。
- interrupted和islnterrupted。Interrupted方法是一个静态方法,它检测当前的线程是否被中断。而且,调用interrupted方法会清除该线程的中断状态。另一方面,islnterrupted方法是一个实例方法,可用来检验是否有线程被中断。调用这个方法不会改变中断状态。
- 在任何给定时刻,一个可运行的线程可能正在运行也可能没有运行(这就是为什么将这个状态称为可运行而不是运行)
- 线程的优先级是高度依赖与系统的
- 当只剩下守护线程时,虚拟机就退出了:由于如果只剩下守护线程,就没必要继续运行程序了。
- 线程的run方法不能抛出任何受查异常,但是,非受查异常会导致线程终止,在这种情况下,线程就死亡了。
- 不需要任何catch子句来处理可以被传播的异常。相反,就在线程死亡之前,异常被传递到一个用于未捕获异常的处理器。
- 琐是可重入的,因为线程可以重复地获得已经持有的锁。锁保持一个持有计数(holdcount)来跟踪对lock方法的嵌套调用。
- 将静态方法声明为synchronized也是合法的。如果调用这种方法,该方法获得相关的类对象的内部锁。
- 在JavaSE8中,并发散列映射将桶组织为树,而不是列表,键类型实现了Comparable,从而可以保证性能为0(log(n))。
- Rugo如果多个线程修改一个普通的hashmap,它们会破坏内部结构(一个链表数组)。有些链接可能丢失,或者甚至会构成循环,使得这个数据结构不在可用。对于concurrentHashMap绝对不对发生这种情况。在上面的例子中,get和put代码不会破坏数据结构。不过,由于操作序列不是原子的,所以结果不可预知。
- ConcurrentHashMap中不允许有null值。有很多方法都使用null值来指示映射中某个给定的键不存在。
- 任何集合类都可以使用同步包装器变成线程安全的。
- Runnable封装一个异步运行的任务,可以把它想象成为一个没有参数和返回值的异步方法。Callable与Runnable类似,但是有返回值。
- 构建一个新的线程是有一定代价的,因为涉及与操作系统的交互。如果程序中创建了大量的生命期很短的线程,应该使用线程池。