读了1-14章。
这本书真的不适合初学者,可能比较适合有一两年Java经验的人来读。
学习真的是一个螺旋递进的过程。刚开始学Java基本语法,书上看到的很多东西觉得过于细枝末节,没见过,用不上,导致书看不下去了。后来学Java Web,发现实际应用中真的会用到很多东西,有了书到用时方恨少的感觉,觉得不补充基础知识就学不下去了。于是又拿来这本书看,前14章算是认真读了,还做了笔记,算是有所收获,但也越来越觉得读不下去了。读到第15章 泛型,实在读不下去了。
接下来打算继续学Java Web,再有书到用时方恨少的感觉的时候回归《Core Java》,初学者还得看这本。
第二章 一切都是对象
在Java中你所做的全部工作就是定义类,产生那些类的对象,以及发送消息给这些对象。
类中两种类型的元素:字段和方法。
Java消除了“向前引用”问题。
当声明一个事物是static时,就意味着这个域或方法不会与包含它的那个类的任何对象实例关联在一起。所以,即使从未创建某个类的任何对象,也可以调用其static方法或访问其static域。
一个static字段对每个类来说都只有一份存储空间,而非static字段则是对每个对象有一个存储空间。
第三章 操作符
整数除法,或将小数转换为整型时,会直接去掉结果的小数位,而不是四舍五入。
关系操作符==和!=适用于对象。比较的是对象的引用。
equals()的默认行为是比较引用。大多数类库都实现了equals()方法,用来比较对象的内容。
直接常量:后缀L代表long,F代表float,D代表double。前缀0x十六进制数,0八进制数。(以上字母大小写均可)
指数记数法:float f = 1e-43f;
第四章 控制执行流程
foreach可用于数组和其它任何Iterable对象。
for(float x : f){ }
label:位于刚好在迭代语句之前。使用标签的唯一理由是因为有循环嵌套存在,而且想从多层嵌套中break或continue.
第五章 初始化与清理
构造器名称与类名完全相同(首字母大写)。
构造器没有返回值。
编译器暗自把“所操作对象的引用”作为第一个参数传递给调用的方法。
this关键字只能在方法内部使用,表示对“调用方法的那个对象”的引用。
在方法内部调用同一个类的另一个方法,就不必用this.
在构造器中,可以用this调用另一个构造器,且必须将调用置于最起始处。
Flower(int a){
this.a = a;
}
Flower(String s, int a){
this(a);
this.s = s;
}
static方法就是没有this的方法。
在static方法的内部不能调用非static方法。
方法的局部变量未初始化,得到编译时错误。
类的字段如果是基本类型,未初始化会得到默认初始值。
类里定义一个对象的引用,如果不初始化,此引用得到特殊值null.
显式的静态初始化:静态块static{},这段代码仅执行一次:当首次生成这个类的一个对象时,或者首次访问属于那个类的静态数据成员时。
将一个数组赋值给另一个,只是复制引用。
所有数组都有一个固有成员length.
第六章 访问权限控制
Java源代码文件通常被称为编译单元,必须有一个后缀名.java。编译单元内可以有一个public类,该类的名称必须与文件名相同。每个编译单元只能有一个public类。
第七章 复用类
当创建了一个导出类对象时,该对象包含了一个基类的子对象。
如果没有默认的基类构造器,或者想调用一个带参数的基类构造器,就必须用关键字super显式地编写调用基类构造器的语句,并且配以适当的参数列表。
想要覆写方法时可以添加@Override注解,如果不留心重载而非覆写了这个方法,编译器会生成错误信息。
final基本类型使数值恒定不变,而用于对象引用,final使引用恒定不变。
一种典型的定义常量的方式:定义为public则可用于包之外;定义为static则强调只有一份;定义为final则说明是一个常量。
Java允许在参数列表中以声明的方式将参数指明为final.
final方法:防止任何继承类修改,不会被覆盖。
所有的private方法都隐式地指定为final.
final类:不能被继承,没有子类。
第八章 多态
后期绑定,含义是在运行时根据对象的类型进行绑定。也叫动态绑定或运行时绑定。
除了static方法和final方法(private方法属于final方法),其它所有方法都是后期绑定。
在构造器内部调用正在构造对象的某个动态绑定方法,结果可能难以预料。因此编写构造器应用尽可能简单的方法使对象进入正常状态,如果可以的话,避免调用其它方法。
Java中所有转型都会得到检查。在运行期间对类型进行检查的行为称作“运行时类型识别”(RTTI)。转型失败会返回ClassCastException.
第九章 接口
抽象方法,仅有声明而没有方法体。
包含抽象方法的类称作抽象类。
要想创建一个接口,用interface关键字取代class关键字。
接口可以包含域,这些域隐式地是static和final的。
即使不显式声明,接口中的方法必须是public的。
使用接口的核心原因:为了能够向上转型为多个基类型(以及由此带来的灵活性)。第二个原因与使用抽象基类相同:防止客户端程序员创建该类的对象,并确保仅仅是建立一个接口。
适配接口:我们可以在任何现有类上添加新的接口,所以这意味着让方法接受接口类型,是一种让任何类都可以对该方法适配的方式。这就是使用接口而不是类的强大之处。
第十章 内部类
一种典型的情况是,外部类将有一个方法,该方法返回一个指向内部类的引用。
如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须具体地指明这个对象的类型:OuterClassName.InnerClassName.
内部类拥有对其外部类所有成员的访问权。
需要获得对外部类对象的引用,可以使用外部类的名字后面紧跟.this。
除非创建的是嵌套类(静态内部类),在拥有外部类对象前,不可能创建内部类对象。
.new语法:
Outer o = new Outer();
Outer.Inner i = o.new Inner();
嵌套类:当内部类是static时,要创建嵌套类对象,并不需要其外围类的对象。嵌套类没有this引用指向外围类对象。
一个内部类被嵌套多少层并不重要,它能透明地访问所有它所嵌入的外围类的所有成员。
第十一章 持有对象
与数组不同,Java容器类都可以自动地调整自己的尺寸。
为什么需要内部类:
一般来说,内部类继承自某个类或实现某个接口,内部类的代码操作创建它的外围类的对象。
每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。
内部类有效地实现了“多重继承”。也就是说,内部类使得允许继承多个非接口类型(类或抽象类)。
通过使用泛型,就可以在编译期防止将错误类型的对象放置到容器中。
List:
ArrayList,优势随机访问元素。
LinkedList,优势插入和删除操作,更多特性。
Set:不保存重复元素。常用HashSet实现,它专门对快速查找作了优化。
Map:将对象映射到其它对象的能力。Map可以返回它的键的Set,它的值的Collection,它的键值对的Set。
Queue:队列是先进先出容器,常被当作一种可靠的将对象从程序的一个区域传送到另一个区域的途径。
迭代器Iterator:
(1)使用方法iterator()要求容器返回一个Iterator。Iterator将准备好返回序列的第一个元素。
(2)使用next()获得序列中的下一个元素。
(3)使用hasNext()检查序列中是否还有元素。
(4)使用remove()将迭代器新近返回的元素删除。
实现Collection就意味着需要提供iterator()方法。
Iterable接口,包含一个产生Iterator的iterator()方法,并且Iterater接口可被foreach用来在序列中移动。
容器不能持有基本类型,但有自动包装机制帮助。
第十二章 通过异常处理错误
异常说明,使用throws关键字,表明方法可能抛出的异常类型。
方法代码中产生了异常:要么处理这个异常,要么在异常说明中说明这个方法将产生异常。
可以声明方法将抛出异常,实际上却不抛出。
Throwable类:Error表示编译时和系统错误;Exception通常是程序员关注的基本类型。
在编译时被强制检查的异常称为被检查的异常。从RuntimeException继承的异常,可以在没有异常说明的情况下被抛出,它们会自动被虚拟机抛出,也被称为不受检查异常。
当要把除内存以外的资源恢复到它们的初始状态时,就要用到finally子句。
当覆盖方法的时候,只能抛出在基类方法异常说明里列出的那些异常。
第十三章 字符串
String对象是不可变的,具有只读特性。每一个看起来会修改String值的方法,实际上都是创建了全新的String对象。
正则表达式。
第十四章 类型信息
通常,你希望大部分代码尽可能少地了解对象的具体类型,而是只与对象家族中的一个通用表示打交道。所以多态是OOP的基本目标。
所有的类都是在对其第一次使用时,动态加载到JVM中的。当程序创建第一个对类的静态成员引用时,就会加载这个类。因此Java程序在它开始运行之前并非被完全加载,其各个部分是在必须时才加载的,这一点与许多传统语言不同。
一旦某个类的Class对象被载入内存,它就被用来创建这个类的所有对象。
Class.forName("Name");这个方法是Class类的一个static成员,返回的是一个Class对象的引用。
如果已经有一个感兴趣的类型的对象,就可以通过getClass()方法来获取Class引用。
类字面常量:ClassName.class;生成对Class对象的引用。
泛化的Class引用:创建一个Class引用,它被限定为某种类型,或该类型的任何子类型:
Class<? extends Number> b = int.class;
关键字instanceof,返回一个布尔值,告诉我们对象是不是某个类型的实例。
Class.isInstance()方法提供了动态地测试对象类型的途径。
对RTTI来说,编译器在编译时打开和检查.class文件。而对于反射机制来说,.class文件在编译时不可获取,在运行时打开和检查.class文件。