Java的哪些事
Java的哪些事
--------------------------------------------------
Java学习分2个方面: Java语法与Java类库
Java: A simple, object-oriented, network-savvy, interpeted, robust, secure, architecture-neutral, portable, high-performance, multithread, dynamic language.
第一部分: Java语法
一. 字符集: Java使用Unicode字符集,采用UTF-16编码.
Unicode 1.0的code point从U+0000到U+FFFF,只有一个code panel. 由于编码有余,UTF-16对Unicode 1.0保留Surrogate Area(U+D800~U+DFFF), Surrogate Area不表示任何code point.
Unicode 2.0的code point从U+0000到U+10FFFF,分为17个code panel,其中第0个code panel称为BMP(Basic multipline panel),涵盖Unicode 1.0中的经典code point. 由于编码不足,UTF-16对Unicode 2.0中的Supplementary character采用巧妙的编码方式: 将BMP的Surrogate area分成high surrogate area(U+DC00~U+DFFF,共1024 bytes), low surrogate area(U+D800~U+DBFF,共1024 bytes), 各从high surrogate area与low surrogate area取4 bytes组成8 bytes的Surrogate pair共同表示一个Supplementary character,规定surrogate pair才能表示supplementatry character,单独的high surrogate area或者单独的low surrogate area都没有意义.这样,可以表示(4*256)*(4*256)=16*65535个supplementary character,即16个code panel.
简言之,在Unicode 2.0中UTF-16对Supplementary Character将BMP的字符编码为16位,将Supplementary Character编码为32位. 所以字符要用code point来表示,char只能表示BMP的字符.受此影响的API主要用String,StringBuffer与Character.
1.1 计算字符串的个数不能再用String.length():
int codeUnitLength=String.length();
int codePointCount=String.codePointCount(0,codeUnitLength);
1.2 遍历字符串:
for(int i=0,n=String.length();i<n;i++){
int codePoint=String.codePointAt(i);
if(Character.isSupplementaryCodePoint(codePoint)){
i++;
}
//do something to codePoint.
}
1.3 Java中全有字符可用Unicode转义序列替换.
//2010年1月1日 星期五
JDK 1.5前使用Unicode1.0(U+0000~U+FFFF)字符集, 采用UTF-16编码.
编码方式: 每个Code Point编码16bit.
JDK 1.5后使用Unicode2.0(U+0000~U+10FFFF)字符集, 采用UTF-16编码.
编码方式: UTF-16将Unicode2.0分成17个Code Panel, 其中第0字面涵盖Unicode1.0, 称为Basic Multilingual Panel, BMP.其它16字面涵盖所有Supplementle characters. UTF-16对BMP字符编码不变,依然编码16bit,但对Supplementle character采用巧妙的编码形式, 它将BMP的Surrogate area(U+D800~U+DFFF,共2048bit)分成Hign surrogate area(U+DC00~U+DFFF,共1024bit)与Low surrogate area(U+D800~U+DBFF,共1024bit),然后从Hight,Low Surrogate area各取4bit组成8bit的Surrogate pair,共同表示一个Supplementle character.这样Supplementle character编码32bit,其前16bit必须落入BMP Surrogate area, 很容易知道一个字符是否Supplementle character.
JDK 1.5后,字符不应该再用char表示,应该使用Code point表示
//2010年8月7日: 简结
字符是信息的基本载体.
字符集是字符的并集.
计算机只能表示0,1. 将字符转换成01表示, 称为编码.
编码的基本概念:
code unit: 编码的单位长度.
code point: 编码的码值.
code panel: 编码的空间.
UTF-16编码:
code unit是16 bytes
code point从U+0000到U+10FFFF
code panel共17个
其中第0 code panel包含所有classic unicode character, 称为BMP(Basic Multingual Panel).
其余16个code panel包含所有supplementary character.
UTF-16是一种变长(variable-length)编码. 采用一种巧妙的方式处理supplementary character:
将BMP的surrogate area(从U+D800~U+DFFF,共2048 bytes)分成low surrogate area(从U+D800~U+DBFF,共1024 bytes)和high surrogate area(从U+DC00~U+DFFF,共1024 bytes),然后各取8 bytes组成一个surrogate pair,作为一个code unit.这样可以表示16*256*256=16*65536个supplementary character,即16个code panel.
所以, supplementary character码长2个code unit, 必须注意!!!
--------------------------------------------------------------
二. 词汇
2.1 保留字(keyword): Java有50个保留字,true与false是直接量(literal)
abstract continue for new switch
assert default goto package synchronized
boolean do if private this
break double implements protected throw
byte else import public throws
case enum instanceof return transient
catch extends int short try
char final interface static void
class finally long strictfp volatile
const float native super while
注意:
Java的关键可以分为几大类:
I. 类型定义
II.控制语句
III. 继承封装
IV. 异常捕获
V. 成员修饰
VI. 命名空间
VII. 运算符
//2010年1月1日 星期五
Keywords are reserved words that have special meanings within the language syntax.
2.2 标识符(Identifier):
Java标识由字母,数字,下划线(_),美元符($)组成,并且不能以数字打头,不能与保留字相同.
注意:
I.因为JVM编译器解析的时候无法区分数字直接量或数字打头的标识符,所以标识不能由数字打头.
II.因为Java使用Unicode字符集,其字母不限制于Lation单词.所以标识符可以是汉字,可用Character.isIdentifierStart()和Character.isIdentifierPart()检测.
//2010年1月1日 星期五
Identifiers are names for constants, variables, functions, properties, methods and objects. The first character must be a letter, underscore or dollar sign. Following characters can also include digits. Letters are A to Z, a to z, and Unicode characters above hex 00C0. Java styling uses initial capital letter on object identifiers, uppercase for constant ids and lowercase for property, method and variable ids.
Note: an identifier must NOT be any word on the Java Reserved Word List.
2.3 直接量(Literal): 由解析器直接识别的文字.
//2010年8月6日
直接量(literal):
boolean直接量:
true,
false
char直接量:
'x',
转义字符
interger直接量:
10进制:
8进制: 以0打头
16进制: 以0x打头
long型: 以L结尾
float直接量:
小数形式
10进制指数形式: 尾数,底数,指数都是10进制.
16进制指数形式: 尾数是16进制, 底数是2进制, 指数是10进制
float型: 以F结尾
Double型: 以D结尾
String直接量:
"..."
array直接量:
{...}
Object直接量:
null
注意:直接量(Literal)一般指基本类型而言.不同基本类型的直接量:
整型: 8进制以0打头. 16进制以0x打头. 长整型以L结尾.
浮点型: 小数形式, 指数形式: 尾数X(基)^指数, 基为10用e表示(尾数是10进制,基是10,指数是10进制), 基为16用p表示(尾数是16进制,基为2,指数是10进制)
单精度以F结尾,双精度以D结尾.
布尔型: true, false
字符型: 单引号括住的字符或者转义序列(escape sequence).
Java的Escapse Sequence共10类:
\b: backspace
\f: formfeed
\n: newline
\r: carriage return
\t: horizontal tab
\\: backslash
\": double quote
\': single quote
\###: Octal encoded character
\uHHHH: Unicode encoded character
2.4 运算符(Operater):
参见<运算符与表达式>
2.5 空白符(White-char):
2.6 注释(Comment):
注意: Java的注释有3种, 单行(//), 多行(/*..*/), 文档(/**..*/)
三. 数据类型,常量和变量
数据类型指数据的存储表示.
Java存储模型:
程序区
------
静态区
------
堆
------
栈
其中,实例的对象创建在堆中,实例的引用创建在栈中.对象与引用是实例必不可少的二部分.
1. 数据类型分类
Java数据类型分为基本类型和引用类型.
基本类型包括: 布尔型,字符型,整型,浮点型
引用类型包括: 数据, 类, 接口, 枚举, 注解
引用类型从多态角度又分为编译期类型与运行时类型.
引用类型从定义角度又分为原生类型与泛生类型.
//2010年1月3日 星期日
基本类型:
(1)布尔型: boolean
直接量: true, false
Java的布尔型直接量为true,false,并且不能参与数值运算;
C/C++的布尔型变量: 非0为真,0为假;真值为1,假值为0;可以参与数值运算.
(2)字符型: char
直接量: 单括的字符或转义字符
1)Java字符使用Unicode字符集,采用UTF-16编码;C/C++的字符型变量点8位.
Java字符型和C/C++的字符型一样,可以参与数值运算.
(3)整型: byte,short,int long
直接量: 10进制,
8进制,
16进制,
long型
(4)浮点型: float,double
直接量: 10进制小数形式
10进制指数形式
16进制指数形式
单精度形式
双精度形式
1)浮点型可以除0, 结果是INFINITE或NAN, 所以浮点型的算术运算需用isInfinite(),isNaN()检测结果可用性.
2)浮点型存在误差, 所以浮点型的关系运算不准确.
-----------------------------------------------
引用类型:
(1)数组:
同构元素的有序集.
直接量: {...}
1)数组的getClassLoader()
基本类型的ClassLoader是bookstrap class loader,所以getClassLoader()返回null类型.
数组类型的ClassLoader是由Java Runtime动态创建的, 其getClassLoader()返回元素类型的ClassLoader.
所以不能使用Class.newInstance()动态创建数组, 需用Array.newInstance()动态创建.
2)声明数组不允许指定维度,定义数组必须指定大小.
数组类型确切地说是一个指针,多维数组不必是齐整的.
3)数组的属性:length, class.
4)数组的复制:
System.arraycopy(src,srcOffset,dest,destOffset,length);
Array.copyOf(src,length);
后者除了复制数组,还可以扩充数组.例如:
int[] a=new int[10];
int[] b=Arrays.copyOf(a, a.length*2);
无论何者,复制都是浅拷贝.
5)多维数组: Java的N维数组可以理解成一维数组的N-1维向量. 例如:
int[] a=new int[3];
int[][] aa=new int[3][];
int[][][] aaa=new int[3][][];
除第一维度必须在初化时指定. 其它维度可以对应元素初始化时再指定. 因为Java的数组更类似于一个指针, 而不要求对称!
(2)类: class
1)Object是所有类的基类.
(3)接口: interface
(4)枚举: enum
枚举与类相似,区别4点:
1)实例定义先于枚举定义, 实例之间用逗号","隔开, 实例定义与枚举定义之间用分号";"隔开.
2)枚举可以定义构造器与方法.
(2.1)构造器只能在定义内使用,定义外无法访问(所以无所谓private,public);
(2.2)预定义方法: Enum.values(), Enum.valueOf(), name(), ordinal(), getDeclareClass().
3)枚举可以用于switch-case-default.
4)枚举不能是Local
public void method(){
enum E{...};//compile error, Enum cannot be local
}
(5)注解: @interface
注解与接口类似, 其语法为:
@Target(PACKAGE|TYPE|FIELD|CONSTRUCTOR|METHOD|PARAMETER|LOCAL_VARIABLE|ANNOTATION_TYPE) 目标类型
@Retention(SOURCE|CLASS|RUNTIME) 保留策略
@Inherited 继承性
@Documented 文档化
modifiers @interface AnnotationName
{
type elementName();
或
type elementName default value;
}
1)注解只有元素的概念,没有域与方法的概念
2)注解的类型:
基本类型
String
Class
enum
注解
以上类型的数组
3)注解是源码的信息标签. 处理器读取这些信息并作相应处理. 否则注解没有用地.
2. 类型转换
(1)定义:将一种类型转换为另一种类型.
(2)分类:类型转换分自动转换与强制转换.
自动转换只发生在兼容的基本类型,不会丢失精度. 所以是安全的!!!
byte-->short-->int-->long-->double<--float
char-->int
强制转换只发生在同一类链, 其中向上强制转换是安全的,向下强制转换是危险的,需用instanceof或Class.isInstance()先作判定.
(1)定义: 一种类型转换为别一种类型
(2)分类: 自动转换,强制转换
(3)原则: 类型转换只发生在兼容的数值类型之间或继承链的类类型之间.
数值类型的低类型转换为高类型不会损失精度,是安全的,JVM自动转换. 例如:表达式求值会把左右操作数自动转换为高类型后再计算.
数值类型的高类型转换为低类型会损失精度,是不安全的,必须强制转换.
数值类型之间的合法转换:
byte->short->int->long
int->double<-float
char ->int
类类型的子类型转换为基类型是向上类型转换,或类型窄化.
类类开的基类型转换为子类型是向下类型转换.
向上类型转换是安全的, 例如基类类型可以引用子类实例,从而实现多态性.
向下类型转换是不安全的,必须先instanceof类型检测,再强制转换.
注意: C++中的布尔类型属于数值类型,但Java的布尔类型区别数值类型, 不能进行类型转换.
3.常量,变量及其特性
常量指值不变的量.
变量指值会变的量.
变量,常量具有4个基本要素: 存储类别, 数据类型, 作用域与生存期.
Java不允许自定义存储类别. 作用域为声明点到内层块}结束处. 生存期分为3种: 类, 实例, 局部.
变量的屏敝原则:
作用域或生存期相同的变量不能同名.
引申: 局部变量可以屏敝实例变量或类变量,但不能屏敝其它局部变量.
解释: static int a;
{
int a;//一个是类变量,一个是实例变量,并且二者定义块{}不同, 不同生存期,且不同作用域, 所以可以屏敝.
//2010年1月1日 星期五
此时a已经是局部变量,之前解释是错误的.
}
//2010年1月1日: 变量的生存期与初始化.
类变量与实例变量会自动初始化为类型的"零值".
局部变量不会自动初始化,引用前必须手工初始化,否则编译错误.
C/C++存在静态存储区的变量会自动初始化为类型的默认值,但auto变量需要显式初始化,否则引用不安全.
//2010年8月6日: Java与C++变量的比较
Java变量的生存期由其变量类型决定: 类变量,实例变量,局部变量;作用域也由类型变量决定.
C/C++变量的生存期由存储类别决定,作用域由声明位置决定.
Java的局变量引用前必须初始化,否则编译出错,并且局部变量不允许被屏敝.
C/C++的局部变量初始化前可以直接引用,但不安全,而且也允许被屏敝.
四. 运算符和表达式
1.运算符要素: 优先级,结合性,直接影响表达式结果.
2.常用运算分类:
从功能角度:
算术运算符: + - * / % ++ --
关系运算符: > < >= <= != ==
逻辑运算符: ! && ||
位运算符: ~ & | ^ <<(算术左移) >>(算术右移) >>>(逻辑右移)
赋值或复合赋值运算符: = += -= *= /= %= ~= &= |= ^= <<= >>= >>>=(只与算术与位运算符结合)
字符串连接: +
"+"是Java语言重载的字符连接运算符.当其有一个操作数为字串类型时生效.
Java不允许程序员重载运算符,这与C++不同.
实质上, Java提供StringBuffer(Thread-safe), StringBuilder的append()方法代替+操作,效率更好!
其它运算符: [] . ()
new
instanceof
?:
从操作数目角度:
一目运算符
二目运算符
三目运算符
3.运算符优先级及结合性
运算符 结合性
---------------------------------------------------------- ------------
[] . (方法调用)
! ~ ++ -- + - (强制转换) new
* / %
+ -
<< >> >>>
< <= > >=
== !=
&
^
|
&&
||
?:
= += -= *= /= %= &= |= ^= <<= >>= >>>=
4.运算符注意事项
(1) ()改变运算符优先级
(2) 不要使用生僻表达. 例如:
int a=10;
a=a++==0?++a:a--;
System.out.println(a);
//2010年1月3日 星期日
浮点型的算术运算与关系运算必须注意:
(1)浮点型可以除0, 算术运算结果可能是INFINITE(除0)或NAN(出错),需用isInfinite()与isNaN()检查结果可用性.
double a=1D/0;
System.out.println(a);
//结果是Infinite;
(2)浮点型存在误差, 关系运算结果未必准确,"天生不可靠"!
(3)严格浮点数运算与strictfp关键字:
严格浮点数运算: 计算过程严格遵循IEEE 754标准,即计算结果是可预料的.
Java使用strictfp关键字表示严格浮点运算,
strictfp可修饰类,接口,具体方法,但是不能修饰抽象方法,例如:
abstract class A{
abstract strictfp int a();
}
否则编译错误.
3. 对于要求精确结果的表达而方,不适宜使用double, float, long等类型,应该使用BigDecimal或BigInteger,或者直接使用int类型取替.
五. 语句
表达式语句
由表达式后加;形成表达式语句.
控制语句
顺序
选择
1. 双分支:
if...else...有3种形式:
1.1 if(condition) statement;
1.2 if(condition)
statement;
else
statement;
1.3 if(condition1)
statement1;
else if(condition2)
statement2;
...
else if(conditionN)
statementN;
else
statementN+1;
2. 多分支:
switch(integer-expression){
case integer-constant1:
statement1; break;
...
case integer-constantN:
statementN; break;
default:
statementN+1;
}
注意: 多分支语句
(1)switch子句必须是整型表达式;
(2)case子句必须是整型常量表达式;
(3)case子句如果没有break结束,将继续往下执行;
JDK5.0后:
switch子句可以是enum表达式;
case子句可以是enum实例.
其中,switch子句的enum表达式中enum实例要用类型名引用,但case子句的enum实例却不用类型名引用. 相当奇怪!!!
循环
1. for循环
for(initialization;condition;increment){
statement;
}
2. while循环
while(condition){
statement;
}
3. do-while循环
do{
statement;
}while(condition);
JDK1.5后:
foreach循环: 用于遍历数组与Iterable对象.
for(ElemType elem:arrayOrIterable){
statement;
}
中断
1. return函数返回.
2. throw异常抛出.
3. break, continue迭代结束.
3. break label, continue label带标签迭代结束.
注意:
1.break使流程跳转到整个迭代结束处.
continue使流程跳转到当次迭代结束处.
2.break的label可以标记任意语句块.
continue的label只能标记循环语句块.
3.带标签的break可以实现goto的效果.
4.在try-catch-finally中,不建议在finally中使用任何跳转语句.因为它会覆盖前面return或throw的结果.
注意: 控制语句的条件表达式涉及浮点型时务必谨慎:
(1)浮点型的算术运算必须注意特殊值INFINITIVE, NAN.
(2)浮点型的关系运算必须注意误差, "天生不准确"!
复合语句{}
空语句;
异常处理try-catch-finally
断言语句assert
assert Expression1 ;
assert Expression1 : Expression2 ;
//2010年8月6日
JDK 1.4需用
-enableassertions 或 -ea 选项启用断言
-disableassertions 或 -da 选项禁用断言
六. 类
6.1 类相关的概念:
(1)程序设计原则:
自顶向下
逐步细化
模块化设计
结构化编码
(2)程序设计方法: POP,FOP,OOP,AOP及SOA
POP: Procedure-Oriented Programme, 面向过程编程.
FOP: Function-Oriented Programme, 面向函数编程.
OOP: Object-Oriented Programme, 面向对象编程.
AOP: Aspect-Orinted Programme, 面向切面编程.
SOA: Service-Oriented Programme, 面向服务编程.
POP, FOP, OOP, AOP, SOA串串烧:
程序=算法+数据结构;
SOP先设计问题的算法,再设计与之对应的数据结构.适合小代码量的编程.
OOP先设计系统的数据结构,再设计与之对应的算法.适合大代码量的编程.
POP与OOP的区别: 先有鸡,先有蛋.
AOP辅助松耦合的扩展
SOA辅助松耦合的集成
OOP的四大特性: 抽象(Abstraction),封装(Encapsulation),继承(Inheritance),多态(Polymorphism)
软件的不变真理就是变化.
抽象固化与变化部分.
封装固化与变化部分.
继承固化部分.
改写变化部分.
OOP的缺陷: 面向对象的应用程序很大部分时间耗费在对象的创建与销毁,合理复用对象会有效地提升性能.
(3)类和实例
类是抽象定义
实例是具体实现.
类是"模子"实例是"饼".
(4)引用和对象
实例的要素: 引用与对象, 二者是实例不可分割的部分.
在Java的内存模型中,实例的对象创建在堆中,实例的引用创建在栈中.实例通过引用操作对象.
Java的内存模型直接决定:
(1)参数的传递: Java的参数传递都是"值传递",即将实参的栈值复制给形参.
对于基本类型而言,实参的栈值是真正的值.
对于引用类型而言,实参的栈值是实例的引用.
(2)变量的屏敝规则
生命期或作用域相同的变量不能被屏敝.
类变量或实例变量不能相互被屏敝,因为作用域相同.
类变量或实例变量可以被局部变量屏敝,因为生存期与作用域都不同.
局部变量不能被局部变量屏敝,因为生存期相同.
注意形参也是局部变量.
(3)变量的初始化规则
类变量与实例变量自动初始为类型的默认值.
局部变量不会自动初始化.
(4)线程的通信与同步
子线程为了提高性能,会在本线程保存主线程内存临时拷贝. 除非使用volatile修饰,或使用synchronized同步.
(5)基类,子类,类继承链或类链
(6)类之间的关系
常见的关系:
聚合(has-a)
依赖(use-a)
继承(is-a)
------------------------------
UML明确定义类的关系:
关联(Association):
聚合(Aggregation):
依赖(Dependency):
泛化(Generalization):
-------------------------------------------
其中,
(1)关联,聚合都是"has-a"关系,二者区别微妙:
关联的"has-a"是必不可少的组成部分.
聚合的"has-a"未必不可少的组成部分.
例如: 对于一个人,
胳膊腿脚必不可少,是关联.
衣裤鞋袜不是必不可少,是聚合.
(2)依赖是"use-a"关系,是一种参照关系.
(3)泛化是"is-a"关系,即所谓的继承(Inheritance).
6.2 类原语
(1)类定义
类访问控制: public, package-private
抽象类: abstract
类拓展: extends
接口实现: implements
其它类修改符 : final, strictfp...
(3)接口定义
(4)枚举定义
(5)Annotation定义
6.3 类的成员:
域, 描述类的状态
方法, 描述类的行为
//2010年1月4日 星期一
将非多态成员声明为final特性(private,static,final),让编译器内联优化字节码.
//2010年8月6日: 域初始化
(1)声明时直接初始化
(2)初始化块: {}
(3)构造器
如果是类成员:
(1)声明时直接初始化
(2)静态初始化块: static{}
(3)按需要初始化容器类: Initialize-on-demand holder class(一种设计模式,在Effective Java 166页)
//2010年8月6日: 方法原型(Signature)
方法原型(Signature): 方法名(方法参数类型列表)
//2010年8月6日: 方法参数传递
Java中只有一种参数传递方式: 值传递, 即将实参的栈值复制给形参数.
如果实参是基本类型,哪么复制的内容即实参的值.
如果实参是引用类型,哪么复制的内容即实参的引用.
注意final对象修改后会返回新对象.这也是String等看起来像"值传递"的原因.
Java不能指定参数传递方式.
C/C++可以指定参数传递方式:值传递,*指针传递或&引用传递. 相当灵活, 相当强悍!!!
//2010年8月6日: 方法重载与改写,见下面的Overload与Override
6.4 Override和Overload
1.改写必须相同方法原型(Signature,方法名与方法形参类型列表)
重载要求方法名相同即可.
2.改写只在类继承链的不同环节发生, 重载可以类继承链的不同环节或相同环节发生.
3.改写必须注意三点:
3.1 改写方法的返回类型或参数类型必须与被改写方法的返回类型或参数类型相同或兼容,后者在JDK5.0称为类型协变.
3.2 改写方法的访问控制必须等于或高于被改写方法的访问控制.
3.3 改写方法的被检查异常必须是被改写方法的被检查异常或其子类.
重载必须注意三点:
重载方法的参数类型应该不兼容,否则容易引起歧义.
重载方法的参数列表与可变参数列表必须谨慎.
重载方法在反射机制里是个难处理的角色,正如final特性在反序列化机制中是个难缠的角色.
6.5 构造器和finalize()方法
1.Java对象初始化工作的执行次序:
1)属性的初始化.
2)初始化块.
3)构造器.
4)如果有超类,先执行超类的1)~3).
5)如果属性是对象,先执行属性对象的1)~3).
2.构造器在实例创建时自动调用,一般用来初始化属性.
3.构造器的特点:
1)没有返回值.
2)与类同名.
3)可以重载.
4)如果类中没定义构造器,编译自动创建默认构造器,即无参构造器.如果类中已定义构造器,编译器不再创建默认构造器.
//2010年1月4日 星期一
Java语言级能够在内存创建对象的功能:
1. 构造器
2. Clonable接口的clone()方法.
3. 反序列化接口的readResolve()方法或readReplace()方法.
//2009年12月28日 星期一
构造器用于创建实例并初始化域,类实例化过程为: 先基类,再属性,然后构造器.
子类构造器可以在第一条语句而且必须第一条语句指定超类构造器,默认是超类的无参构造器.
初始化块在类实例化时初始化域,其执行顺序早于构造器.
静态初始化块在类加载时初始化类域.
//2010年1月4日 星期一
finalize()在垃圾收集器回收对象时调用,可以用来清理工作.虽然可用System.gc(), System.runFinalization()通知垃圾收集器,但对象具体回收时机不可保证,因此finalize()不能作为关键资源的清理工作.另外, finalize()不像C++的析构函数, Java类对象的finalize()链不能自动启用,必须在finalize()中使用try-finally确保基类finalize()调用,或者设立finalizer guardar.后者利用回收对象本身一定会先回收其属性的特性.
//2010年1月4日 星期一
由于Java的内存模型特点:
1.在堆中的存储分配会自动初始化为对应类型的默认值.
2.在栈中的存储分配不会自动初始化.
6.6 super和this
super,this是实例的二个隐含引用,都有2个作用.
super引用基类对象,引用基类构造器(只在构造器中).
this引用实例对象,引用构造器(只在构造器中).
6.7 成员修饰符
static,final,abstract,strictfp,volatile,native,transient
6.8 抽象类和接口
1.从定义角度:接口是常量与抽象方法的集合, 接口的属性默认public static final, 接口的方法默认public abstract.
抽象类由可以定义变量与具体方法.
2.从继承角度:接口支持多继承,抽象类只能单继承.
3.从设计角度:接口用于组合,可以在类继承链的任意环节引入.
抽象类用于继承,只能在类继承链的顶层环节引入.
6.9 封装,访问控制
类的访问控制只有public与package-private.
类的成员访问控制有private,package-private,protected,public.
特殊的方法成员:
Factory方法.
Self-use方法.
6.10 多态:
多态定义:实例根据运行时类型选择方法. 多态只体现在实例方法, 或称只有实例方法具有多态性.
多态相关:编译时类型,运行时类型,动态联编,静态联编.
多态不是改写:子类可以改写基类的类域,类方法,实例域,实例方法(或称屏敝). 但多态只体现在实例方法.
多态陷阱: 多态方法的互调. 解决措施: Self-use方法.
继承与组合:
面向对象程序设计中重用代码的手段.
阻止继承: final类和方法, private构造器.
将不需多态行为的方法声明为final, 可以优化字节码.
6.11 嵌套类: 定义在类里面的类, 其全限定名为<外围类全限定名>$<嵌套类名>, 注意$在Linux系统下必须转义!
嵌套类(nested class)指在类内定义的类, 目的是服务外围类.
嵌套类有四种:
静态成员类(static member class),
实例成员类(instance member class),
局部类(local class)
匿名类(anonymous class)
其中后三者又统称内部类(inner class)
静态成员类等价正常类.
内部类可以访问实例闭包,结合接口可以实现多继承效果.
内部类也可以继承,实例化.但有一些特殊语法:
1. 继承内部类,要在子类构造器初始化外围实例.例如:
class A{
class InA{}
}
class B extends A.InA{
public B(A a){
a.super();//必须在第一条语句调用此句.
}
}
2. 创建内部类实例,要用<外围实例>.new运算符,而不是new运算符.
3. 内部类访问外围实例, 使用<外围类>.this引用,而不是this引用.
//2010年8月6日: 编码习惯
使用this.引用实例变量
使用Klass.引用类变量
提高可读性(一看就知道哪些是类变量,哪些是实例变量,哪些是局部变量).
4. 内部类访问外围变量或参数,必须声明为final特性,否则编译错误.
七. Java体系
1. 物理概念及逻辑概念
类路径: 类的根root. 一般使用-classpath选项或CLASSPATH环境变量指定.
类目录: 类的目录. 即文件系统的目录.
类文件: 类的文件
命名空间
包
类
2. 概念串串烧
Java使用包的概念管理命名空间,
包类+类名=类的全限定名
包映射类目录
类映射类文件
一个类文件可以定义多个非public类, 但是只能定义一个public类. 而且, public类必须与类文件同名.
main方法是Java应用程序的唯一入口,但是main方法可以定义在非public类.
3. 包的定义与类的导入
类使用package语句定义包, package语句必须是类的起始语句.
类使用import语句导入包或类, import语句位于package语句后, 所有定义前.
4. 静态导入import static
导入类或接口的可访问static成员, 本地的static成员屏敝静态导入的static成员.
八. JDK 5新语法
8.1 Generic type, 泛型
8.2 Foreach
8.3 Auto Boxing/Un-Boxing
根据上下文情景在基本类型及其包装类型间自动转换.
由于Auto Boxing/Un-Boxing引起的一个歧义:
由于Collection接口有remove(Object), List接口又有remove(int).
对于List对象而言,如果元素恰为Integer类型,哪么结合Auto-Boxing与un-boxing的时候,会调用哪个重载方法?
List<Integer> intList = new ArrayList<Integer>();
intList.add(1);
// intList.add(2);
// intList.add(3);
System.out.println(intList);
intList.remove(1);
System.out.println(intList);
结果是:
java.lang.IndexOutOfBoundsException: Index: 1, Size: 1
可见其准确调用remove(int),此时不会Auto Boxing/Un-boxing.
8.4 Variable parameter list
8.5 enum
枚举是一种特殊的类:
1. 实例定义先于类定义, 实例间用comma隔开, 实例定义与类定义间用semicolon隔开.
2. 构造器只能在类定义内部调用,无所谓private与public.
3. 枚举可用于switch-case-default,但是奇怪switch(Expression)中的实例常量要用枚举类型名引用,但case(Expression)中的实例常量不用枚举类型名引用.
4. 枚举拓展Enum类,具有实例方法: ordinal(), name(), getDeclaringClass(),类方法values(),valueOf().
8.6 import static
8.7 annotation
第二部分: Java类库
具体参照Java平台技术体系.
系统包:13个一级包
java.lang
1.字符串处理:
CharSequence#
String: final实例
StringBuffer: 线程安全的mutable实例
StringBuilder: 线程兼容的mutable实例.
注意: String, StringBuffer, StringBuilder都提供Codepoint的支持,但只有String提供Regular Expression的支持.
2.反射机制:
(1)反射是利用类的运行时类型标识(Runtime Type Identity,RTTI)进行分析与编程的技术:
(2)反射API:
传统API:
Interfaces:
Member
InvocationHandler
Classes:
Package
Class
AccessibleObject
Constructor
Method
Field
Array
Modifier
Proxy
ReflectPermission
针对GenericType:
GenericDeclaration: 范型定义,例如<K,E>, 只有Class, Counstructor, Method才实现(范型类,范型接口,范型方法)
Type
TypeVaraible: 类型变量, 例如 T.
ParameterizedType: 参数化类型, 例如 A<T>
GenericArrayType: 范型数组类型,例如 T[]或A<T>[]
WildchardType: 通配符类型, 例如 ?, ? extends T, ? super T.
另外在Class, Contructor, Method, Field中添加范型反射的方法.
具体参照<Java泛型.not>中的总结.
针对Annotation:
AnnotationElement
另外在Package, Class, Constructor, Method, Field中添加注解反射的方法.
3.代理:
(1)代理针对接口编程
(2)静态代理中,代理对象与被代理对象实现相同接口,然后将被代理对象的请求转发给代理对象处理, 即Decorator模式.
(3)动态代理的步骤:
(3.1)定义代理接口
(3.2)实现代理对象
(3.3)定义代理句柄(Invocation)
(3.4)创建(或绑定)被代理对象
使用Proxy.newInstance(ClassLoader, Class[], InvocationHandler)生成被代理对象.
参数一表示代理类加载器, null表示默认类加载器.
参数二表示代理接口
参数三表示代理句柄, 即(3.3)
等价于:
Class proxyClass=Proxy.getProxyClass(ClassLoader, Class[]).
proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(invocationHandler);
习惯上,将(3.3),(3.4)由一个接口实现类完成.
代理陷阱: 调用循环
InvocationHandler{
Object invoke(Object proxy, Method method, Object[] args){
method.invoke(proxy,args);//造成死循环,无限地调用代理句柄.
}
}
java.math
java.util
1. 日期处理:
Date: final实例
Calendar: Date的辅助类
GregorianCalendar
DateFormat: Date的格式类
SimpleDateFormat
java.io
java.nio
1. nio使用的结构更接近于OS执行I/O的方式: Channel与Buffer.
2. Channel的类层次:
Closeable~
Channel#
ReadableByteChannel#
WriteableByteChannel#
ByteChannel: ReadablByteChannel与WriteableByteChannel的合并接口.
ScatteringByteChannel#
GatheringByteChannel#
InterruptibleChannel#
AbstractInterruptibleChannel
FileChannel: 实现ByteChannel, ScatteringByteChannel, GatheringByteChannel
SelectableChannel: 可通过 Selector 实现多路复用的通道。
ServerSocketChannel
SockeChannel: 实现ByteChannel, ScatteringByteChannel, GatheringByteChannel
DatagramChannel: 实现ByteChannel, ScatteringByteChannel, GatheringByteChannel
3. Buffer的类层次:
Buffer#
CharBuffer
ByteBuffer
MappedByteBuffer
ShortBuffer
IntBuffer
LongBuffer
FloatBuffer
DoubleBufferr
4. Charset的类层次
Charset
CharsetDecoder
CharsetEncoder
CoderResult
CodingErrorAction
5. 应用:
(1)Channel分为FileChannel与SelectableChannel.
FileChannel只能通过FileInputStream, FileOutputStream, RandomAccessFile获取.
SelectableChannel可通过Selector实现多路利用, 主要包含ServerSocketChannel, SocketChannel, DatagramChannel.
(2)Channel交互对象是字节流. 如果交互对象是字符流, 需用Charset, CharsetEncoder, CharsetDecoder辅助.
(3)视图缓冲器, 映射字节缓冲器
借助ByteBuffer.asXXXBuffer()可以创建其它类型缓冲器的视图.
MappedByteBuffer
java.applet
java.awt
java.beans
java.net
java.rmi
java.security
java.sql
java.text
扩展包:21个一级包
javax.accessibility
javax.activation
javax.activity
javax.annotation
javax.crypto
javax.imageio
javax.jws
javax.lang.model
javax.management
javax.naming
javax.net
javax.print
javax.rmi
javax.script
javax.security.auth
javax.sound.midi
javax.sql
javax.swing
1. Applet是嵌入网页运行的图形化程序.
Applet的生命周期:
init()-->start()-->stop()-->destroy(), 在start()与stop()之间多次调用pait(), repaint(), update()重画界面.
2. Java图形化程序设计要点:
(1)图形化应用程序必须运行于EventQueue. 由EventQueue的DispatcherThread同步所有AWTEvent.
(2)图形化应用程序必须调用System.exit(0)结束. 图形化应用程序后台往往多线程, 光是结束main线程是不够的.
3. 参照<JFC Swing.not>
javax.tools
javax.transaction
javax.xml
第三方:14个一级包
org.ietf.jgss
org.omg.CORBA
org.omg.CORBA_2_3
org.omg.CosNaming
org.omg.Dynamic
org.omg.DynamicAny
org.omg.IOP
org.omg.Messaging
org.omg.PortableInterceptor
org.omg.PortableServer
org.omg.SendingContext
org.omg.stub.java.rmi
org.w3c.dom
org.xml.sax
--------------------------------------------------
实质上根本不够能力去概括.
--------------------------------------------------
一. Lang and util
//2010年1月1日 星期五
字符串处理: String, StringBuffer, StringBuilder
1. String, 字串final对象, 很多应用程序的安全性基于String的final特性.
2. StringBuffer, String的可变辅助类, 线程安全.
3. StringBuilder, StringBuffer的非同步版本.
字符串关键API:
length()/codePointCount(start, end)
equals()
equalsIgnoreCase()
charAt(position)/codePointAt(position)
//2010年1月4日 星期一
Date, Calendar, GregorianCalendar,
Date是final对象.
Calendar是Date可变辅助类.
GregorianCalendar是Calendar的具体子类.
这几个类可以完成涉及时间的大部分功能.
DateFormat, SimpleDateFormat是Date的格式类.
//2010年1月4日 星期一
Java中所有类都是Object的子类, Object本身具有若干关键方法,直接影响Java中其它类设计:
1.对象回收:
protected void finalize();
对象克隆:
protected Object clone() throws CloneNotSupportedException;
2.对象比较:
public boolean equals(Object obj);
public int hashCode();
3.对象格式:
public String toString();
4.线程同步:
public void wait();
public void wait(long);
public void notify();
public void notifyAll();
5.反射机制:
public Class<?> getClass();
//2010年1月4日 星期一
<Effective Java>关于equals(), hashCode()的算法:
equals必须满足:
自反性: x.equals(x)
对称性: x.equals(y) --> y.equals(x)
传递性: x.equals(u) && y.equals(x) --> x.equals(z)
一致性: x,y未变--> x.equals(y)
非空引用: x.equals(null) --> false
public boolean equals(Object obj){
if(obj==null){
return false;
}
if(this==obj){
return true;
}
if(!(obj instanceof TYPE)){ //或者:obj.getClass()!= this.getClass()
return false;
}
Type that=(Type)obj;
return (that.Y==Y)||(Y!=null && Y.equals(that.Y))...
//关键属性的比较,注意对象为空的情况.
}
hashCode()必须满足:
相等对象的hashCode相等,不等对象的hashCode不等.
对于关键属性x:
int result=17;//初始为素数.
result=37*result+hashCode(x);
如果x是byte, short, char,强制转为int.
如果x是long, (int)(x^(x>>>32));
如果x是float, Float.floatToIntBits(x);
如果x是double, f=Double.doubleToLongBits(x);
f^(f>>>32);
如果x是boolean, x?0:1;
如果x是对象: x==null?-1:x.hashCode();
//2010年1月5日 星期二
一些关键的接口:
1. Cloneable标记接口,Object要使用clone方法,必须实例此接口,否则抛CloneNotSupportedException.
2. Comparable接口,在Collection frame的集合元素都应该实现此接口,如果没有,需要在相应方法传递Comparator.
3. Iterable,使用要使用Foreach语法的对象,此接口返回Iterator对象.
4. Serializable,序列化机制必须的接口,其子类Externalizable提供可定制方法readExternal()与writeExternal().
//2010年1月5日 星期二
关于对象克隆: 除了使用Cloneable接口外,还可以使用Java序列化机制,先将对象序列化,然后再反序列化得到与原来对象一样的内存存储对象.但这种方式性能较低.
二. Collections
关于Java的Collections frame框架:
Collections frame的类图:
Collection:
Set
HashSet
LinkedHashSet
TreeSet
List
ArrayList
LinkedList: Queue与Stack基本都用LinkedList实现.
Vector
Queue
Map:
HashMap
LinkedHashMap
TreeMap
辅助类或接口:
Collections
Arrays
关联类或接口:
Iterator与Iterable
Comparator与Comparable
关联方法:
equals()判定是否相等调用.
hashCode()在哈希操作中用作Key.
注意:
1. Map接口不继承Collection接口.
2. Vector是ArrayList的线程同步版本.
Hashtable是HashMap的线程同步版本.
3. Collections或Arrays包含大量集合操作的实用方法.
//2010年1月3日 星期日
Effective中关于equals,hashCode的算法,参考Effective Java
三. io/nio
1. Console类,表示从控制台输入,但不回显.
2. JDK5.0提供Scanner扫描输入.
3. JDK5.0提供Formater格式输出.
Formatter与Formatable结合使用.
格式说明符语法:
%[格式][宽度.精度][t]转换符
格式符6类9种:
符号: +(
填充: 空格0
左对齐: -
千位符: ,
进制符: #
参数索引: < $
转换符:
10进制: d
16进制: x
8进制: o
小数形式: f
10进制指针形式: e
16进制指针形式: a
通用浮点数形式: g
字串: s
字符: c
布尔: b
散列码: h
日期时间: tx
百分号: %
换行符: n
日期时间:
具体查看Formatter的API帮助.
4. Java2简明教程:
4.1 流的层次结构:
java.io包的关键类: InputStream, OutputStream, File, RandomAccessFile, FileDescriptor
java.io包的异常类: IOException, FileNotFoundException, EOFException, InterruptedException.
InputStream:
1. StringBufferInputStream
2. ByteArrayInputStream
3. FileInputStream
4. FilterInputStream
4.1 BufferedInputStream
4.2 PushbackInputStream
4.3 LineNumberInputStream
4.4 DataInputStream
ObjectInputStream
5. PipedInputStream
6. SequenceInputStream
OutputStream:
1. ByteArrayOutputStream
2. FileOutputStream
3. FilterOutputStream
3.1 BufferedOutputStream
3.2 PrintStream
3.3 DataOutputStream
ObjectOutputStream
4. PipedOutputStream
4.2 File类:
File类封装文件抽象路径, 文件抽象路径(File Abstract Path)既可以文件的绝对路径,也可以文件相对路径(相对"user.dir"系统属性). 可以创建,删除,修改或查询文件属性,但不能读写文件内容.
文件相关操作步骤:
1. 先用File抽象文件.
2. 再作文件属性相关的操作, 例如查询文件是否存在,文件的创建时间之类.
3. 最后传递File创建IO流, 对文件内容进行读写.
4.3 RandomAccessFile类:
RandomAccessFile类同时实现InputStream与OutputStream接口,可以随机读写文件内容.
4.4 对象序列化机制:
序列化机制先检测对象是否Externalizable,
如果是,调用其writeExternal()与readExternal()进行序列化与反序列化.
如果不是, 再检测对象是否Serializable,
如果是, 调用其writeObject()与readObject()进行序列化与反序列化.
如果不是, 抛出NotSerializableException.
序列化过程中,Serializable接口的writeReplace(), readReplace()方法可以替换序列化与反序列化的结果.以下控制序列化过程的4个sercurity方法:
protected Object writeReplace() throws ObjectStreamException;
private void writeObject(ObjectOutputStream out) throws IOException;
private void readResolve(ObjectInputStream in) throws IOException, ClassNotFoundException;
protected Object readReplace() throws ObjectStreamException;
四. Net
五. thread and concurrent
六. JDBC
七. I18N
八. XML/JAXP
8.1 DOM
8.2 SAX
8.3 StAX
九. RegExp
十. Format
1. String.format/System.out.format(printf)
2. Formatter: 用于流的格式输出, Formater(File/String)是替换, Formater(Appendable/OutputStream)是追加, 很奇怪的形式.
3. Scanner:用于流的扫描输入,
十. Reflect/Tools
关于反射(Reflect)的总结:
<1> 反射是利用类的运行时类型标识(Runtime Type Identity, RTTI)进行分析与编程的技术.
<2> RTTI的关键API:
Class
Constructor
Method
Field
Array
其中,得到Class的方式有3种:
Object.getClass()
Class.forName()
T.class类型常量, T可以是primitive, 也可以是reference, 包括数组类型.
JVM只为每种类型维护一个Class对象,即Class是Singleton的.可以直接使用==,!=进行比较.但是对于数组类型而言, ==是不兼容的, getName()也返回奇怪的名字, 需要用getCannonicalName()返回规范名字才可读.
另外,由于array class loader是Java Runtime自动创建的, 其Class.getClassLoader()返回的是其元素的ClassLoader, 无法使用Class.newInstance()来创建实例, 需用Array.newInstance(). Class.newInstance使用类的默认构造器创建实例,如果带参构造器,需要使用先创建Constructor,然后由Construnctor.newInstance()来创建实例.
十一. Observe/Proxy
//2010年1月5日 星期二
1.Java代理面向接口编程,而不是面向具体类编程.
2.Java代理实现步骤:
2.1 定义代理接口和编写代理实现类.
2.2 实现InvocationHandler接口,改写invoke()方法添加代理逻辑.
2.3 创建被代理实例,创建方法有2种:
Proxy.newProxyInstance(ClassLoader proxyClassLoader,Class[] proxyInterfaceArray, InvocationHandler handler)
或者,
Class proxyClass=Proxy.getProxyClass(ClassLoader proxyClassLoader, Class[] proxyInterfaceArray);
ProxyType inst=proxyClass.getCounstructor(Class[]{InvocationHandler.class}).newInstance(new Object[]{invocationHandler});
后者需要抛出一串被检查异常.
注意,不可在InvocationHandler.invoke(Object proxy, Method method, Object[] args)调用method.invoke(proxy,args),这样将导致死循环,代理实例调用拦截,再调用代理实现...
3.Java代理不般用于隐藏后台处理细节.经典实现:
/*
* 代理接口
*/
public interface ProxyInf {
void execute();
}
/*
* 代理实现
*/
public class ProxyImpl implements ProxyInf {
@Override
public void execute() {
System.out.println("ProxyImpl.execute()...");
}
}
/*
* InvocationHandler实现
*/
public class ProxyInvocationHandler implements InvocationHandler{
protected final ProxyInf proxyInst;
public ProxyInvocationHandler(ProxyInf proxyInst){
this.proxyInst=proxyInst;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println(proxy.getClass().getName());
System.out.println(method.toString());
System.out.println(Arrays.toString(args));
return method.invoke(proxyInst, args);
}
}
/*
* 使用工厂方法创建代理实例
*/
public class ProxyFactory {
protected static ProxyInvocationHandler handler=new ProxyInvocationHandler(new ProxyImpl());
protected ProxyFactory(){}
public static ProxyInf newInstance() throws IllegalArgumentException, SecurityException, InstantiationException, IllegalAccessException, InvocationTargetException, NoSuchMethodException {
// return (ProxyInf)Proxy.newProxyInstance(ProxyInf.class.getClassLoader(), new Class[]{ProxyInf.class}, handler);
Class<?> proxyClass=Proxy.getProxyClass(ProxyInf.class.getClassLoader(), new Class[]{ProxyInf.class});
ProxyInf proxyInst=(ProxyInf) proxyClass.getConstructor(new Class[]{InvocationHandler.class}).newInstance(new Object[]{handler});
return proxyInst;
}
}
十二. AWT/Swing/Applet/JavaBean
//2010年1月1日 星期五
Applet的理论总结:
1. Applet的执行环境: Applet嵌入浏览器的网页中执行.
2. Applet的生命周期:
init, 初始化资源, 在网页加载或网页打开时调用.
start, 启动处理, 在网页获取焦点时调用.
stop, 停止处理, 在网页失去焦点时调用.
destroy, 销毁资源, 在网页关闭时调用.
另外,还有paint(),repaint(),update()方法供在各个生命周期切换中调用.
3. Applet的开发流程.
3.1 拓展Applet或JApplet,并改写相应生命周期的回调方法.
3.2 借助<applet>标签嵌入html代码,并设置codebase,code,width,height属性.
//2010年1月1日 星期五
每个Swing程序, 有两点技术需要强调:
<1> 所有AWT/Swing组件必须由事件高度线程(Event Dispatch Thread)进行配置, 线程会将鼠标和键盘控制转移到用户接口组件.
否则会存在安全隐患,即使概率很少.
<2> 多个框架的程序中, 退出main方法, 只是终止主线程, 没有终止程序. 事件调度线程保持程序处于激活状态, 直到关闭所有框架或调用System.exit方法终止程序.
应该在退出程序时调用System.exit确保程序终止.
AWT/Swing的注意事项:
1. AWT/Swing应该在System EventQueue中执行.EventQueue的DispatchThread会同步处理AWTEvent.
System EventQueue可以通过Tookit.getSystemEventQueue()获取.
EventQueue.invokeXXX(Runnable)或
2. AWT/Swing结束时应该调用System.exit.由于AWTEvent在System EventQueue的DispatchThread中处理, 仅仅结束main线程是不够的.
JFrame.setDefaultOperation(JFrame.EXIT_ON_CLOSE)会在JFrame关闭时调用System.exit.
//2010年1月6日 星期三
AWT,Swing,SWT开发模式采用事件委托模型,
用户通过鼠标,键盘操作组件-->组件产生事件-->事件传达监听器-->监听器实现具体处理逻辑-->根据结果更新组件.
不同组件,不同事件,不同监听器.而组件,事件,监听器构成学习GUI的三个基本元素.
组件,布局管理器,事件体系参见<JFC Swing.not>的总结.
学习AWT/Swing主要学习:
<1> 组件: 基本属性及设置
高级模型及配置
<2> 布局管理器: 效果及配置
<3> 事件: 类型及监听器.
另外,Accelerator Key,
Key Stroke,
Image,
Graphics,
Color,
Rich Text,
Print
等功能,也是GUI必不可少.
//2010年1月6日 星期三
AWT/Swing类层次结构:
Object
Button
Canvas
CheckBox
Choice
Container
BasicSplitPanelDivider
CellRendererPane
DefaultTreeCellEditor.EditorContainer
JComponent //所有Swing组件的蕨类, 包括JPanel与JScrollPane
Panel
ScrollPane
Window
BasicToolBarUI.DragWindow
Dialog
JDialog
Frame
JFrame
JWindow
Label
List
Scrollbar
Text Component
TextArea
TextField
可见,AWT是Swing的基础,另外,Swing继续沿用AWTEvent以及LayoutManager,尽管也用LayoutManager2.
//2010年1月6日 星期三
1. JFrame
Swing对于heavyweight component的设计模型:
Window Applet
Frame Dialog
JFrame JDialog JWindow JApplet JInternalFrame
上面JFrame, JDialog, JWindow, JApplet, JInternalFrame都实现RootPaneContainer接口,其中前面者是heavyweight component,后者是lightweight component.
RootPaneContainer接口返回一个JRootPane,每个JRootPane包含一个JContentPane, 一个JGlassPane, 一个MenuBar, 一个JLayeredPane.
JGlassPane位于顶层, 一般用于捕捉鼠标事件, 也可用于描绘顶层组件.
JLayeredPane包含6个常用的层:
DEFAULT_LAYER: 默认层, 位于Integer(0).
PALATTE_LAYER: 调色板层, 位于Integer(100).
MODEL_LAYER: 模型层, 位于Integer(200).
POPUP_LAYER: 弹出层, 位于Integer(300).
DRAG_LAYER: 拖拉层, 位于Integer(400).
FRAME_CONTENT_LAYER: 内容层, 位于Integer(-30000).
MenuBar位于内容层.
十三. RMI
十四. Security/JAAS
//2010年1月2日 星期六
1. ClassLoader, 参考API
简结:
ClassLoader负责加载类字节码,并创建Class对象.
Class对象包含定义其的ClassLoader引用.
数组类型的Class对象的ClassLoader其元素的ClassLoader对象,由Java Runtime自动创建.
基本类型的Class对象的ClassLoader为null.
//2010年1月3日 星期日
When the JVM is started, three class loader is used:
1. Bookstrap class loader
2. Extensions class loader
3. System class loader
The bookstrap class loader loads the core java libraries, which locate at <JAVA_HOME>/lib directory.
The bookstrap class loader is part of the core JVM, which is written in native language, such as C/C++.
The bookstrap class loader has not ClassLoader object.
For example, String.class.getClassLoader() is null.
The extensions class loader loads the extensions libraries, which locate at <JAVA_HOME>/lib/ext or any other directory specified by "java.ext.dirs" system property.
The extensions class loader is implemented by "sun.misc.Launcher$ExtClassLoader" class.
The extensions class loader will not reference any other class path,即扩展类加载器不使用类路径.
The system class loader loads the application libraries, which locate at directory specified by "CLASSPATH" system variable or "java.class.path" system property.
The system class loader is implemented by "sun.misc.Lanucher$AppClassLoader" class.
//2010年1月2日 星期六
ClassLoader的加载机制:
1. Class与ClassLoader加载资源时的区别:
public java.net.URL getResource(String name) {
name = resolveName(name);
ClassLoader cl = getClassLoader0();
if (cl==null) {
// A system class.
return ClassLoader.getSystemResource(name);
}
return cl.getResource(name);
}
由源码可见,Class.getResource delegate to ClassLoader.getResource, if ClassLoader is a bookstrap class loader, it will delegate to ClassLoader.getSystemResource().
但与ClassLoader.getResource()不同,Class.getResource()先调用resolveName()对resource name进行解析. 所以, Class.getResource()可以指定/打头的绝对路径,也可以指定相对路径,但是ClassLoader.getResource()只能指定相对CLASSPATH的路径,即不能指定以/打头的绝对路径,否则返回null.
public URL getResource(String name) {
URL url;
if (parent != null) {
url = parent.getResource(name);
} else {
url = getBootstrapResource(name);
}
if (url == null) {
url = findResource(name);
}
return url;
}
由源码可见,ClassLoader会调用parent class loader的getResource()来查找资源,如果parent是bookstrap class loader,则别外处理.在parent class loader返回null的情况下,再次调用findResource()来处理.注意,这里的findResource()指的是沿着class loader chain从下往上依次调用getResource()来查找,而不是目录结构的树形查找.
十五. Native
十六. Annotation
--------------------------------------------------
随笔
--------------------------------------------------
1. 类->Java变量的域初始化
Java的类变量,实例变量会自动初始化类型的默认值, 局部变量不会自动初始化, 引用前必须显式初始化.
这个规则的唯一例外就是final域必须显式初始化, 不论是类变量, 还是实例变量.
显式初始化类变量:
(1)声明同时初始化
(2)static初始化块
显式初始化实例变量:
(1)声明同时初始化
(2)初始化块
(3)构造器
2. 类->this,super
this引用当前实例或重载构造器,如果引用重载构造器,必须位于某个构造器中.
super引用基类实例或基类构造器,如果引用基类构造器,必须位于子类构造器的首语句.
3. lang and util->Random
Random(long seed)相同随机因子产生的随机序列相同.如果不指定随机因子或使用System.nanoTime()作为随机因子.
Random的nextInt(int)方法比较随机.其使用的算法不同.
4. Java体系->垃圾回收与finalize()方法
JVM根据某种垃圾回收算法回收无用对象,释放占用内存.回收前调用对象的finalize()方法.
由于回收时机不确定,finalize()显得不可靠,不能用于关键资源的回收.
垃圾回收相关方法:
System.gc()启动垃圾回收.
System.runFinalization()执行回收对象的finalize()方法.
gc与runFinalization()的区别: 某个对象零引用后会自动标记为回收对象, 但可能还在堆中. 因为尚未启动垃圾回收. 这种现象与垃圾回收算法相关.
5. lang and util->Runtime
6. Java体系->
(1)物理概念: 类路径,类目录,类文件.
(2)逻辑概念: 命名空间,包,类
(3)定义包: package语句
(4)导入包或类: import语句
(5)静态导入: import static语句
(6)设置类路径: -classpath选项或CLASSPATH环境变量
7. 类->
(1)类和实例
类是抽象定义,实例是具体实现
(2)基类,子类,继承链
(3)类的关系:
is-a: 泛化(Generalization,或继承)
has-a: 关联(Association),聚合(Aggregation)
关联是必不可少, 聚合是可有可无. 或者, 关联是一对一, 聚合是一对多(零或多)
use-a: 依赖(Dependency)
(4)动态绑定: 编译时类型和运行时类型
(5)重载(Overload)和改写(Override)
(1)从定义角度: 重载指方法名相同,形参列表不同. 改写指方法签名必须相同.
(2)从发生角度: 重载发生在继承链的上下,或相同结点. 改写发生在继承链的上下环节.
(3)从设计角度: 重载实现编译时的多态, 即根据形参绑定不同方法. 改写实现运行时的多态, 即根据运行时类型绑定不同方法.
注意事项:
(1)重载方法的形参列表必须个数不同,或者类型不兼容. 否则容易产生歧义.
(2)访问控制: 改写方法的访问控制必须等于或高于被改写方法的访问控制.
参数类型: 改写方法的返回类型与形参类型必须等于或兼容被改写方法的返回类型与参数类型,兼容的情况又称为类型协变.
被检查异常: 改写方法的被检查异常必须等于或兼容被改写方法的被检查异常,兼容的情况也可视作类型协变.
(6)多态,改写: 多态与改写是完全不同的概念, 子类可以改写基类的任何可访问成员, 即替换. 但多态只体现在成实例方法, 即实例方法根据运行时类型绑定, 其它成员根据编译时类型绑定.
(7)final:
final类不可被继承
final方法不可被改写
final域不可再赋值
注意事项:
(1)final域必须显式初始化.
(2)final类或final方法可以优化字节码,使用内联调用.
(3)final实例,final引用,final对象的区别:
final实例指引用与对象都不可变.
final引用指引用不可变.
final对象指对象不可变.
(4)final对象实现:
(1)所有可访问域都是final实例, 理想状态.
(2)不提供域的Mutator方法.
(3)对可变域的Accessor方法提供保护性拷贝.
8. 数据类型->类型转换
(1)类型转换指一种类型转换为别一种类型.
(2)类型转换只发生在兼容的数值类型或继承链的类类型之间.
数据类型的低类型向高类型转换不会损失精度,是安全的.
数据类型的高类型向低类型转换会损失精度,是不安全的.
数值类型的合法转换:
char->int
byte->short->int->long
int->double<-float
类类型的子类向基类转换叫向上类型转换.
类类型的基类向子类转换叫向下类型转换.
向上类型转换是安全的,向下类型类型是危险的,必须先instanceof类型检测.
9. 类->抽象类,接口
(1)从定义角度: 接口是常量与抽象方法的集合, 所有域默认public static final, 所有方法默认public abstract.
抽象类可以定义变量与具体方法.
(2)从继承角度: 接口支持多继承, 抽象类只支持单继承.
(3)从设计角度: 接口用于实现组合, 可以在继承链的任意环节引入, 但要维护实现接口的所有类.
抽象类用于实现继承, 只能在继承链的顶层环节引入, 但只需要维护基类即可.
10. 类->访问控制
(1)类的访问控制: public, package-private
(2)成员访问控制: public, protected, package-private, private
11. 类->Object: 所有类的基类.
12. 类->equals(),hashCode()改写
equals()必须满足: 自反,对称,传递,一致.
hashCode()必须满足: x.equals(y), x.hashCode()==y.hashCode().
实现算法见<effective javae>