一. Java设计的初衷
简单: 没有头文件、指针、结构、联合、操作符重载、虚基类等特性
面向对象:关注对象和接口
网络功能:有扩展的网络库,网络编程容易
健壮:Java采用的指针模型消除了重写内存和损坏数据的可能性
安全:实现了虚拟机和安全库,防范运行时堆栈溢出,防范在自己的处理空间之外破坏内存,防范未经授权读写文件
体系结构中立:字节码是实现体系结构无关的基石
可移植:数据类型有固定的大小,int永远为32位。二进制数据以固定的格式进行存储和传输,消除了字节顺序的困扰。字符串是以标准的Unicode格式存储的。
解释型:Java解释器可以在任何移植了Java解释器的机器上执行Java字节码。
高性能:即时编译器
多线程:Java把多线程的实现交给了底层的操作系统或线程库来完成。只要操作系统支持,Java多线程就可以利用多个处理器。
动态:Java允许程序员知道对象的结构和行为。
二.Java程序设计
JDK:Java Development Kit 编写Java程序的程序员使用的软件
JRE:Java Runtime Environment 运行Java程序的用户使用的软件
三.Java基本的程序设计结构
访问修饰符public用于控制程序的其它部分对这段代码的访问级别
关键字class表明Java程序中的全部内容都包含在类中
每个Java应用程序都必须有一个public的main方法
以/**开始, 以*/结束的注释可以用来自动地生成文档
Java是一种强类型语言。在Java中,一共有8中基本数据类型,其中4种整型,2种浮点型,1种用于表示Unicode编码的字符单元的字符型char和1种用于表示真值的boolean型。在Java中,没有无符号类型,整型的范围与运行Java代码的机器无关。
int是4个字节的,能表示的最大正数大约是20亿,一般用于表示id够用了。
float是4个字节的,能表示的有效位数6到7位,经常会不够用。
在Java中,char类型用UTF-16编码表示一个代码单元。
Character类的isJavaIdentifierStart和isJavaIdentifierPart方法可以判定字符是否是字母。
Java中的每一个变量都属于一种类型,不区分变量的声明与定义,变量定义后需要初始化,可以与定义放在同一行,也可以单独的一行。final关键字声明常量。const是Java保留的关键字,但目前没有被使用。
Java中的运算符有自增(减)运算符,关系运算符和boolean运算符,位运算符。
关于自增运算符,有一个段子:某些程序员认为C++语言应该叫做++C语言,哈哈。。
boolean运算符存在“短路”的行为。前面的表达式已经能得出整个表达式的结果时,不会计算后面的表达式。
>>位运算符用符号位填充高位,>>>用0填充高位。
strictfp关键字和StrictMath类:关注结果的可移植性
静态导入
二元操作时转换的优先级是double > float > long > int, 这里的double优先级指的是其中有一个操作数是double。
Java没有内置的字符串类型,而是在标准Java类库里提供了一个预定义类String。每个用双引号括起来的字符串都是String类的一个实例。
==运算符不能检测两个字符串是否相等,它只能确认两个字符串是否放在同一个位置上。
switch语句将从选项值相匹配的case标签处开始执行直到遇到break语句,或者执行到switch语句的结尾。
BigInteger的使用
数组一旦创建,无法改变大小。如果需要运行时动态改变数组大小,使用array list.
Arrays.copyOf用来增加数组的长度,第二个参数是新数组的长度。它是创建了新数组。
Arrays.sort对数值型数组进行排序。Arrays.binarySearch二分查找数组元素。Arrays.deepToString打印二维数组。
四.对象与类
面向对象的程序是由对象构成的,每个对象包含对用户公开的功能部分和隐藏的特定的实现部分。不关心对象是哪儿来的,关注的是用它来解决实际问题。要想创建一个完整的程序,应该将若干类组合在一起,其中只有一个类有main方法。
类是构造对象的模板或蓝图。
对象的3个主要特性:行为、状态、标识。行为由可调用的方法定义,状态是对象所保存的描述当前特征的信息。每个对象都有唯一的身份。实例域建议使用private修饰,在所有的方法中不要命名与实例域相同的局部变量。
类之间的关系有:依赖、继承、聚合。应该尽量减少类之间的依赖。
在Java中,任何对象变量的值都是对存储在另外一个地方的一个对象的引用。new操作符的返回值也是一个引用。不要编写返回可变对象的引用的访问器方法。如果需要返回一个可变对象的引用,应该首先对它进行clone.
构造器与类同名,无返回值,可以有参数也可以无参数,与new结合使用。构造对象时必须初始化被final修饰的实例域,初始化之后这个实例域不能被修改,这里是指它不能重新引用另一个对象,并不意味这所引用的对象不能被修改。 一个方法可以访问所属类的所有对象的私有数据。
System中声明的out对象是一个公有的静态常量。一个方法不需要访问对象状态,只需要访问类的静态域的时候,应该声明为静态方法。
将参数传递给方法时,值调用表示方法接收的是调用者提供的值,引用调用表示方法接收的是调用者提供的变量地址。Java程序设计语言对对象采用的调用不是引用调用,而是值调用。实际上,对象引用进行的是值传递。Java里总是采用值调用。
Java中要完整地描述一个方法,需要指出方法名和方法的参数类型,它们构成了方法的签名。默认构造器是指没有参数的构造器,一个类如果没有默认构造器,系统会提供一个,将所有的实例域设置为默认值。虽然通常把初始化块放在构造器里,但是如果有初始化块,那么先执行初始化块,再执行构造器。
实例域被设置成一个有意义的初值,是一个好的习惯。可以赋值成一个常量,也可以使用静态方法来赋值。
类和变量默认的作用域是包内可见。类路径中的不同项目之间,Unix下使用冒号来分隔,Windows下使用分号来分割。从Java SE6开始,jar文件目录中可以使用通配符‘*’。默认的类路径包含当前目录,如果用户自定义后,有可能不包含当前目录。
类路径使用-classpath(-cp)指定,不提倡设置环境变量CLASSPATH,不提倡把jar包放在jre/lib/ext下,因为你会忘掉这件事情。
类设计的技巧:数据设计为私有;对数据初始化,最好不要依赖于系统对实例域设置默认值;不要在类中使用过多的基本类型;不是所有的域都需要独立的域访问器和域更改器;使用标准格式进行类的定义;将职责过多的类进行分解;类名和方法名要能体现它们的职责。
五.继承
由于子类的构造器不能访问超类的私有域,它必须调用超类的构造器来对这些域进行初始化。可以通过super实现对超类构造器的调用,super必须是子类构造器里的第一条语句。super和this关键字不同,它并不是一个引用,只是告诉编译器调用超类的方法。
一个对象变量能够引用多种实际类型的现象叫做多态,在运行时能够自动地选择调用哪个方法的现象称为动态绑定。
private,static,final修饰的方法编译器将进行静态绑定。
在覆盖一个方法的时候,子类的方法不能低于超类方法的可见性。Java中用于控制可见性的4个访问修饰符:private,public,protected,默认。这里默认指的是无修饰符号,无修饰符时对本包可见。
使用final可以避免动态绑定带来的开销,但在现代Java虚拟机里,性能的提升作用可能不大。因为现代Java虚拟机的编译器的内联优化可以回退。
抽象方法起着占位的作用,有抽象方法的类也必须声明为抽象的。抽象类不能被实例化,但可以定义一个抽象类的对象变量,引用子类对象。
Object是所有类的超类,它的方法有equals,hashCode,toString,getClass,clone
在Object里,equals用于判断两个对象是否有相同的引用。然而,它的本意是用来比较两个对象是否相等。如果两个对象具有相同的引用,那么它们当然相等。但在大多数场景下,我们需要检测的是两个对象的状态的相等性。如果两个对象的状态相等,那么应该认为它们是相等的。Java语言规范要求equals具有自反性、对称性、传递性、一致性、非null不等于null这5条特性。
使用instanceof或是getClass来判断相等性,取决于对象相等概念的定义是由超类还是由子类来主导。
覆盖超类的方法时,加上@Override标签是个好习惯。
每个对象都有一个默认的散列码,值为对象的存储地址。如果重新定义equals方法,就必须重新定义hashCode方法。换句话说,equals必须与hashCode的定义一致。
基本数据类型没有toString方法。
ArrayList的方法有size,add,set,get,remove,ensureCapacity,trimToSize。set只能对已经存在的对象进行更改。ArrayList随机插入和删除的性能不好。ArrayList后面的<>里的类型不能是基本类型,但可以使用基本类型的包装器类型,比如Integer。自动拆箱时会调用非静态方法intValue。Integer还有一些有用的静态方法:parseInt,valueOf,toString。
enum对象的构造器是私有的。Enum类的方法有valueOf,toString,ordinal,compareTo.
在程序运行期间,Java运行时系统始终为每个对象维护一个RTTI。使用反射的主要对象是工具开发者,而不是应用程序员。
Throwable是Exception的超类,Throwable里的printStackTrace用于打印栈轨迹。
继承设计的技巧:将公共操作和域放在超类;不要使用受保护的域;继承适合is-a的关系;保证继承的方法都有意义;覆盖方法时不要改变预期的行为;使用多态而不是类型信息;不要过多地使用反射。
六.接口和内部类
接口不是类,而是对类的一组需求描述。接口中的所有方法自动地属于public。
接口绝不能含有实例域,也不是在接口中实现方法。
如果要对对象进行比较和排序,让对象实现Comparable接口。
Java里对对象的拷贝默认是浅拷贝。
内部类定义为私有,但内部类的实例域定义为公有,也是安全的。内部类的对象总有一个隐式引用,指向创建它的外部类对象。内部类是一种编译器现象,与虚拟机无关。
局部类不能用public或private进行修饰,它的作用域限定在了声明这个局部类的块中。
因为构造器的名字必须与类名相同,而匿名类没有名字,所有匿名类没有构造器。
代理类可以在运行时创建全新的类,实现指定的接口。
七.图形界面
AWT abstract window toolkit
八.事件处理
监听器 适配器
九. Swing和设计模式
设计模式的灵感来自建筑师Christopher Alexander对公共和私人居住空间的建筑设计模式的分类。
MVC,即“模型-视图-控制器”模式,背景是显示信息和接收用户输入的用户界面系统。对于同一数据而言,可能需要同时更新多个可视化表示,于是解决方案演变成了现在这样,把这些功能分布到3个独立的交互组件:模型、视图和控制器。
在AWT和Swing设计中,常用的模式还有:组合(容器和组件),装饰(带滚动条的面板),策略(布局管理器)。
十. 部署应用程序和applet
jar包的META-INF下有个MANIFEST.MF文件,里面有很多节,记载了jar包的信息。-m参数可以把编辑后的MANIFEST.MF打入jar包。Java web start程序有个jnlp文件,tomcat默认的MIME里设置了它的启动程序。
十一. 异常、日志、断言和调试
所有的Error和Exception都是Throwable的子类。
Error描述了Java运行时系统的内部错误和资源耗尽错误。应用程序不应该抛出这种类型的对象。
Exception又分解为两个分支:RuntimeException和其它异常。由程序错误导致的异常属于RuntimeException,包括错误的类型转换、数组越界访问、访问空指针。而其它异常通常是程序本身没有问题,由于I/O错误这类问题导致,包括试图在文件尾部后面读取数据、试图打开一个错误格式的URL、试图根据给定的字符串查找类但并不存在。这样的异常又称为已检查(checked )异常。编译器将核查是否为所有的已检查异常提供了异常处理器。
一个方法必须声明所有可能抛出的已检查异常,而未检查异常要么不可控制(Error),要么就应该避免发生(RuntimeException)。如果调用了一个抛出已检查异常的方法,就必须对它进行处理,或者将它传递出去。在覆盖时,子类方法声明的已检查异常不能超过超类的声明范围。
一旦方法抛出了异常,这个方法就不可能返回到调用者。