ThinkingInJava读书笔记 第1章对象导论 动态绑定是默认行为,不需要像C那样需要把函数声明为Virtual才可以实现; 所有的类都继承自单一的基类(Object),因此所有的对象都具有一个通用的接口,从而所有对象都保证具有类型信息,这种机制使垃圾回收器的实现变得容易; 泛型又称参数化类型,如ArrayListshape,尤其在容器使用中有积极作用; 总结:一切皆对象,单根继承,全动态内存分配 第2章一切皆对象 标识符实际是对象的一个引用,new操作符实现一个对象与引用的关联 寄存器是最快的存储区,但是Java程序不能直接控制它,不能在程序中感觉到寄存器存在的任何迹象。(CC允许向编译器建议寄存器分配的方式?) Java的引用存放在栈上,对象存放在堆上,堆和栈都位于RAM(随机访问存储器)。 程序中的常量直接放在代码的内部(代码段?),在嵌入式系统常量也可以放在ROM(只读存储器) 对于是基本类型的简单变量,用new创建对象并不是最有效,所以采用在栈上创建一个非引用的自动变量,直接存储值,其他对象都放在堆上 所有的数字类型都有正负号,没有无符号数值类型 BigInteger,BigDecimal没有对应的基本类型 Javadoc有嵌入式html和标签两种形式 编码采用驼峰风格,类名首字母大写,标识符第一个字母小写 第3章操作符 Java函数参数传递缺省是引用传递而不是c的值传递 12E13代表12x10负13次方,E并不是数学中的自然对数基数2。718,这是历史语言惯例而已。 左移低位补0,右移按数的符号,整数高位补0负数则高位补1。新增一种无符号右移,无论正负都在高位插入0 第4章控制执行流程 Foreach语法for(floati:f)f是一个浮点数组 第5章初始化与清理 重载方法必须有独一无二的参数类型列表。返回值不同是不能用来区分重载,因为调用者可能不关心返回值,那么编译器就无法判断该调用哪个函数 在构造函数中可以通过this调用另一个构造函数,但是必须放在开头并且只能调一个,第2个调用会编译错误 Static主要用于表达全局函数,有点不那么面向对象 Finalize函数用于释放不是用new分配的内存,例如通过C的native方法分配的内存,它不总能保证被调用,只有在垃圾收集决定回收还对象时才会调用。可以用它调用的时机来发现一些很难定位的程序问题。 垃圾回收一方面回收内存,一方面使堆中的对象紧凑排列。实现原理通常有引用计数法,但是比较慢,对循环引用的对象难以处理。 另一种是追溯引用法,最终能找到一个活的对象。停止复制就是将所有活的对象复制到另一个堆没有被复制的就是垃圾。如果垃圾少会使用自适应模式(根据效率在停止复制和标记清扫模式之间切换),标记清扫 这种方式不会整个复制只是把非垃圾标记出来,标记完成后才开始清理。并整理剩下的对象以保持空间连续。早期虚拟机就使用这种机制。垃圾回收时程序会暂停。复制也可以把需要复制的对象拷贝到废弃的块中,块用来帮助做回收。每个块用代数记录块是否存活。大型对象通常会增加代数并不会复制。 JIT(Justintime)技术用于提升速度,它会把全部或部分程序翻译成本地机器码。这种编译后的代码加载可能会很零散,所以有种惰性评估的方式,在程序执行到的时候才用JIT编译成机器码,这样程序执行的次数越多就越快 static只能修饰成员变量,不能修饰局部变量,静态初始化只有在必要时才进行。 显示静态初始化和初始化代码是先与对象构造函数执行,不过静态初始化只执行一次 第6章访问权限控制 Importstatic是导入包中的静态函数 Public修饰class一个文件只能有一个且文件名必须和类名一致,如果不带public则该类只能在包内访问,名字也可以与文件不一样 第7章复用类 Override关键字要求修饰的函数的基类一定有相同参数和返回值的函数,否则会编译错误 是否选择要继承一个类,看你是否有将它向上转型的需求 Final有点类似const意味着类不可继承,函数不可重载,变量不可改变 第8章多态 多态分离做什么和怎么做 在基类的构造函数中调用多态函数,由于派生类对象并未构造完成,可能导致该多态函数引用的类变量未完全初始化,但是调用final函数是安全的,因为他不能被继承 向下转型会自动检查类型并抛出异常 第9章接口 抽象类是普通类和接口之间的中庸之道,abstract抽象函数等同于纯虚函数,可以只有部分函数是抽象函数 接口和抽象类都可以有成员变量,但接口的成员变量缺省是static和final的(抽象类反之),接口中的函数和变量默认是public的 接口只能派生自接口,可以多继承 class中的私有接口可以被公有嵌套类实现,则该嵌套类只能被自身使用。另外私有接口可以强制接口中的方法不要添加类型信息,也就是不允许向上转型 设计应该优先选择类而不是接口,只有当接口的需求变得明确时再进行重构 第10章内部类 内部类和组合是完全不同的概念,它了解外部类并能与之通信 内部类能访问外部类的所有成员并拥有所有的访问权(c只能隐藏代码,与外部类没有联系) 在创建外部类对象前不可能创建内部对象,但静态内部类没有这个限制,需要用外部对象。new内部类来创建内部对象 匿名内部类是通过创建一个继承自某一个具体类的匿名对象来生成。如returnnewContent(){。}; 如果不想内部类与外界产生关系,可以将类声明为static,又名嵌套类,内部类不能有static数据和字段,但嵌套类可以有所有类型的数据 Java通过接口和内部类来完成多重继承 第11章持有对象 TreeMap按照键的升序保存,LinkedHashMap按照插入的顺序保存 Iteratorremove会删除next返回的元素,因此需要先调用next再调用remove 第12章异常 可以将一个异常的cause放入另一个异常以形成异常链 Runtimeexception不需要异常说明,由虚拟机自动抛出。但代码可以抛出运行时异常 finally用于将资源恢复到初始状态 抛出异常的finally中再抛出一个新的异常会导致老的异常被覆盖。前一个异常没处理就抛出新的异常是不好的习惯。 在finally返回会安静的丢掉该异常 第13章字符串 System。out。formatprintf等价并与C的使用方式相同 String的正则表达式 第14章类型信息 使用RTTI可以从多态的基类引用中查询到该引用指向的对象具体类型,Java使用Class对象来执行RTTI。可以通过forName,getInterfaces,getSuperClass来获取 运行时的类型信息由Class对象来表示 可以通过类字面变量来获取对象,如:FancyToy。class 第16章泛型 Java的泛型是后支持的,采用了类型擦出的方式,不如C支持得彻底 第17章容器深入研究 只有在需要容器元素是有序的时候才使用treesettreemap Collection有大量工具函数帮助操作容器 第二十一章并发 Thread。yield让系统切换线程 Excutor用来管理线程的生命周期,用线程池赋值 Runnable是独立执行的工作任务,不返回值。如果要返回值需要用Callable 后台线程必须在线程启动之前将其设为Daemon 对于同一个对象,所有的synchronized方法共享同一把锁,针对每个类也有一个锁,所以synchronizedstatic方法可以防止对static数据的并发访问 原子操作是不能被线程上下文切换所打断,java中long和double不是原子的,因为会发生字撕裂,如果用volatile就可以是其成为原子的。 可视性问题是指在多处理器系统中一个线程修改了数据只会保存在本地处理器的缓存中,因此不同的任务会有不同的视图。volatile解决了可视性问题,当对其变量操作时,其结果一定会写入主存,及时他被缓存在本地处理器缓存,读操作都会从主存中读取。 易变性(可视性)和原子性是两个不同的概念,如果一个域由synchronized保护,那么他不用声明为volatile。synchronized是在某一对象上同步,通常是类的this,如果在不同的对象上同步则不会互相互斥。 临界区也称同步控制块 中断线程Cancel不能中断IO操作或者Synchronize锁 调用sleep和yield时并没有释放锁,但是调用wait时对象锁是释放了的。 CopyOnWrite是指写入时将数据赋值一份修改,原值还可以被其他线程读取,然后通过一个原子操作将复制的数据整个修改保证一致性 CountDownLatch和CycleBarrier都是栅栏的语义,一个线程在这个对象上阻塞,其他线程如果完成某项任务就减小1,当这个一个数值减到0阻塞的线程才能继续运行。CycleBarrier可以重置这个值,而CountDownLatch却是一次性的。