??xml version="1.0" encoding="utf-8" standalone="yes"?> 一般来_不要在expression1、expression2中用函数的q回| 使用Ӟ~译旉要用javac -sourceQ执行时需要用java -ea?br />
附上一写得很不错的原文: 深入解析Java的assertion J2SE 1.4在语a上提供了一个新Ҏ(gu),是assertion(断言)功能Q它是该版本在Java语言斚w最大的革新。在软g开发中Qassertion是一U经典的调试、测试方式,本文深入解析assertion功能的用以及其设计理念Qƈl出相关的例??/p>
assertion(断言)在Y件开发中是一U常用的调试方式Q很多开发语a中都支持q种机制Q如CQC++和Eiffel{,但是支持的Ş式不相同,有的是通过语言本n、有的是通过库函数等。另外,从理Z来说Q通过assertion方式可以证明E序的正性,但是q是一相当复杂的工作Q目前还没有太多的实跉|义?/p>
在实CQassertion是在程序中的一条语句,它对一个boolean表达式进行检查,一个正程序必M证这个boolean表达式的gؓtrueQ如果该gؓfalseQ说明程序已l处于不正确的状态下Q系l将l出警告或退出。一般来_assertion用于保证E序最基本、关键的正确性。assertion查通常在开发和试时开启。ؓ了提高性能Q在软g发布后,assertion查通常是关闭的。下面简单介l一下Java中assertion的实现?/p>
1Q?) 语法表示 在语法上Qؓ了支持assertionQJava增加了一个关键字assert。它包括两种表达式,分别如下Q?/p>
在两U表辑ּ中,expression1表示一个boolean表达式,expression2表示一个基本类型或者是一个对?Object) Q基本类型包括boolean,char,double,float,int和long。由于所有类都ؓObject的子c,因此q个参数可以用于所有对象?/p>
1Q?) 语义含义 在运行时Q如果关闭了assertion功能Q这些语句将不vM作用。如果打开了assertion功能Q那么expression1的值将被计,如果它的gؓfalseQ该语句强抛Z个AssertionError对象。如果assertion语句包括expression2参数Q程序将计算出expression2的结果,然后这个结果作为AssertionError的构造函数的参数Q来创徏AssertionError对象Qƈ抛出该对象;如果expression1gؓtrueQexpression2不被计?/p>
一U特D情冉|Q如果在计算表达式时Q表辑ּ本n抛出ExceptionQ那么assert停止运行,而抛个Exception?/p>
1Q?) 一些assertion例子 下面是一些Assert的例子?/p>
1Q?) ~译 ׃assert是一个新关键字,使用老版本的JDK是无法编译带有assert的源E序。因此,我们必须使用JDK1.4(或者更?的Java~译器,在用Javac命oӞ我们必须加上-source 1.4作ؓ参数?source 1.4表示使用JDK 1.4版本的方式来~译源代码,否则~译׃能通过Q因为缺省的Javac~译器用JDK1.3的语法规则?/p>
一个简单的例子如下Q?/p>
1Q?) q行 ׃带有assert语句的程序运行时Q用了新的ClassLoader和Classc,因此Q这U程序必dJDK1.4(或者更高版?的JRE下运行,而不能在老版本的JRE下运行?/p>
׃我们可以选择开启assertion功能Q或者不开启,另外我们q可以开启一部分cL包的assertion功能Q所以运行选项变得有些复杂。通过q些选项Q我们可以过滤所有我们不兛_的类Q只选择我们兛_的类或包来观察。下面介l两cd敎ͼ 首先Q我们认为assertion是必要的。因为,如果没有l一的assertion机制QJavaE序通常使用if-then-else或者switch-case语句q行assertion查,而且查的数据cd也不完全相同。assertion机制让JavaE序员用l一的方式处理assertion问题Q而不是按自己的方式处理。另外,如果用户使用自己的方式进行检查,那么q些代码在发布以后仍然将起作用,q可能会影响E序的性能。而从语言a层次支持assertion功能Q这把assertionҎ(gu)能带来的负面媄响降到最?/p>
Java是通过增强一个关键字assert实现支持assertionQ而不是用一个库函数支持Q这说明Java认ؓassertion对于语言本n来说是非帔R要的。实际上Q在Java的早期的规范中,Java是能够支持assert的,但是׃一些实现的限制Q这些特性从规范中除M。因此,assert的再ơ引入应该是恢复了Java对assert的支持。C语言是通过Assert.h函数库实现断a的支持?/p>
Java的assertion的开启也和C语言不太一P我们都知道在C语言中,assertion的开启是在编译时候决定的。当我们使用debug方式~译E序时候,assertion被开启,而用release方式~译时候,assertion自动被关闭。而Java的assertion却是在运行的时候进行决定的。其实,q两U方式是各有优缺炏V如果采用编译时军_方式Q开发h员将处理两种cd的目标码Qdebug版本和release版本Q这加大了文管理的隑ֺQ但是提高了代码的运行效率。Java采用q行时决定的方式Q这h有的assertion信息置于目标代码中Q同一目标代码可以选择不同方式q行Q增强目标代码的灉|性,但是它将牺牲因ؓassertion而引起一部分性能损失。Java专家组认ؓQ所牺牲的性能相当,因此java采用了运行时军_方式?/p>
另外Q我们注意到AssertionError作ؓError的一个子c,而不是RuntimeException。关于这一点,专家l也q行了长期的讨论。Error代表一些异常的错误Q通常是不可以恢复的,而RuntimeException该错误在q行时才发生的特炏VAssertionError通常为非常关键的错误Q这些错误往往是不Ҏ(gu)恢复的,而且assertion机制也不鼓励E序员对q种错误q行恢复。因此,Zassertion的含义,Java专家组选择了让AssertError为Error的子cR?/p>
在本节,我们考虑assertion与承的关系Q研Iassert是如何定位的。如果开启一个子cȝassertionQ那么它的父cȝassertion是否执行Q?/p>
下面的例子将昄如果一个assert语句在父c,而当它的子类调用它时Q该assert为false。我们看看在不同的情况下Q该assertion是否被处理?/p>
assert expression1:expression2;
如果expression1为trueQ则不抛出错误,E序正常q行Qexpression2也不会执行?br />
如果expression1为falseQ则抛出异常Q程序中断蟩出,expression2执行?/p>
不要其使用在public函数中检查输入参敎ͼ但可以用于private函数中检输入参数?br />
个h的一点理解:使用assert只是Z帮助我们调试E序Q因此用assert所遵@的原则就?#8220;不能因ؓ有了assert的存在而ɽE序的结构发生Q何的改变”Q说白了是“如果把assert部分删除了,E序依然不会有Q何的问题Q只不过不能帮助我们查出一些错误来?#8221;Q因此用assert的时候不应该在表辑ּ中用函敎ͼ因ؓ一旦把q句assert语句删除后,E序的结构就改变了,q不W合上述提到的原则!
javac -source 1.4 test.java
参数
例子
说明
-ea
java -ea
打开所有用L(fng)的assertion
-da
java -da
关闭所有用L(fng)的assertion
-ea:<classname>
java -ea:MyClass1
打开MyClass1的assertion
-da:<classname>
java -da: MyClass1
关闭MyClass1的assertion
-ea:<packagename>
java -ea:pkg1
打开pkg1包的assertion
-da:<packagename>
java -da:pkg1
关闭pkg1包的assertion
-ea:...
java -ea:...
打开~省?无名?的assertion
-da:...
java -da:...
关闭~省?无名?的assertion
-ea:<packagename>...
java -ea:pkg1...
打开pkg1包和其子包的assertion
-da:<packagename>...
java -da:pkg1...
关闭pkg1包和其子包的assertion
-esa
java -esa
打开pȝcȝassertion
-dsa
java -dsa
关闭pȝcȝassertion
l合使用
java -dsa:MyClass1:pkg1
关闭MyClass1和pkg1包的assertion
其中...代表Q此包和其子包的含义。例如我们有两个包ؓpkg1和pkg1.subpkg。那么pkg1...׃表pkg1和pkg1.subpkg两个包?br />
另外QJavaZ让程序也能够动态开启和关闭某些cd包的assertion功能QJava修该了Class和ClassLoader的实玎ͼ增加了几个用于操作assert的API。下面简单说明一下几个API的作用?br />
ClassLoadercM的几个相关的API:
setDefaultAssertionStatus:用于开?关闭assertion功能
setPackageAssertionStatus:用于开?关闭某些包的assertion功能
setClassAssertionStatus: 用于开?关闭某些cȝassertion功能
clearAssertionStatusQ用于关闭assertion功能
class Base
{
public void baseMethod()
{
assert false : "Assertion failed:This is base ";// Lassertionp|
System.out.println("Base Method");
}
}
class Derived
extends Base
{
public void derivedMethod()
{
assert false: "Assertion failed:This is derive";// Lassertionp|
System.out.println( "Derived Method" );
}
public static void main( String[] args )
{
try
{
Derived derived = new Derived();
derived.baseMethod( );
derived.derivedMethod();
}
catch( AssertionError ae )
{
System.out.println(ae);
}
}
}
q行命o
含义
l果
Java Derived
不启用assertion
Base Method
Derived Method
Java -ea Derived
开启所有assertion
Java.lang.AssertionError:Assertion Failed:This is base
Java -da Derived
关闭所有assertion
Base Method
Derived Method
Java -ea:Base Derived
仅打开Base的assertion
Java.lang.AssertionError:Assertion Failed:This is base
Java -ea:Derived Derived
仅打开Derived的assertion
Base Method
Java.lang.AssertionError:Assertion Failed:This is derived
从这个例子我们可以看出,父类的assert语句只有在父类的assert开启才起作用,如果仅仅开启子cȝassertQ父cȝassert仍然不运行。例如,我们执行java -ea:Derived Derived的时候,Basecȝassert语句q不执行。因此,我们可以认ؓQassert语句不具有承功能?/p>
assertion的用是一个复杂的问题Q因涉及到E序的风|assertionq用的目标,E序的性质{问题。通常来说Qassertion用于查一些关键的|q且q些值对整个E序Q或者局部功能的完成有很大的影响Qƈ且这U错误不Ҏ(gu)恢复的。assertion表达式应该短、易懂,如果需要评估复杂的表达式,应该使用函数计算。以下是一些用assertion的情늚例子Q这些方式可以让javaE序的可靠性更高?/p>
switch (x) { case 1: …; case 2: …; case 3: … default: assert false:"x value is invalid: "+x; }
assert value>=0:"Value should be bigger than 0:"+value;通过q种方式Q我们可以对函数计算完的l果q行查?
private boolean isBalance() { …… }在这个系l中Q在一些可能媄响这U^衡关pȝҎ(gu)的前后,我们都可以加上assert验证Qassert isBalance():"balance is destoried";
assertion为开发h员提供了一U灵zd调试和测试机Ӟ它的使用也非常简单、方ѝ但是,如何规范、系l地使用assertion(特别是在Java语言?仍然是一个亟待研I的问题?br />
关于作?/span> Ƨ阳辎ͼ北京大学计算机系士毕业Q?8qv开始研I基于java的Y件开发、测试,参与开发、测试过多个ZJava的应用程序和W(xu)eb服务目。联pL?a href="mailto:yeekee@sina.com">mailto:yeekee@sina.com 周欣Q北京大学计机pdd士生Q主要研I方向:E序理解、逆向工程及Y件度量,联系方式 zhouxin@sei.pku.edu.cn?/td> |
而我们调用interruptҎ(gu)也很有趣Q通常q个标志都是未被讄的,一旦调用这个方法,它就会设|这个标志,说白了,q个Ҏ(gu)所完成的工作也׃仅限于设|了一个这L(fng)标志。接下来p和上一D落中提到的事情相关联了Q如果线E当前是d的状态,那么它会利用q个标志啦,然后?#8220;三g事情”Q然后这个标志又被清除了Q如果线E当前是非阻塞状态,那么该方法的调用也就仅仅是设|一个标志而已Q注意设|了q个标记和没设|这个标记完全不同了Q一旦你再想调用sleep{阻塞方法时Q它们都?#8220;立刻跛_d状态、抛出异常、清除标?#8221;啦,呵呵?/p>
xQ终于清除了interruptҎ(gu)的作用了吧?
式,Eclipse会加上:private static final long serialVersionUID = 1L;
其实q个问题倒也不媄响程序的q行Q但是我看到Problems里面有警告就不舒服,同时也说明我们写的代码还是不规范。不怕,我们有互
联网查查是怎么回事Q具体的原因q就是和序列化中的这个serialVersionUID有关?br />
serialVersionUID 用来表明cȝ不同版本间的兼容性。如果你修改了此c? 要修Ҏ(gu)倹{否则以前用老版本的cd列化的类恢复时会出错
?br />
在JDK中,可以利用JDK的bin目录下的serialver.exe工具产生q个serialVersionUIDQ对于Test.classQ执行命令:serialver Test?/p>
Z在反序列化时Q确保类版本的兼Ҏ(gu),最好在每个要序列化的类中加入private static final long serialVersionUIDq个属性,?/p>
体数D己定义。这P即某个cd与之对应的对象已l序列化出去后做了修改,该对象依然可以被正确反序列化。否则,如果不显式定?/p>
该属性,q个属性值将由JVMҎ(gu)cȝ相关信息计算Q而修改后的类的计结果与修改前的cȝ计算l果往往不同Q从而造成对象的反序列化因
为类版本不兼容而失败?/p>
不显式定义这个属性值的另一个坏处是Q不利于E序在不同的JVM之间的移植。因Z同的~译器实现该属性值的计算{略可能不同Q从?/p>
造成虽然cL有改变,但是因ؓJVM不同Q出现因cȝ本不兼容而无法正反序列化的现象出现?/p>
serialVersionUID作用Q?
序列化时Z保持版本的兼Ҏ(gu),卛_版本升时反序列化仍保持对象的唯一性?
你可以随便写一个,在Eclipse中它替你生成一个,有两U生成方式:
一个是默认?LQ比如:private static final long serialVersionUID = 1L;
一个是Ҏ(gu)cd、接口名、成员方法及属性等来生成一?4位的哈希字段Q比如:private static final long serialVersionUID = -
8940196742313994740L;之类的?/p>
当你一个类实现了Serializable接口Q如果没有定义serialVersionUIDQEclipse会提供这个提C功能告诉你d义之?
在Eclipse中点ȝ中warning的图标一下,Eclipse׃自动l定两种生成的方式,如上面所q。如果不惛_义它Q在Eclipse的设|中也可?/p>
把它x的,讄如下Q?
Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems
Serializable class without serialVersionUID的warningҎ(gu)ignore卛_?
如果你没有考虑到兼Ҏ(gu)问题时Q就把它xQ不q有q个功能是好的,q个serialVersionUIDZ让该cdSerializable向后兼容?
如果你的cSerialized存到盘上面后,可是后来你却更改了类别的field(增加或减或改名)Q当你DeserializeӞ׃出现Exception的,
q样׃造成不兼Ҏ(gu)的问题?
但当serialVersionUID相同Ӟ它就会将不一L(fng)field以type的预讑րDeserializeQ这个可以避开不兼Ҏ(gu)的问题?br />
1Q?private
cM限定为private的成员,只能被这个类本n讉K?br />
如果一个类的构造方法声明ؓprivate,则其它类不能生成该类的一个实例?/p>
2Q?default
cM不加M讉K权限限定的成员属于缺省的QdefaultQ访问状态,可以被这个类本n和同一个包中的cL讉K?/p>
3Q?protected
cM限定为protected的成员,可以被这个类本n、它的子c(包括同一个包中以及不同包中的子类Q和同一个包中的所有其他的c访问?/p>
4Q?public
cM限定为public的成员,可以被所有的c访问?/p>
?-1列出了这些限定词的作用范围?/p>
【表3-1】 java中类的限定词的作用范围比?br />
=============================================================
|| 同一个类 同一个包的类 不同包的子类 不同包非子类 ||
|| private * ||
|| default * * ||
|| protected * * * ||
|| public * * * * ||
=============================================================
说明Q上面这个表Q看h很简单,而且也很Ҏ(gu)记忆Q但是却蕴含着极ؓ丰富的信息,可以从不同的角度来理解上面的q个表?br />
比如在同一个类里面Ӟ四个关键词都相当于是publicQ可以不在乎限定词是什么;在同一个包里面Ӟ除了private限定词外Q所有的限定词的作用都完全等同于public。我们经怼思考这样一个问题:一个类的属性和Ҏ(gu)是否对外可见Q这个问题描qC提到?#8220;可见”二字Q当环境?#8220;非子c?#8221;Ӟ说白了就是我们能否通过实例化这个类后,用一个对象把q个cȝq些字段或者方法给“?#8221;出来Q即“某对?某属性(或某Ҏ(gu)Q?#8221;。因为通常我们都是在不同包的环境下操作的,比如我们会import很多pȝ的包中的c,诸如“import java.awt.*;”q样的语句,因此我们使用q些包中的类Ӟ它们Ҏ(gu)们的可见也就仅仅局限在使用“public”限定词修饰的属性或Ҏ(gu)上了Q因此大家往往会误以ؓ只有public的东西才能点出来Q实则不Ӟ当我们在同一个包中的非子cM也可以把除了private修饰的东西之外的所有属性和Ҏ(gu)l?#8220;?#8221;出来。其实对?#8220;?#8221;q个q算Q可以分两个角度ȝ解,既然能用?#8220;?#8221;操作Q那׃表了我们使用的环境应该是“非子c?#8221;Q非子类又可以分?#8220;包内”?#8220;非包?#8221;Q对?#8220;包内”Q只要不是private修饰的东襉K能点出来Q对?#8220;非包?#8221;则只能是public的东西才能点出来Q;Q如果是?#8220;子类”中操作时Q大家可以思考一下,我们q用“?#8221;操作吗?昄不用了,因ؓ在子cMQ父cM定义的东西只要可见的话都可以被你拿过来用Q因此根本就用不到点操作Q当然这里也要分“包内”?#8220;非包?#8221;。对于default限定词,我们不能昄的用它来定义属性或Ҏ(gu)Q只要我们在定义属性或Ҏ(gu)的前面什么限定词都不加,默认的使用了default限定词?/p>
final变量是在整个c被创徏时候被赋|之后׃能改变了?
对于final变量Q如果在声明的时候和构造的时候均不进行赋|~译出错?
对于利用构造方法对final变量q行赋值的时候,此时在构造之前系l设|的默认D覆盖?
帔RQ这里的帔R指的是实例常量:x员变量)赋|
①在初始化的时候通过昑ּ声明赋倹{final int x=3Q?
②在构造的时候赋倹{?
class A{
final int x;
public A(){
x=4;
}
}
2. finalҎ(gu)不能被改?
利用final定义Ҏ(gu)Q这L(fng)Ҏ(gu)Z个不可覆盖的Ҏ(gu)?
下面q样׃~译出错Q?br />
class A{
public static void max(){
System.out.println("A:max()");
}
}
class B extends A{
public void max(){
}
}
Z保证Ҏ(gu)的一致性(即不被改变)Q可方法用final定义?
如果在父cM有final定义的方法,那么在子cM保证调用的是同一个父cL法?
如果一个方法前有修饰词private或staticQ则pȝ会自动在前面加上final。即private和staticҎ(gu)默认均ؓfinalҎ(gu)?
注:cȝ修饰W仅限于abstract、final、public。Final和abstract永远不会同时出现?
3. finalcM能被l承;
final修饰cȝ时候,此类不可被承,即finalcL有子cR这样可以用final保证用户调用时动作的一致性,可以防止子类覆盖情况的发生?
String cd是finalc?Q目的是提供效率保证安全?/p>
import java.applet.*;
import java.net.*;
public class InetAddDemo extends Applet{
public void test(){
try{
InetAddress add=InetAddress.getLocalHost();
System.out.println(add.getHostAddress());
System.out.println(add.getHostName());
System.out.println(InetAddress.getLocalHost());
System.out.println(add.hashCode());
byte [] b= add.getAddress();
/*ByteArrayInputStream bais=new ByteArrayInputStream(b);
InputStreamReader isr=new InputStreamReader(bais);
BufferedReader br=new BufferedReader(isr);
char [] ch=new char[b.length];
br.read(ch);
System.out.println(ch);
q段代码依然不能够打印出我们期望的结?/
String s = "12345abcd";
byte b2[] = s.getBytes();
System.out.println(b2.toString());
String s1="d?a?";
byte [] s2=s1.getBytes();
String s3=new String (s2);
System.out.println(s3);
String tt=new String(b);
System.out.println(tt);
System.out.println(Bytes2String(b));
System.out.println(add.toString());
}catch(Exception e){
System.out.println(e.getMessage());
}
}
public void init(){
test();
}
public String Bytes2String(byte [] b){
String str="";
for(int i=0;i<b.length;i++){
int t=(b[i]<<24)>>>24;
str+=Integer.toString(t)+".";
}
str=str.substring(0, str.length()-1);
return str;
}
}
/*说明Q?br />
Q?Qjava中定义变量ƈ不需要赋予初始|pȝ自动为其?值或nullQ但是这仅限于在cM定义的属于类的类变量Q?br />
而对于在cdC定义的(f)时变量,则必要赋初始|否则会出错的Q?br />
Q?Q位q算赋默认的两端都是int型变量,而且q回g是int型的。如果在位运符的两端有一个变量ؓlong型,则返回g为long型?br />
Q?Q对于bytecdQ比较特D,首先它是整型Q而且只有一个字节长度,而且是有W号的,q里需要特别说明的?br />
java中不会区分无W号和有W号Q既然byte是一个字节的有符hQ那它的表示范围是-128~127Q但是我们经怼把byte作ؓ
单字节的容器Q比如在文gdӞ或作为缓冲区旉是用byteq种cdQ如果要把byte转化为字W时׃有问题,
比如Q例如下面一个例?
import java.io.UnsupportedEncodingException;
public class test{
public static void main(String g[]) {
String s = "12345abcd";
byte b[] = s.getBytes();
String t = b.toString();
System.out.println(t);
}
}
输出字符串的l果和字W串s不一样了.
q是因ؓ对于byte[]cdQ它也是Object的子c,但是数组q种Ҏ(gu)的子cdƈ没有特别的实现自qtoString()Ҏ(gu)Q因此我们调?br />
"b.toString()"后,实际上还是调用了Object父类里的toStringҎ(gu)<函数体内的具体代码是Q?br />
getClass().getName() + "@" + Integer.toHexString(hashCode())>Q该Ҏ(gu)只是q回了该cȝName+@+hashCode而已Q?br />
有意思的是,对于数组c,cd字是?["后紧跟数l的cdQ比如这里返回的是"[B"Q呵呵,挺有吧Q?/p>
l过以下方式转码可以正{换了:
public class test{
public static void main(String g[]) {
String s = "12345abcd";
byte b[] = s.getBytes();
try {
String t = new String(b);
System.out.print(t);
} catch (Exception e) {
e.printStackTrace();
}
}
}
因此如果只是单纯的用它来作Z个中转的用途,那就无所谓了Q但是一旦涉及到和字W的转化时就会有问题Q?br />
q里暂且用上q提到的Ҏ(gu)Q即重新构造一个String对象Q但是构造String对象有着如下的从byte[]
转化为Stringcd的潜规则Q?br />
如果byte里存储的数据范围?~127Ӟ也就是字节的首位?Ӟ׃byte[]数组中的一个字节拿出来转化Z?br />
两个字节的charcdQƈ把这个字W放到String中,如果范围?128~-1Ӟ也就是首位ؓ1Ӟ׃自动的把
btye[]中下一个字节也拿出来,让这两个字节l合成一个两字节的charcdQ然后存攑ֈString中。从q里
也可以看Z个潜规则Q汉字表C成两字节的二进制时Q第一个字节肯定是负倹{?br />
因此对于今天做的q个E序来说Q想要把保存在byte[]中的IP地址数值直接拿出来Q需要h为的把byte中存储的
有符h转化为无W号数据Q用单的位操作就可以实现了?br />
Q?Q还需要说明的一Ҏ(gu)Qjava中没有运符重蝲Q对于StringcL谓的+号可以连接字W串Q其实只是在~译器里面做了点手脚Q?br />
q不是真正意义上的运符重蝲?br />
Q?Q最后,q要说明的是Q要熟练的掌握String和各U数值类型之间的转化Ҏ(gu)Q?br />
举int型和Stringcd转化的例子吧Q?br />
int b --> String strQ?br />
<1>str=""+b;
<2>str=Integer.toString(b);//从int出发Q利用Integer包装cd?br />
<3>str=String.valueOf(b);//从str出发Q利用Stringcd?br />
String str --> int b;
b=Integer.parseInt(str);
b=Integer.parseInt(str, int radix);
最后,再对Integer.parseIntҎ(gu)作一点说明,str字符串只能ؓ三种形式之一Q即"[0-9]*"?-[0-9]*"
?\u002D[0-9]*"两种形式之一Q其中负?-'的ASCii码就是\u002DQ因此这两种形式是等L(fng)Q除此之?br />
的Ş式均非法Q这里ؓ了写得简z,使用了正则表辑ּ的写法[0-9]*表示L长度数字序列?br />
*/
import java.io.IOException;
import java.net.*;
public class UDPServer implements Runnable{
/**
* @param args
*/
public UDPServer(){
new Thread(this).start();
try{
DatagramSocket dgs=new DatagramSocket(8765);
byte [] buf=new byte[1024];
DatagramPacket dgp=new DatagramPacket(buf,buf.length);
for(int i=0;i<3;i++){
dgs.receive(dgp);
System.out.println("The server has received the datagram!");
dgs.send(dgp);
}
}catch(IOException ioe){
ioe.printStackTrace();
}
}
public static void main(String[] args) {
// TODO Auto-generated method stub
new UDPServer();
}
public void run() {
// TODO Auto-generated method stub
new UDPClient();
}
}
/*
说明Q?br />
q里要对UDP方式作一个简要的说明Q构成UDP通信机制的主要是两个c,即DatagramSocket和DatagramPacketQ?br />
主要包括发送和接收两个斚w的内容,对于发送方来说Q需要:
Q?Q徏立一个DatagramSocket对象Q注意徏立的时候不需要指定端口,因ؓ发送方x的是发送成功,而不在乎是从本机的哪个端口发送出ȝQ?br />
而发送的具体事宜则是由DatagramPacket来完成的Q包括对目的地址的指定?br />
Q?Q徏立一个DatagramPacket对象Q注意要制定目的地址和对应的端口A?br />
Q?Q调用DatagramSocket对象的send函数发送,send函数的参数就是刚建立的DatagramPacket对象?br />
对于接收Ҏ(gu)Ԍ需要:
Q?Q徏立一个DatagramSocket对象Q注意要指定端口Q因Z为接收方Q不在乎接收的东西是从哪里来的,而只是在本机的一个指定端口进?br />
接收ok了,但需要注意这里的端口要与发送方投递的端口A一致?br />
Q?Q徏立一个DatagramPacket对象Q注意不必指定地址和端口,因ؓq是被动的接Ӟ而在接收q程中,该DatagramPacket对象
扮演的角色仅仅是一个信息的承蝲者,也就是把从端口来的信息封存到它里面?br />
Q?Q调用DatagramSocket对象的receive函数接收Qreceive函数的参数就是刚建立的DatagramPacket对象?/p>
最后,q有一炚w要说明,是在刚刚指出的接受模式来说Q比如说本例中,虽然未给DatagramPacket对象指定地址和端口,但是
依然可以调用send函数q行发送,q是Z么呢Q因为它先调用了receive函数Q通过调用该函敎ͼ可以在接收过E中保存了信息的来源Q?br />
也就是地址和端口,因此下次再用send发送时Q就仍然往q个地址和端口发送数据,因此可以发送成功?br />
*/
对于轻量U组Ӟ都是l承于ContainercȝQ?#8220;轻量U?#8221;部g需要一个处在容器体pM?#8220;重量U?#8221;部g提供q行l画的场所。当q个“重量U?#8221;?#8220;宗”被告知要l制自n的窗体时Q它必须把这个绘ȝh转化为对其所有子孙的l画h。这是由java.awt.Container的paint()Ҏ(gu)处理的,该方法调用包容于其内的所有可见的、ƈ且与l画区相交的轻量U部件的paint()Ҏ(gu)。因此对于所有覆盖了paint()Ҏ(gu)的Container子类Q?#8220;轻量U?#8221;?#8220;重量U?#8221;QContainer的子cM一定都是轻量lg哦,呵呵Q都需要在函数的最后调用父cȝpaintҎ(gu)Q即super.paint(g)?/p>
最后,对于AWTl制Q给Z下准则:
a.对于大多数程序,所有的客户区绘M码应该被攄在部件的paint()Ҏ(gu)中?
b.通过调用repaint()Ҏ(gu)Q程序可以触发一个将来执行的paint()调用Q不能直接调用paint()Ҏ(gu)?
c.对于界面复杂的部Ӟ应该触发带参数的repaint()Ҏ(gu)Q用参数定义实际需要更新的区域Q而不带参数调用会D整个部g被重甅R?
d.因ؓ对repaint()的调用会首先Dupdate()的调用,默认C促成paint()的调用,所以重量部g应该覆盖update()Ҏ(gu)以实现增量绘Ӟ如果需要的?轻量U部件不支持增量l制) ?
e.覆盖了paint()Ҏ(gu)的java.awt.Container子类应当在paint()Ҏ(gu)中调用super.paint()以保证子部g能被l制?
f.界面复杂的部件应该灵zd使用裁剪区来把绘画范围羃?yu)到只包括与裁剪区相交的范围?/p>
==============================================================================
Swingl画的处理过E?br />
Swing处理"repaint"h的方式与AWT有稍微地不同Q虽然对于应用开发h员来讲其本质是相同的 -- 同样是触发paint()。Swingq么做是Z支持它的RepaintManager API (后面介绍)Q就象改善绘L能一栗在Swing里的l画可以C条\Q如下所qͼ
(A) l画需求首先生于一个重量先(通常是JFrame、JDialog、JWindow或者JApplet)Q?br />
1。事件分zE调用其先的paint()
2。Container.paint()的默认实C递归地调用Q何轻量子孙的paint()Ҏ(gu)?br />
3。当到达W一个Swing部gӞJComponent.paint()的默认执行做下面的步骤:
i.如果部g的双~冲属性ؓtrueq且部g的RepaintManager上的双缓冲已l激z,把Graphics对象转换Z个合适的屏外Graphics?
ii.调用paintComponent()(如果使用双缓冲就把屏外Graphics传递进??
iii.调用paintBorder()(如果使用双缓冲就把屏外Graphics传递进??br />
iv.调用paintChildren()(如果使用双缓冲就把屏外Graphics传递进?Q该Ҏ(gu)使用裁剪q且遮光和optimizedDrawingEnabled{属性来严密地判定要递归地调用哪些子孙的paint()?
v.如果部g的双~冲属性ؓtrueq且在部件的RepaintManager上的双缓冲已l激z,使用最初的屏幕Graphics对象把屏外映像拷贝到部g上?/p>
注意QJComponent.paint()步骤#1?5在对paint()的递归调用中被忽略?q里的JComponent指的是在paintChildren()函数中判断出的需要递归调用的组Ӟ在步?4中介l了)Q因为所有在swingH体层次中的轻量U部件将׃n同一个用于双~冲的屏外映像?
(B) l画需求从一个javax.swing.JCponent扩展cȝrepaint()调用上生:
1。JComponent.repaint()注册一个针寚w件的RepaintManager的异步的重画需求,该操作用invokeLater()把一个Runnable加入事g队列以便E后执行在事件分zE上的需求?
2。该Runnable在事件分zE上执行q且D部g的RepaintManager调用该部件上paintImmediately()Q该Ҏ(gu)执行下列步骤Q?/p>
i.使用裁剪框以及遮光和optimizedDrawingEnabled属性确?#8220;?#8221;部gQ绘M定从q个部g开?处理透明以及潜在的重q部??
ii.如果栚w件的双缓冲属性ؓtrueQƈ且根部g的RepaintManager上的双缓冲已Ȁz,{换Graphics对象到适当的屏外Graphics?
iii.调用栚w?该部件执行上q?A)中的JComponent.paint()步骤#2-4)上的paint()Q导致根部g之下的、与裁剪框相交的所有部件被l制?
iv.如果栚w件的doubleBuffered属性ؓtrueq且栚w件的RepaintManager上的双缓冲已l激z,使用原始的Graphics把屏外映像拷贝到部g?/p>
注意Q如果在重画没有完成之前Q又有发生多起对部g或者Q何一个其先的repaint()调用Q所有这些调用会被折q到一个单一的调用,卛_到最上层Q这里的层指的是那种HierarchyQ而不是展现给我们的最上面的那个图或者按钮)的SWing部g的paintImmediately()Q调用它的repaint()。例如,如果一个JTabbedPane包含了一个JTableq且在其包容层次中的现有的重画需求完成之前两ơ发布对repaint()的调用,其结果将变成对该JTabbedPane部g的paintImmediately()Ҏ(gu)的单一调用Q会触发两个部g的paint()的执行?br />
q意味着对于Swing部g来说Qupdate()不再被调用?
虽然repaint()Ҏ(gu)D了对paintImmediately()的调用,它不考虑"回调"l图Qƈ且客L(fng)的绘M码也不会攄到paintImmediately()Ҏ(gu)里面。实际上Q除非有Ҏ(gu)的原因,Ҏ(gu)不需要超载paintImmediately()Ҏ(gu)?
===================================================================================
Swingl画准则
Swing开发h员在写绘M码时应该理解下面的准则:
1。对于Swing部gQ不是pȝQ触发还是程序-触发的请求,M调用paint()Ҏ(gu)Q而update()不再被Swing部g调用?
2。程序可以通过repaint()触发一个异步的paint()调用Q但是不能直接调用paint()?
3。对于复杂的界面Q应该调用带参数的repaint()Q这样可以仅仅更新由该参数定义的区域Q而不要调用无参数的repaint()Q导致整个部仉甅R?
4。Swing中实现paint()?个要素是调用3个分ȝ回调Ҏ(gu)Q?br />
paintComponent()
paintBorder()
paintChildren()
Swing部g的子c,如果x行自ql画代码Q应该把自己的绘M码放在paintComponent()Ҏ(gu)的范围之内?不要攑֜paint()里面)?
5。Swing引进了两个属性来最大化的改善绘ȝ性能|?
opaque: 部g是否要重d所占据范围中的所有像素位Q?
optimizedDrawingEnabled: 是否有这个部件的子孙与之交PQ?
6。如果Swing部g?遮光)opaque属性设|ؓtrueQ那pC它要负责绘制它所占据的范围内的所有像素位(包括在paintComponent()中清除它自己的背?Q否则会造成屏幕垃圾?
7。如果一个部件的遮光?opaque)和optimizedDrawingEnabled属性有一个被讄为falseQ将D在每个绘L作中要执行更多的处理Q因此我们推荐的明智的方法是同时使用透明q且交P部g?
8。用UI代理(包括JPanel)的Swing部g的扩展类的典型作法是在它们自qpaintComponent()的实C调用super.paintComponent()。因为UI代理可以负责清除一个遮光部件的背景Q不q这一操作需要根据规?5中的讑֮来决定?br />
9。Swing通过JComponent的doubleBuffered属性支持内|的双缓Ԍ所有的Swing部g该属性默认值是trueQ然而把Swing容器的遮光设|ؓtrue有一个整体的构思,把该容器上的所有轻量子孙的属性打开Q不它们各自的讑֮?
10。强烈徏议ؓ所有的Swing部g使用双缓册Ӏ?
11。界面复杂的部g应该灉|地运用剪切框来,只对那些与剪切框怺的区域进行绘L作,从而减工作量?
P.S.英文出处Qhttp://java.sun.com/products/jfc/tsc/articles/painting/index.html
构造方法摘?/strong> | |
---|---|
JTree() q回带有CZ模型? JTree ?/td>
| |
JTree(Hashtable<?,?> value) q回? Hashtable 创徏?JTree Q它不显C根?/td>
| |
JTree(Object[] value) q回 JTree Q指定数l的每个元素作ؓ不被昄的新根节点的子节炏V?/td>
| |
JTree(TreeModel newModel) q回 JTree 的一个实例,它显C根节点 - 使用指定的数据模型创建树(wi)?/td>
| |
JTree(TreeNode root) q回 JTree Q指定的 TreeNode 作ؓ其根Q它昄根节炏V?/td>
| |
JTree(TreeNode root, boolean asksAllowsChildren) q回 JTree Q指定的 TreeNode 作ؓ其根Q它用指定的方式昄根节点,q确定节Ҏ(gu)否ؓ叶节炏V?/td>
| |
JTree(Vector<?> value) q回 JTree Q指?Vector 的每个元素作Z被显C的新根节点的子节点?/td>
|
常用Ҏ(gu)Q?br />
1。得到模型:
getModel()?DefaultTreeModel)getModel()
2。得到根Q?br />
getModel().getRoot()?DefaultMutableTreeNode)getModel().getRoot()
3。根据node得到pathQ?br />
TreePath visiblePath = new TreePath(((DefaultTreeModel)getModel()).getPathToRoot(node))
4。根据Path展开到该节点Q?br />
makeVisible(visiblePath)
5。根据path讑֮该节炚w定
tree.setSelectionPath(visiblePath)
6。滚动到可见位置Q?br />
scrollRowToVisible(int row)
7。展开?lt;从根展开或从某一个节点展开>
关于JTree的展开
// If expand is true, expands all nodes in the tree.
// Otherwise, collapses all nodes in the tree.
public static void expandAll(JTree tree, boolean expand) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
// Traverse tree from root
expandAll(tree, new TreePath(root), expand);
}
private static void expandAll(JTree tree, TreePath parent, boolean expand) {
// Traverse children
TreeNode node = (TreeNode) parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
8。遍历树(wi)的所有节?lt;从根遍历或从某一个节炚w?gt;
public static void visitAllNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllNodes(tree,root);
}
public static void visitAllNodes(JTree tree,TreeNode node) {
// node is visited exactly once
//you can do your things about this node,such as:
tree.makeVisible(new TreePath(
((DefaultTreeModel)tree.getModel()).getPathToRoot(node)));
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
visitAllNodes(tree,n);
}
}
}
9。遍历树(wi)已经展开的节?lt;从根遍历或从某一个节炚w?gt;
// Traverse all expanded nodes in tree
public static void visitAllExpandedNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllExpandedNodes(tree, new TreePath(root));
}
public static void visitAllExpandedNodes(JTree tree, TreePath parent) {
// Return if node is not expanded
if (!tree.isVisible(parent)) {
return;
}
// node is visible and is visited exactly once
TreeNode node = (TreeNode) parent.getLastPathComponent();
//you can do your things about this node,such as:
System.out.println(node.toString());
// Visit all children
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
visitAllExpandedNodes(tree, path);
}
}
}
一个较为完整的l习(fn)Q?br />
import java.awt.Dimension;
import java.awt.Color;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Enumeration;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.BoxLayout;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;
public class JTreeDemo {
public static void expandAll(JTree tree, boolean expand) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
// Traverse tree from root
expandAll(tree, new TreePath(root), expand);
}
private static void expandAll(JTree tree, TreePath parent, boolean expand) {
// Traverse children
TreeNode node = (TreeNode) parent.getLastPathComponent();
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
expandAll(tree, path, expand);
}
}
// Expansion or collapse must be done bottom-up
if (expand) {
tree.expandPath(parent);
} else {
tree.collapsePath(parent);
}
}
public static void visitAllNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllNodes(tree,root);
}
public static void visitAllNodes(JTree tree,TreeNode node) {
// node is visited exactly once
//you can do your things about this node,such as:
tree.makeVisible(new TreePath(
((DefaultTreeModel)tree.getModel()).getPathToRoot(node)));
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
visitAllNodes(tree,n);
}
}
}
// Traverse all expanded nodes in tree
public static void visitAllExpandedNodes(JTree tree) {
TreeNode root = (TreeNode) tree.getModel().getRoot();
visitAllExpandedNodes(tree, new TreePath(root));
}
public static void visitAllExpandedNodes(JTree tree, TreePath parent) {
// Return if node is not expanded
if (!tree.isVisible(parent)) {
return;
}
// node is visible and is visited exactly once
TreeNode node = (TreeNode) parent.getLastPathComponent();
//you can do your things about this node,such as:
System.out.println(node.toString());
// Visit all children
if (node.getChildCount() >= 0) {
for (Enumeration e = node.children(); e.hasMoreElements();) {
TreeNode n = (TreeNode) e.nextElement();
TreePath path = parent.pathByAddingChild(n);
visitAllExpandedNodes(tree, path);
}
}
}
public static JTree tr;
public static void main(String[] args) {
// 构造函敎ͼJTree()
JTree example1 = new JTree();
tr=example1;
example1.setBackground(Color.lightGray);
example1.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent me){
try{
visitAllNodes(tr);
Thread.sleep(2000);
System.out.println(tr.getPathForRow(1).toString());
expandAll(tr,tr.getPathForRow(1),false);
Thread.sleep(2000);
visitAllExpandedNodes(tr);
}catch(InterruptedException e){
e.printStackTrace();
}
}
});
// 构造函敎ͼJTree(Object[] value)
Object[] letters = { " a ", " b ", " c ", " d ", " e " };
JTree example2 = new JTree(letters);
// 构造函敎ͼJTree(TreeNode root)(TreeNodeI?
// 用空l点创徏?br />
DefaultMutableTreeNode node1 = new DefaultMutableTreeNode(); // 定义?wi)结?br />
JTree example3 = new JTree(node1); // 用此?wi)结点做参数调?JTree的构造函数创建含有一个根l点的树(wi)
// 构造函敎ͼJTree(TreeNode root)(同上,只是TreeNode非空)
// 用一个根l点创徏?br />
DefaultMutableTreeNode node2 = new DefaultMutableTreeNode(" Color ");
JTree example4 = new JTree(node2); // l点不可以颜?默认为白面黑?br />
example4.setBackground(Color.lightGray);
// 构造函敎ͼJTree(TreeNode root, boolean
// asksAllowsChildren)(同上,只是TreeNode又有不同)
// 使用DefaultMutableTreeNodecd用一个根l点创徏?wi),讄为可d孩子l点,再添加孩子结?br />
DefaultMutableTreeNode color = new DefaultMutableTreeNode(" Color ",
true);
DefaultMutableTreeNode gray = new DefaultMutableTreeNode(" Gray ");
color.add(gray);
color.add(new DefaultMutableTreeNode(" Red "));
gray.add(new DefaultMutableTreeNode(" Lightgray "));
gray.add(new DefaultMutableTreeNode(" Darkgray "));
color.add(new DefaultMutableTreeNode(" Green "));
JTree example5 = new JTree(color);
// 构造函敎ͼJTree(TreeNode root)(同上,只是TreeNode非空)
// 通过逐个dl点创徏?br />
DefaultMutableTreeNode biology = new DefaultMutableTreeNode(" Biology ");
DefaultMutableTreeNode animal = new DefaultMutableTreeNode(" Animal ");
DefaultMutableTreeNode mammal = new DefaultMutableTreeNode(" Mammal ");
DefaultMutableTreeNode horse = new DefaultMutableTreeNode(" Horse ");
mammal.add(horse);
animal.add(mammal);
biology.add(animal);
JTree example6 = new JTree(biology);
horse.isLeaf();
horse.isRoot();
// 构造函?JTree(TreeModel newModel)
// 用DefaultMutableTreeNodelcd义一个结点再用这个结点做参数定义一个用DefaultTreeMode
// 创徏一个树(wi)的模?再用JTree的构造函数创Z个树(wi)
DefaultMutableTreeNode root = new DefaultMutableTreeNode(" Root1 ");
DefaultMutableTreeNode child1 = new DefaultMutableTreeNode(" Child1 ");
DefaultMutableTreeNode child11 = new DefaultMutableTreeNode(" Child11 ");
DefaultMutableTreeNode child111 = new DefaultMutableTreeNode(
" Child111 ");
root.add(child1);
child1.add(child11);
child11.add(child111);
DefaultTreeModel model = new DefaultTreeModel(root);
JTree example7 = new JTree(model);
JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.X_AXIS));
panel.setPreferredSize(new Dimension(700, 400));
panel.add(new JScrollPane(example1)); // JTree必须攑֜JScrollPane?br />
panel.add(new JScrollPane(example2));
panel.add(new JScrollPane(example3));
panel.add(new JScrollPane(example4));
panel.add(new JScrollPane(example5));
panel.add(new JScrollPane(example6));
panel.add(new JScrollPane(example7));
JFrame frame = new JFrame(" JTreeDemo ");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setContentPane(panel);
frame.pack();
frame.setVisible(true);
}
}
另外一个例子,在该例子中笔者用基于本机目录构建的模型来构建树(wi)Q?br />
/**
* 查API时发?.4FileSystemViewq个东东多了一些功?
* 无聊地写了这个文件目录树(wi)
*
* 声明Q用j2sdk1.4
* :实现自己的Filec,以过滤掉一般文Ӟ只剩下目?
* ~点Qgui慢得要死,swing的通病?(my pc==256ddr,thunderbird900,xp)
*/
import java.awt.Component;
import java.io.*;
import javax.swing.*;
import javax.swing.event.TreeModelListener;
import javax.swing.filechooser.FileSystemView;
import javax.swing.tree.*;
public class Test {
/**
* javax.swing.filechooser.FileSystemView在这个程序里很重要,
* 用法参考j2sdk1.4 API文
* 切记Q?.4 not 1.3!!!!!!!!
*/
private static FileSystemView fileView;
int a=BB;
static int BB=34;
/**
*在这里用了Singleton模式
* 不过g没什么破?
*/
static FileSystemView getFileView() {
if (fileView == null)
fileView = FileSystemView.getFileSystemView();
return fileView;
}
public static void main(String[] args) throws Exception {
//如果加入下面q句,会ؕ?i wonder why
UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
//initial frame
JFrame frame = new JFrame();
frame.setSize(400, 300);
//关闭H口旉出程?
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//initial tree with customer TreeModel
JTree tree = new JTree(new CustomTreeModel());
//set customer TreeCellRenderer
tree.setCellRenderer(new CustomTreeCellRenderer());
frame.getContentPane().add(new JScrollPane(tree));
frame.setVisible(true);
}
}
class CustomTreeModel implements TreeModel {
private FileSystemView fileView;
public CustomTreeModel() {
fileView = Test.getFileView();
}
//q回根节?
public Object getRoot() {
return fileView.getRoots()[0];
}
//q回父节点parent的第index个子节点,index?开?
public Object getChild(Object _parent, int index) {
File parent = (File) _parent;
return parent.listFiles()[index];
}
//q回父节点parent?子节点child的位|?与上面的Ҏ(gu)正好相反
public int getIndexOfChild(Object parent, Object child) {
File[] files = ((File) parent).listFiles();
for (int i = 0; i < files.length; i++) {
if (files[i].equals(child))
return i;
}
return -1;
}
//q回父节点parent的子节点?
public int getChildCount(Object parent) {
File[] files = ((File) parent).listFiles();
/**
*maybe driver not ready,ie cdrom
*then files is null
*/
if (files == null)
return -1;
return files.length;
}
//是否叶节?
public boolean isLeaf(Object node) {
return ((File) node).isFile();
}
public void valueForPathChanged(TreePath path, Object newValue) {
}
/**
*下面的方法要实现,则要涉及比较复杂的事件处?
*如果有兴?
*可以单的使用javax.swing.EventListenerList来实?
*/
public void addTreeModelListener(TreeModelListener l) {
}
public void removeTreeModelListener(TreeModelListener l) {
}
}
/**
* 如果没有安装自己的CellRenderer
* JTree默认的CellRenderer是JLabel
* 它只是简单的setText(node.toString)
* CustomeTreeCellRenderer也只是简单取?
* windows默认的文件图标和文g?装到JLabel上去
*/
class CustomTreeCellRenderer extends DefaultTreeCellRenderer {
/**
*
*/
private static final long serialVersionUID = 3892593039200536416L;
private FileSystemView fileView;
public CustomTreeCellRenderer() {
fileView = Test.getFileView();
}
public Component getTreeCellRendererComponent(JTree tree, Object value,
boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus) {
super.getTreeCellRendererComponent(tree, value, selected, expanded,
leaf, row, hasFocus);
File file = (File) value;
setIcon(fileView.getSystemIcon(file));
setText(fileView.getSystemDisplayName(file));
return this;
}
}
JDBC是一个通用的底层的、支持基本SQL功能的Java API。它提供了两部分与数据库独立的APIQ即JDBC API和JDBC Driver API?
JavaE序通过JDBC API讉KJDBC Driver ManagerQJDBC Driver Manager再通过JDBC Driver API 讉K不同的JDBC驱动E序Q从而实现对不同数据库的讉K。说白了是底层是数据库Q上层是用户的访问请求,中间层包括各个数据库的各自的驱动E序、用戯用的API函数Q只不过q里的API有两个子层,中间加入了一个JDBC Driver Manager来进行管理。整个链是这L(fng)QDB--〉DB Driver--〉JDBC Driver API--〉JDBC Driver Manager--〉JDBC API--〉用?
JDBC URLl构Q?
jdbc:<子协?gt;:<子名U?gt;
例如Q?
jdbc:odbc:test
Tips:
(1)
如果通过|络来访问数据库Q则网l地址的放在子名称部分Q格式ؓQ?/hostname:port/sub protocol
例如Q?
jdbc:dbnet://ant:356/fred
(2)
对于odbc子协议,比较Ҏ(gu)Q可以在子名U后面接L多个属性值的特征。因此odbc子协议的完整语法为:
jdbc:odbc:<数据源名U?gt;[;<属性名>=<属性?gt;;......]
例如Q?
jdbc:odbc:mydb;UID=bacoo;PWD=bacoo
所有与数据库有关的对象和方法都?java.sql 包中Q因此在使用 JDBC 的程序中必须加入 "import java.sql.* "?JDBC 要连?ODBC 数据库,(zhn)必首先加?JDBC-ODBC 桥驱动程?
Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
该语句加载驱动程序,q创cȝ一个实例。然后,要连接一个特定的数据库,(zhn)必d?Connect cȝ一个实例,q?URL 语法q接数据库?
String url = "jdbc:odbc:Grocery prices";
Connection con = DriverManager.getConnection(url);
h意,(zhn)用的数据库名是?zhn)?ODBC 讄面板中输入的“数据?#8221;名称?
URL 语法可能因数据库cd的不同而变化极大?
jdbc:subprotocol:subname
W一l字W代表连?em>协议Qƈ且始l是 jdbc。还可能有一?em>子协?/em>Q在此处Q子协议被指定ؓ odbc。它规定了一cL据库的连通性机制。如果?zhn)要连接其它机器上的数据库服务器,可能也要指定该机器和一个子目录Q?
jdbc:bark//doggie/elliott
最后,(zhn)可能要指定用户名和口oQ作接字W串的一部分Q?
jdbc:bark//doggie/elliot;UID=GoodDog;PWD=woof
*******************************************************************************************
*******************************************************************************************
上面l出了连接数据库的一U方法,其实q有另外一U方法,如下Q?
System.setProperty("jdbc.drivers","sun.jdbc.odbc.JdbcOdbcDriver");
String url = "jdbc:odbc:Grocery prices";
Connection con=DriverManager.getConnection(url);
说明Q?
我们可以用System.getProperty("jdbc.drivers")对设定的System属性D行查询。其实,对于System属性,pȝ认可的属性如下:
java.version Java Runtime Environment version
java.vendor Java Runtime Environment vendor
java.vendor.url Java vendor URL
java.home Java installation directory
java.vm.specification.version Java Virtual Machine specification version
java.vm.specification.vendor Java Virtual Machine specification vendor
java.vm.specification.name Java Virtual Machine specification name
java.vm.version Java Virtual Machine implementation version
java.vm.vendor Java Virtual Machine implementation vendor
java.vm.name Java Virtual Machine implementation name
java.specification.version Java Runtime Environment specification version
java.specification.vendor Java Runtime Environment specification vendor
java.specification.name Java Runtime Environment specification name
java.class.version Java class format version number
java.class.path Java class path
java.library.path List of paths to search when loading libraries
java.io.tmpdir Default temp file path
java.compiler Name of JIT compiler to use
java.ext.dirs Path of extension directory or directories
os.name Operating system name
os.arch Operating system architecture
os.version Operating system version
file.separator File separator ("/" on UNIX)
path.separator Path separator (":" on UNIX)
line.separator Line separator ("\n" on UNIX)
user.name User's account name
user.home User's home directory
user.dir User's current working directory
大家可以看到其中q没有jdbc.driversq一个属性,但是System的属性可以随意的由我们来dQ比如我们用setProperty讑֮了一个名?#8220;bacoo”的属性,q指定该属性gؓ“test”的话Q那么当我们用getProperty时就可以索到属性bacoo的gؓtest。这里之所以要加入“jdbc.drivers”q个属性|是因为DriverManagerq个c默认的会在初始化时去System中搜索这一属性的|在这个属性g我们可以多个需要加载的驱动用冒?#8220;:”隔开Q又׃DriverManager是一个静态类Q其实在定义一个类Ӟ不允许用static修饰Q只允许public、final、abstract三个修饰W,q里说其是静态类指的是该cȝ所有方法和属?lt;其实该类也没有属性,q构造函数都没有>均是静态的Q,因此在调用DriverManager.getConnection(url)ӞDriverManager需要先初始化,׃加蝲驱动了?
一旦连接到数据库,可以请求表名以及表列的名称和内容等信息Q而且(zhn)可以运?SQL 语句来查询数据库或者添加或修改其内宏V可用来从数据库中获取信息的对象有:
有关整个数据库的信息Q表名、表的烦引、数据库产品的名U和版本、数据库支持的操作?
DatabaseMetaData dbmd;
dbmd=con.getMetaData();
下面重点介绍一下DatabaseMetaDat中的两个重要函数getTables和getColumnsQ?
ResultSet
getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types)
仅返回与目录、模式、表名称和(表)cd标准匚w的表描述?
catalogQ要在其中查找表名的目录名。对?JDBC-ODBC 数据库以及许多其他数据库而言Q可其讄?null。这些数据库的目录项实际上是它在文gpȝ中的l对路径名称?/pre>schemaPatternQ要包括的数据库“Ҏ(gu)”。许多数据库不支持方案,而对另一些数据库而言Q它代表数据库所有者的用户名。一般将它设|ؓ null?/pre>tableNamePatternQ一个掩码,用来描述(zhn)要索的表的名称。如果?zhn)希望索所有表名,则将其设为通配W?%?em>h意,SQL 中的通配W是 % W号Q而不是一?PC 用户?* W号?/em>types[]Q这是描q?zhn)要检索的表的cd?String 数组。数据库中通常包括许多用于内部处理的表Q而对作ؓ用户的?zhn)没什么h(hun)倹{如果它是空|则?zhn)会得到所有这些表。如果?zhn)其设ؓ包含字符?#8220;TABLES”的单元素数组Q?zhn)仅获得对用h用的表格?/pre>例子Q?/strong>
String [] types=new String[1];
types[0]="TABLE";rs=dbmd.getTables(null, null, "%", types);
Java Doc中说该函数返回的表描qC息都包括以下10U信息,TABLE_CAT、TABLE_SCHEM、TABLE_NAME、TABLE_TYPE、REMARKS、TYPE_CAT、TYPE_SCHEM、TYPE_NAME、SELF_REFERENCING_COL_NAME、REF_GENERATIONQ但是在实际试Ӟq回的结果中只有TABLE_CAT、TABLE_SCHEM、TABLE_NAME、TABLE_TYPE、REMARKSq?V顺便要说一声的是,变量types可以取的值有Q?TABLE"?VIEW"?SYSTEM TABLE"?GLOBAL TEMPORARY"?LOCAL TEMPORARY"?ALIAS" ?"SYNONYM"Q通常只取TABLE?
*************************************************************************************************************************************************************************************************
ResultSet
getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern)
仅返回与目录、模式、表和列名称标准匚w的列描述?
通常在得到有x定表Q比如我们这里指定了表名为FoodPriceQ的列的描述信息的结果集QrsQ之后,我们重点兛_的是COLUMN_NAME?strong>DATA_TYPEQ数据类型占用的字节敎ͼ比如整型是4Q?/strong>?strong>TYPE_NAMEQINTEGER、CURRENCY之类的类型名UͼQ?/strong>当然最兛_的肯定是COLUMN_NAME了。下面把l果集中所有可以得到的信息列给出如下:
TABLE_CAT、TABLE_SCHEM、TABLE_NAME、COLUMN_NAME、DATA_TYPE、TYPE_NAME、COLUMN_SIZE、BUFFER_LENGTH、DECIMAL_DIGITS、NUM_PREC_RADIX、NULLABLE、REMARKS、COLUMN_DEF、SQL_DATA_TYPE、SQL_DATETIME_SUB、CHAR_OCTET_LENGTH、ORDINAL_POSITION、IS_NULLABLE、ORDINAL?
例子Q?
rs=dbmd.getColumns(null, null, "FoodPrice", null);
因此我们通常?
while(rs.next()){
?
System.out.print(rs.getString("COLUMN_NAME")+"\t");
}来得到该表中所有的列名U?strong>其实q就是一个从l果集中索的l果
ResultSet
关于某个表的信息或一个查询的l果。?zhn)必须逐行讉K数据行,但是(zhn)可以Q何顺序访问列?
对于数据库中表的描述信息的结果集可以q样得到Qrs=dbmd.getTables(null, null, "%", null);
对于某张表中的列的描qC息的l果集可以这样得刎ͼrs=dbmd.getColumns(null, null, "FoodPrice", null);
对于要从表中索具体的W合要求的结果集Q而不仅仅是一些描qC息了Q就必须使用如下的方法:
Statement st=con.createStatement();
String query="SELECT FoodName FROM FOOD;";//注意字符串中要包?#8220;;”Q?br /> rs=st.executeQuery(query);
ResultSetMetaData
有关 ResultSet 中列的名U和cd的信息?
ResultSetMetaData rsmd;
rsmd = rs.getMetaData();
numCols = rsmd.getColumnCount();
// 打印列名
for (i = 1; i <= numCols; i++)System.out.print(rsmd.getColumnName(i) + " ");
System.out.println();
最后,l出一些零散的知识Q?
Q?Q对于数据库的连接、访问等{操作都需要放在try和catch块中q行Q都有可能抛出SQLException异常Q用该异常c需要import java.sql.*;
Q?Q前面提到的DatabaseMetaDat、ResultSet、ResultSetMetaData均是接口Q而不是类Q在下面的例子中Q通过跟踪调试Q可以发现在E序q行q程中生的都是ZJdbcOdbc驱动的类Q即JdbcOdbcResultSet{类Q把q些c(它们都实C相应的接口)实例化后赋值给ResultSet接口Q如ResultSet rs=dbmd.getColumns(null, null, "FoodPrice", null);因此Q我们们不难推断出对于其他类型的数据库驱动,均是q样一个原理,同时也理解了Z么Java中有许多接口Q而ƈ没有与这些接口对应的实现了它们的c,再一ơ验证了接口是一U标准,一U规范?
l出一个完整的例子Q?
package com.bacoo.www;
import java.sql.*;
public class JdbcOdbcTest {ResultSet rs;
ResultSetMetaData rsmd;
DatabaseMetaData dbmd;
Connection con;
int numCols,i;
public JdbcOdbcTest(){
System.setProperty("jdbc.drivers","sun.jdbc.odbc.JdbcOdbcDriver");
String url="jdbc:odbc:Groceries";
String query="SELECT DISTINCTROW FoodName FROM Food " +
"WHERE (FoodName like 'C%');";
try{
//Class.forName("sun.jdbc.odbc.JdbcOdbcDriver");
con=DriverManager.getConnection(url);
dbmd=con.getMetaData();
System.out.println("Connected to:"+dbmd.getURL());
System.out.println("Driver "+ dbmd.getDriverName());
String [] types=new String[1];
types[0]="TABLE";
rs=dbmd.getTables(null, null, "%", null);
dumpResults("--Tables--");
rs.close();
}catch(Exception e){
System.out.println(e);
}
System.out.println("--Column Names--");
try{
rs=dbmd.getColumns(null, null, "FoodPrice", null);
while(rs.next()){
System.out.print(rs.getString("COLUMN_NAME")+" ");
}
System.out.println();
rs.close();
}catch(Exception e){
System.out.println(e);
}
try{
Statement st=con.createStatement();
rs=st.executeQuery("SELECT FoodName FROM FOOD;");
}catch(Exception e){
System.out.println("query exception");
}
dumpResults("--contents of FoodName column--");
try{
Statement st=con.createStatement();
rs=st.executeQuery(query);
}catch(Exception e){
System.out.println("query exception");
}
dumpResults("--Results of Query--");
}private void dumpResults(String head) {
// q是打印列标头和每列的内容的
// 通用Ҏ(gu)
System.out.println(head);
try {
// 从元数据中获取列?br /> rsmd = rs.getMetaData();
numCols = rsmd.getColumnCount();
// 打印列名
for (i = 1; i <= numCols; i++)
System.out.print(rsmd.getColumnName(i) + "?);
System.out.println();
// 打印列内?br /> while (rs.next()) {
for (i = 1; i <= numCols; i++)
System.out.print(rs.getString(i) + "\t");
System.out.println();
}
} catch (Exception e) {
System.out.println(e.getMessage());
}
}public static void main(String[] args) {
// TODO Auto-generated method stub
new JdbcOdbcTest();
System.out.println(System.getProperty("jdbc.drivers"));
}}
q行的结果是Q?
Connected to:jdbc:odbc:Groceries
Driver JDBC-ODBC Bridge (odbcjt32.dll)
--Tables--
TABLE_CAT、TABLE_SCHEM、TABLE_NAME、TABLE_TYPE、REMARKS?br /> C:\Documents and Settings\Administrator\桌面\db1 null MSysAccessObjects SYSTEM TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null MSysAccessXML SYSTEM TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null MSysACEs SYSTEM TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null MSysObjects SYSTEM TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null MSysQueries SYSTEM TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null MSysRelationships SYSTEM TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null Food TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null FoodPrice TABLE null
C:\Documents and Settings\Administrator\桌面\db1 null Stores TABLE null
--Column Names--
FSKey StoreKey FoodKey Price
--contents of FoodName column--
FoodName?br /> Apples
Oranges
Hamburger
Butter
Milk
Coca Cola
Green beans
--Results of Query--
FoodName?br /> Coca Cola
sun.jdbc.odbc.JdbcOdbcDriver当然使用该例子,必须要先建立一个数据源?/p>
]]>
import java.util.Iterator;
import java.util.Properties;
public class sysEnv {
public static void main(String args[])
{
Properties props=System.getProperties();
Iterator iter=props.keySet().iterator();
while(iter.hasNext())
{
String key=(String)iter.next();
System.out.println(key+" = "+ props.get(key));
}
}
}
其实Q不光是JTabbedPane有这U问题,M一个组仉不能在同一个容器(或面板)中被加蝲两次Q不Z何种方式?/p>
抽象与其实现解耦,使它们都可以独立地变化?/span>
大致意思是_一l实C另一l用他们的对象分离。这里的实现指的是抽象类及其
zcȝ来实现自q对象Q而不是抽象类的派生类Q这些派生类被称为具体类Q。下?/span>
是《Design Patterns Explained》书中的例子。其l构囑֦下: 下面是它的实玎ͼ
abstract class Shape{
protected Drawing myDrawing;
abstract public void draw();
Shape(Drawing drawing){
myDrawing=drawing;
}
protected void drawLine(){
myDrawing.drawLine();
}
protected void drawCircle(){
myDrawing.drawCircle();
}
}
class Rectangle extends Shape{
public Rectangle(Drawing darw){
super(darw);
}
public void draw(){
drawLine();
drawLine();
drawLine();
drawLine();
}
}
class Circle extends Shape{
public Circle(Drawing draw){
super(draw);
}
publicvoid draw(){
myDrawing.drawCircle();
}
}
abstract class Drawing{
abstract public void drawLine();
abstract public void drawCircle();
}
class V1Drawing extends Drawing{
public void drawLine(){
DP1.draw_a_line();
}
public void drawCircle(){
DP1.draw_a_circle();
}
}
class V2Drawing extends Drawing{
public void drawLine(){
DP2.drawLine();
}
public void drawCircle(){
DP2.drawCircle();
}
}
class DP1{
public static void draw_a_line(){
System.out.println("使用DP1的draw_a_line()ȝ");
}
public static void draw_a_circle(){
System.out.println("使用DP1的draw_a_circle()d");
}
}
class DP2{
public static void drawLine(){
System.out.println("使用DP2的drawLine()ȝ");
}
public static void drawCircle(){
System.out.println("使用DP2的drawCircle()d");
}
}
public class BridgeClient {
public static void main(String[] args) {
Drawing draw1=new V1Drawing();
Drawing draw2=new V2Drawing();
Shape shape1=new Rectangle(draw1);
shape1.draw();
Shape shape2=new Circle(draw2);
shape2.draw();
}
}
输出l果如下Q?/span>
使用DP1?/span>draw_a_line()ȝ
使用DP1?/span>draw_a_line()ȝ
使用DP1?/span>draw_a_line()ȝ
使用DP1?/span>draw_a_line()ȝ
使用DP2?/span>drawCircle()d
在这个例子中Shape对象实际上是一?/span>Retangle?/span>Circle对象Q?/span>?/span>Clientq不知道到底是那?/span>Q?/span>因ؓ它们看v来都一栗?/span>Drawing实际上是一?/span>V1Drawing?/span>V2Drawing,?/span>Shape对象q知道到底是哪个Q?/span>因ؓ它们看v来都一栗DP1或DP2使用它的Drawing对象知道是哪一个。Shape是事物的抽象QDrawing是实现或者操作事物方法的抽象。他们两个都可以独立地变化。正如例子中所说那P我们可以输出一个矩形可以用V1Drawing也可以用V2Drawing来完成,输出一个圆形也是一样都有两U方法。Bridge模式遵@了设计模式中两条基本{略Q找出变化ƈ装之和优先使用对象聚集Q而不是类l承?/span>
结QBridge模式是一U抽象与其实现相分离的模式。它主要应用于:当事物是一l变化量Q和对这些事物的操作Ҏ(gu)(实现)也是一l变化量的情况,也就是说它们都是多变的?/span>
单态定?/strong>: 在很多操作中Q比如徏立目?数据库连接都需要这L(fng)单线E操作?
q有, singleton能够被状态化; q样Q多个单态类在一起就可以作ؓ一个状态仓库一样向外提供服务,比如Q你要论坛中的帖子计数器Q每ơ浏览一ơ需要计敎ͼ单态类能否保持住这个计敎ͼq且能synchronize的安全自动加1Q如果你要把q个数字怹保存到数据库Q你可以在不修改单态接口的情况下方便的做到?
另外斚wQSingleton也能够被无状态化。提供工h质的功能, 如何使用? public class Singleton {
private Singleton(){}
//在自己内部定义自׃个实例,是不是很奇怪? private static Singleton instance = new Singleton();
//q里提供了一个供外部讉K本class的静态方法,可以直接讉K W二UŞ?
private static Singleton instance = null; }
使用Singleton.getInstance()可以讉K单态类?
上面W二中Ş式是lazy initializationQ也是说第一ơ调用时初始SingletonQ以后就不用再生成了?
注意到l(f)azy initialization形式中的synchronizedQ这个synchronized很重要,如果没有synchronizedQ那么用getInstance()是有可能得到多个Singleton实例。关于lazy initialization的Singleton有很多涉及double-checked locking (DCL)的讨论,有兴者进一步研I?
一般认为第一UŞ式要更加安全些?br />
使用Singleton注意事项Q?br />
有时在某些情况下Q用Singletonq不能达到Singleton的目的,如有多个Singleton对象同时被不同的c装入器装蝲Q在EJBq样的分布式pȝ中用也要注意这U情况,因ؓEJB是跨服务器,跨JVM的?
我们以SUN公司的宠物店源码(Pet Store 1.3.1)的ServiceLocatorZE微分析一下: Singleton模式看v来简单,使用Ҏ(gu)也很方便Q但是真正用好,是非怸Ҏ(gu)Q需要对Java的类 U程 内存{概忉|相当的了解?
MQ如果你的应用基于容器,那么Singleton模式用或者不用,可以使用相关替代技术?
q一步深入可参考:
Double-checked locking and the Singleton pattern
When is a singleton not a singleton?
设计模式如何在具体项目中应用?a target="_blank">《Java实用pȝ开发指南?/font>
Singleton模式的要点:
Singleton模式的实现方?br />
1、饿汉式singleton public static EagerSingleton getInstance() 2、懒汉式singleton 3、登记式singleton
饿汉式、懒汉式都不能被l承
Singleton模式主要作用是保证在Java应用E序中,一个类Class只有一个实例存在?
Singleton模式׃ؓ我们提供了这样实现的可能。用Singleton的好处还在于可以节省内存Q因为它限制了实例的个数Q有利于Java垃圾回收Qgarbage collectionQ?br />
我们常常看到工厂模式中类装入?class loader)中也用Singleton模式实现?因ؓ被装入的cd际也属于资源?br />
一般Singleton模式通常有几UŞ?
//注意q是private 只供内部调用
public static Singleton getInstance() {
return instance;
}
}
public class Singleton {
public static synchronized Singleton getInstance() {
//q个Ҏ(gu)比上面有所改进Q不用每ơ都q行生成对象Q只是第一ơ
//使用时生成实例,提高了效率!
if (instance==null)
instanceQnew Singleton();
return instance; }
在Pet Store中ServiceLocator有两U,一个是EJB目录下;一个是WEB目录下,我们查这两个ServiceLocator会发现内容差不多Q都是提供EJB的查询定位服务,可是Z么要分开呢?仔细研究对这两种ServiceLocator才发现区别:在WEB中的ServiceLocator的采取Singleton模式QServiceLocator属于资源定位Q理所当然应该使用Singleton模式。但是在EJB中,Singleton模式已经失去作用Q所以ServiceLocator才分成两U,一U面向WEB服务的,一U是面向EJB服务的?
1、某个类只能有一个实?br />
2、必自行创个实?br />
3、必d整个pȝ提供q个实例
public class EagerSingleton
{
private static final EagerSingleton m_instance = new Eagersingleton();
private Eagersingleton(){}
{
return m_instance;
}
}
public class LazySingleton
{
private static LazySingleton m_instance = null;
private LazySingleton(){};
synchronized public static LazySingleton getInstance()
{
if( m_instance == null )
{
m_instance = new LazySingleton();
}
return m_instance;
}
}
import java.util.HashMap;
public class RegSingleton
{
static private HashMap m_registry = new HashMap();
static
{
RegSingleton x = new regSingleton();
m_registry.put(x.getClass().getName(), x);
}
protect RegSingleton(){}
static public RegSingleton getInstance(String name)
{
if(name == null )
{
name = "RegSingleton";
}
if(m_registry.get(name ) == null )
{
m_registry.put(name, Class.forName(name).newInstance();
}
catch(Exception e)
{
System.out.println("Error happened.");
}
return (RegSingleton)(m_registry.get(name));
}
}
三种Singleton模式的比?/strong>
饿汉?c被加蝲时就被实例化?br />
懒汉?cd载时Q不被实例化Q在W一ơ引用时实例化?
而登记式可以被ѝ?/p>
下面的内容只是API的规?没有什么太高深的意?但我之所以最先把它列在这?是因些规范在事实中ƈ不是真正能保证得到实现?
1。自反性:对于M引用cd, o.equals(o) == true成立?
2。对U性:如果 o.equals(o1) == true 成立,那么o1.equals(o)==true也一定要成立?
3。传递性:如果 o.equals(o1) == true 成立?nbsp; o1.equals(o2) == true 成立,那么o.equals(o2) == true 也成立?
4。一致性:如果W一ơ调用o.equals(o1) == true成立再o和o1没有改变的情况下以后的Q何次调用都成立?
5。o.equals(null) == true M旉都不成立?
以上几条规则q不是最完整的表q?详细的请参见API文?br />
但是在hashCode()函数的协定中Q要?#8220;如果Ҏ(gu) equals(Object) Ҏ(gu)Q两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode Ҏ(gu)都必ȝ成相同的整数l果?#8221;Q因此我个h认ؓequalsҎ(gu)q应该加上这W?条规定:
6。如?o.equals(o1) == true 成立,那么必须有o.hashCode==o1.hashCode()?
对于Objectc?它提供了一个最最严密的实?那就是只有是同一对象?equalsҎ(gu)才返回true,也就是h们常说的引用比较而不是值比较。这个实C密得已经没有什么实际的意义,所以在具体子类(相对于Object来说)?如果我们要进行对象的值比?必d现自qequalsҎ(gu)?
先来看一下以下这D引自于JDK中的E序:
Q说明:attribute在FieldPosition中有q样的定义:private Format.Field attribute;Q?br />
public boolean equals(Object obj)
{
if (obj == null) return false;
if (!(obj instanceof FieldPosition))
return false;
FieldPosition other = (FieldPosition) obj;
if (attribute == null) {
if (other.attribute != null) {
return false;
}
}
else if (!attribute.equals(other.attribute)) {
return false;
}
return (beginIndex == other.beginIndex
&& endIndex == other.endIndex
&& field == other.field);
}
q是JDK中java.text.FieldPosition的标准实?g没有什么可说的. 我相信大多数或绝大多数程序员认ؓ,q是正确的合法的equals实现.毕竟它是JDK的API实现? q是让我们以事实来说话吧:
package debug;
import java.text.*;
public class Test {
public static void main(String[] args) {
FieldPosition fp = new FieldPosition(10);
FieldPosition fp1 = new MyTest(10);
System.out.println(fp.equals(fp1));
System.out.println(fp1.equals(fp));
}
}
class MyTest extends FieldPosition{
int x = 10;
public MyTest(int x){
super(x);
this.x = x;
}
public boolean equals(Object o){
if(o==null) return false;
if(!(o instanceof MyTest )) return false;
return ((MyTest)o).x == this.x;
}
}
q行一下看看会打印Z?
System.out.println(fp.equals(fp1));打印true
System.out.println(fp1.equals(fp));打印flase
两个对象,出现了不对称的equals法.问题出在哪里(脑筋急{弯:当然出在JDK实现的固有BUGQ看来JDK中的东西未必完全都是最最最正确的,我们要敢于怀疑它Q??
我相信有太多的程序员在实现equalsҎ(gu)旉用过instanceofq行W来q行短\优化的,实事求是地说很长一D|间我也这么用q。太多的教程Q文都l了我们q样的误对{而有些稍有了解的E序员可能知道这L(fng)优化可能有些不对但找不出问题的关键。另外一U极端是知道q个技术缺L(fng)骨灰U专家就提议不要q样应用?
我们知道Q?通常"要对两个对象q行比较Q那么它?应该"是同一cd。所以首先利用nstanceofq行W进行短路优化(“短\”《Short-circuiting》,而短路的最大好处就是能够优化性能。所谓的短\是当第一个被q算的表辑ּ的结果已l能够决定运的最l结果时Q就不会再去计算其他的表辑ּQ因此可以避免掉额外且不必要的运操作,其是当所略过的是复杂或含有过E调用的表达式时Q短路的性能提升q度更ؓ明显。比如我们在if中同时用&&判断多个条g的时候,遇到W一个false的时候就不会再计后面的表达式是否ؓtrue了)Q如果被比较的对象不和当前对象是同一cd则不用比较返回false,但事实上Q?子类是父cȝ一个实?Q所以如?子类 instanceof 父类Q始l返回true,q时肯定不会发生短\优化Q下面的比较有可能出现多U情况,一U是父类不能造型成子c而抛出异常(比如子类.equals(父类)后,在equals内部会进行试囑ְ父类向下造型成子cȝ操作Q,另一U是父类的private 成员没有被子cȝ承而不能进行比较,q有是形成上面q种不对U比较。可能会出现太多的情c?
那么Q是不是׃能用 instanceofq行W来q行优化Q答案是否定的,JDK中仍然有很多实现是正的Q如果一个class是final的,明知它不可能有子c,Z么不用instanceof来优化呢Q(可见对于不涉及子cȝ问题Ӟ用instanceofq行短\优化q是很可行的Q?
Zl护SUN的开发小l的声誉Q我不说明哪个类中,但有一个小l成员在用这个方法优化时在后加加上了加上了这L(fng)注释Q?
if (this == obj) // quick checkQ也是短\优化Q?br />
return true;
if (!(obj instanceof XXXXClass)) // (1) same object?
return false; 可能是有些疑问,但不知道如何做(不知道ؓ什么没有打?sh)话l我......Q?
那么对于非finalc,如何q行cd的quick check呢?
if(obj.getClass() != XXXClass.class) return false;
用被比较对象的class对象和当前对象的class比较Q看h是没有问题,但是Q如果这个类的子cL有重新实现equalsҎ(gu)Q那么当子类.equals(子类)比较Ӟ也就是要使用“if(obj.getClass() != XXXClass.class) return false;”来进行比较了Q显然obj.getClass()《这个是字类?肯定不等于XXXCalss.class《这个是父类?从这里就直接q回得到false的结果了Q因此子cM定义的equals实际上根本没发挥出应有的效力来,所以if(obj.getClass() != this.getClass()) return false;才是正确的比较?呵呵Q看C没?我们首先否定了instanceofQ接下来又否定了“obj.getClass() != XXXClass.class”q种错误的比较做法,最后才l出了正的比较Ҏ(gu)?br />
另外一个quick check是if(this==obj) return true;而且q个短\优化应该攑֜“obj.getClass() != XXXClass.class”优化的前面?
是否equalsҎ(gu)一定比较的两个对象׃定是要同一cdQ上面我用了"通常"Q这也是l大多数E序员的愿望Q但是有些特D的情况Q我们可以进行不同类型的比较Q这q不q反规范。但q种Ҏ(gu)情况是非常罕见的Q一个不恰当的例子是QIntegercȝequals可以和Sort做比较,比较它们的value是不是同一数学倹{(事实上JDK的API中ƈ没有q样做,所以我才说是不恰当的例子)。在完成quick check以后Q我们就要真正实C认ؓ?#8220;相等”。对于如果实现对象相{,没有太高的要求,比如你自己实现的“?#8221;c,你可以认为只要name相同卌为它们是相等的,其它的sex,ago都可以不考虑。这是不完全实现Q但是如果是完全实现Q即要求所有的属性都是相同的Q那么如何实现equalsҎ(gu)Q?
class Human{
private String name;
private int ago;
private String sex;
....................
public boolean equals(Object obj){
quick check.......
Human other = (Human)ojb;
return this.name.equals(other.name)
&& this.ago == ohter.ago
&& this.sex.equals(other.sex);
}
}
q是一个完全实玎ͼ但是Q有时equals实现是在父类中实现的Q而且要求被子cȝ承后Q父cȝequals能正的工作Q这时父cM的equalsq不事实知道子类到底扩展了哪些属性,所以用上面的方法无法equals得到完全实现?
一个好的方法是利用反射来对equalsq行完全实现Q?l出一个完整的在父cM定义的equalsҎ(gu)Q只是比较字D)的实玎ͼ
public boolean equals(Object obj){
if(obj == this)
return true;
if(obj.getClass() != this.getClass())
return false;
Class c = this.getClass();
Filed[] fds = c.getDeclaredFields();
for(Filed f:fds){
if(!f.get(this).equals(f.get(obj)))
return false;
}
return true;
}
Z说明的方便,上明的实现省略了异常Q这L(fng)实现攑֜父类中,可以保证你的子类的equals可以按你的愿望正地工作。当然这里只是考虑了基于字D늛{的比较Q如何还涉及到基于方法等其他斚w的相{比较,则应该扩展上面的代码Q反出更多的东西(比如Ҏ(gu)Q来加以比较判断?
关于equalsҎ(gu)的最后一Ҏ(gu)Q如果你要是自己重写Q正说应该是盖)了equalsҎ(gu)Q那同时׃定要重写hashCode()Q否?............
我们q是看一下这个例子:
public final class PhoneNumber {
private final int areaCode;
private final int exchange;
private final int extension;
public PhoneNumber(int areaCode, int exchange, int extension) {
rangeCheck(areaCode, 999, "area code");
rangeCheck(exchange, 99999999, "exchange");
rangeCheck(extension, 9999, "extension");
this.areaCode = areaCode;
this.exchange = exchange;
this.extension = extension;
}
private static void rangeCheck(int arg, int max, String name) {
if(arg < 0 || arg > max)
throw new IllegalArgumentException(name + ": " + arg);
}
public boolean equals(Object o) {
if(o == this)
return true;
if(!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.extension == extension && pn.exchange == exchange && pn.areaCode == areaCode;
}
}
注意q个cLfinal的,所以这个equals实现没有什么问题?
我们来测试一?
public static void main(String[] args) {
Map hm = new HashMap();
PhoneNumber pn = new PhoneNumber(123, 38942, 230);
hm.put(pn, "I love you");
PhoneNumber pn1 = new PhoneNumber(123, 38942, 230);
System.out.println(pn);
System.out.println("pn.equals(pn1) is " + pn.equals(pn1));
System.out.println(hm.get(pn1));
System.out.println(hm.get(pn));
}
既然pn.equals(pn1),那么我put(pn,"I love you");后,get(pn1)q什么是null呢?
{案是因为pn和pn1的hashCode不一P而hashMap是以hashCodeZ键的?
所以根据规范要求(在文章最开始部分提到的标准equalsҎ(gu)需要满的6条性质Q,如果两个对象q行equals比较时如果返回true,那么它们的hashcode要求q回相等的倹{?
此外Q在写hashCode函数Ӟ需要注意:
随便你怎么写,只要保证A.equals(B)一定可以推出A.hashCode()==B.hashCode()pQ当Ӟ应该量使得A.equals(B)==false的时候,使得A.hashCode()量不等于B.hashCode()Q绝对不会相{是不可能的Q但是要量降低概率?
比如Q?br />
public int hashCode() {
int result;
result = getName().hashCode();
result = 29 * result + getBirthday().hashCode();
return result;
}
其时是需要你Ҏ(gu)自己的类l出Ҏ(gu)的一U算法,能够满通过该算法得到的q个整数|也就是hashCodeQ能够区别该cȝ各个实例?/p>
1、FACTORY—追MM不了请吃饭了,麦当劳的鸡翅和肯德基的鸡都是MM爱吃的东西,虽然口味有所不同Q但不管你带MM去麦当劳或肯德基Q只向服务员说“来四个鸡?#8221;p了。麦当劳和肯德基是生鸡翅的Factory
工厂模式Q客L(fng)和工厂类分开。消费者Q何时候需要某U品,只需向工厂请求即可。消费者无M改就可以接纳C品。缺Ҏ(gu)当品修Ҏ(gu)Q工厂类也要做相应的修改。如Q如何创建及如何向客L(fng)提供?
2、BUILDER—MM最爱听的就?#8220;我爱?#8221;q句话了Q见C同地方的MM,要能够用她们的方a跟她说这句话哦,我有一个多U语a译机,上面每种语言都有一个按键,见到MM我只要按对应的键Q它?yu)p够用相应的语a说出“我爱?#8221;q句话了Q国外的MM也可以轻松搞掂,q就是我?#8220;我爱?#8221;builder。(q一定比军在伊拉克用的译机好卖)
建造模式:品的内部表象和品的生成q程分割开来,从而一个徏造过E生成具有不同的内部表象的品对象。徏造模式得品内部表象可以独立的变化Q客户不必知道品内部组成的l节。徏造模式可以强制实行一U分步骤q行的徏造过E?
3、FACTORY METHOD—请MM去麦当劳吃汉堡,不同的MM有不同的口味Q要每个都记住是一件烦人的事情Q我一般采用Factory Method模式Q带着MM到服务员那儿Q说“要一个汉?#8221;Q具体要什么样的汉堡呢Q让MM直接跟服务员说就行了?
工厂Ҏ(gu)模式Q核心工厂类不再负责所有品的创徏Q而是具体创建的工作交给子类dQ成Z个抽象工厂角Ԍ仅负责给出具体工厂类必须实现的接口,而不接触哪一个品类应当被实例化q种l节?
4、PROTOTYPE—跟MM用QQ聊天Q一定要说些深情的话语了Q我搜集了好多肉ȝ情话Q需要时只要copy出来攑ֈQQ里面p了,q就是我的情话prototype了。(100块钱一份,你要不要Q?
原始模型模式Q通过l出一个原型对象来指明所要创建的对象的类型,然后用复制这个原型对象的Ҏ(gu)创徏出更多同cd的对象。原始模型模式允许动态的增加或减品类Q品类不需要非得有M事先定的等U结构,原始模型模式适用于Q何的{l构。缺Ҏ(gu)每一个类都必配备一个克隆方法?
5、SINGLETON—俺?个漂亮的老婆Q她们的老公都是我,我就是我们家里的老公SigletonQ她们只要说?#8220;老公”Q都是指的同一个hQ那是?刚才做了个梦啦,哪有q么好的?
单例模式Q单例模式确保某一个类只有一个实例,而且自行实例化ƈ向整个系l提供这个实例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用?
l构型模?
6、ADAPTER—在朋友聚会上碰C一个美女SarahQ从香港来的Q可我不会说_语Q她不会说普通话Q只好求助于我的朋友kent了,他作为我和Sarah之间的AdapterQ让我和Sarah可以怺交谈?也不知道他会不会耍我)
适配器(变压器)模式Q把一个类的接口变换成客户端所期待的另一U接口,从而原本因接口原因不匚w而无法一起工作的两个c能够一起工作。适配cd以根据参数返q一个合适的实例l客L(fng)?
7、BRIDGE—早上碰到MMQ要说早上好Q晚上碰到MMQ要说晚上好Q碰到MMI了件新服Q要说你的衣服好漂亮哦,到MM新做的发型,要说你的头发好漂亮哦。不要问?#8220;早上到MM新做了个发型怎么?#8221;q种问题Q自qBRIDGEl合一下不p?
桥梁模式Q将抽象化与实现化脱耦,使得二者可以独立的变化Q也是说将他们之间的强兌变成弱关联,也就是指在一个Y件系l的抽象化和实现化之间用组?聚合关系而不是承关p,从而两者可以独立的变化?
8、COMPOSITE—Mary今天q生日?#8220;我过生日Q你要送我一件礼物?#8221;“嗯,好吧Q去商店Q你自己挑?#8221;“qgT恤挺漂亮Q买Q这条裙子好看,乎ͼq个包也不错Q买?#8221;“喂,C三g了呀Q我只答应送一件礼物的哦?#8221;“什么呀QT恤加裙子加包包,正好配成一套呀Q小姐,ȝ你包h?#8221;“……”QMM都会用Composite模式了,你会了没有?
合成模式Q合成模式将对象l织到树(wi)l构中,可以用来描述整体与部分的关系。合成模式就是一个处理对象的?wi)结构的模式。合成模式把部分与整体的关系用树(wi)l构表示出来。合成模式得客L(fng)把一个个单独的成分对象和׃们复合而成的合成对象同{看待?
9、DECORATOR—Maryq完轮到Sarlyq生日,q是不要叫她自己挑了Q不然这个月伙食费肯定玩完,拿出我去q在华山上照的照片Q在背面写上“最好的的礼物,是׃的Fita”Q再到街上礼品店C个像框(卖礼品的MM也很漂亮哦)Q再N壁搞术设计的Mike设计了一个漂亮的盒子装v?#8230;…Q我们都是DecoratorQ最l都在修饰我q个人呀Q怎么P看懂了吗Q?
装饰模式Q装饰模式以对客L(fng)透明的方式扩展对象的功能Q是l承关系的一个替代方案,提供比承更多的灉|性。动态给一个对象增加功能,q些功能可以再动态的撤消。增加由一些基本功能的排列l合而生的非常大量的功能?
10、FACADE—我有一个专业的Nikon相机Q我喜Ƣ自己手动调光圈、快门,q样照出来的照片才专业,但MM可不懂这些,教了半天也不会。幸好相机有Facade设计模式Q把相机调整到自动档Q只要对准目标按快门p了,一切由相机自动调整Q这样MM也可以用q个相机l我拍张照片了?
门面模式Q外部与一个子pȝ的通信必须通过一个统一的门面对象进行。门面模式提供一个高层次的接口,使得子系l更易于使用。每一个子pȝ只有一个门面类Q而且此门面类只有一个实例,也就是说它是一个单例模式。但整个pȝ可以有多个门面类?
11、FLYWEIGHT—每天跟MM发短信,手指都篏MQ最q买了个新手机,可以把一些常用的句子存在手机里,要用的时候,直接拿出来,在前面加上MM的名字就可以发送了Q再不用一个字一个字敲了。共享的句子是FlyweightQMM的名字就是提取出来的外部特征Q根据上下文情况使用?
享元模式QFLYWEIGHT在拳?yn)L赛中指最轻量U。n元模式以׃n的方式高效的支持大量的细_度对象。n元模式能做到׃n的关键是区分内蕴状态和外蕴状态。内蕴状态存储在享元内部Q不会随环境的改变而有所不同。外蕴状态是随环境的改变而改变的。外蕴状态不能媄响内蕴状态,它们是相互独立的。将可以׃n的状态和不可以共享的状态从常规cM区分开来,不可以׃n的状态从c里剔除出去。客L(fng)不可以直接创׃n的对象,而应当用一个工厂对象负责创׃n的对象。n元模式大q度的降低内存中对象的数量?
12、PROXY—跟MM在网上聊天,一开头L“hi,你好”,“你从哪儿来呀Q?#8221;“你多大了Q?#8221;“w高多少呀Q?#8221;q些话,真烦人,写个E序做ؓ我的Proxy吧,凡是接收到这些话都设|好了自动的回答Q接收到其他的话时再通知我回{,怎么P酷吧?
代理模式Q代理模式给某一个对象提供一个代理对象,q由代理对象控制Ҏ(gu)对象的引用。代理就是一个h或一个机构代表另一个h或者一个机构采取行动。某些情况下Q客户不x者不能够直接引用一个对象,代理对象可以在客户和目标对象直接起到中介的作用。客L(fng)分L不出代理主题对象与真实主题对象。代理模式可以ƈ不知道真正的被代理对象,而仅仅持有一个被代理对象的接口,q时候代理对象不能够创徏被代理对象,被代理对象必Lpȝ的其他角色代为创建ƈ传入?
行ؓ模式
13、CHAIN OF RESPONSIBLEITY—晚上去上英语课Qؓ了好开溜坐C最后一排,哇,前面坐了好几个漂亮的MM哎,扑ּU条Q写?#8220;Hi,可以做我的女朋友吗?如果不愿意请向前?#8221;Q纸条就一个接一个的传上MQ糟p,传到W一排的MM把纸条传l老师了,听说是个老处奛_Q快?
责Q链模式:在责任链模式中,很多对象由每一个对象对其下家的引用而接
h形成一条链。请求在q个链上传递,直到链上的某一个对象决定处理此h。客户ƈ不知道链上的哪一个对象最l处理这个请求,pȝ可以在不影响客户端的情况下动态的重新l织铑֒分配责Q。处理者有两个选择Q承担责L者把责Q推给下家。一个请求可以最l不被Q何接收端对象所接受?
14、COMMAND—俺有一个MM安得特别严,没法见面Q只好借助于她弟弟在我们俩之间传送信息,她对我有什么指C,写一张纸条让她弟弟带l我。这不,她弟弟又传送过来一个COMMANDQؓ了感谢他Q我请他吃了杂酱面Q哪知道他说Q?#8220;我同时给我姐姐三个男朋友送COMMANDQ就C最气Q才h吃面?#8221;Q?-(
命o模式Q命令模式把一个请求或者操作封装到一个对象中。命令模式把发出命o的责d执行命o的责d割开Q委z不同的对象。命令模式允许请求的一方和发送的一方独立开来,使得h的一方不必知道接收请求的一方的接口Q更不必知道h是怎么被接Ӟ以及操作是否执行Q何时被执行以及是怎么被执行的。系l支持命令的撤消?
15、INTERPRETER—俺有一个《MM真经》,上面有各UMM的攻略,比如说去吃西的步骤、去看电(sh)qҎ(gu){等Q跟MMU会Ӟ只要做一个InterpreterQ照着上面的脚本执行就可以了?
解释器模式:l定一个语a后,解释器模式可以定义出其文法的一U表C,q同时提供一个解释器。客L(fng)可以使用q个解释器来解释q个语言中的句子。解释器模式描q怎样在有了一个简单的文法后,使用模式设计解释q些语句。在解释器模式里面提到的语言是指M解释器对象能够解释的Ml合。在解释器模式中需要定义一个代表文法的命ocȝ{l构Q也是一pd的组合规则。每一个命令对象都有一个解释方法,代表对命令对象的解释。命令对象的{l构中的对象的Q何排列组合都是一个语a?
16、ITERATOR—我׃了MaryQ不一切的向她求婚?
MaryQ?#8220;惌我跟你结婚,得答应我的条?#8221;
我:“什么条件我都答应,你说?#8221;
MaryQ?#8220;我看上了那个一克拉的钻?#8221;
我:“我买Q我乎ͼq有吗?”
MaryQ?#8220;我看上了湖边的那栋别?#8221;
我:“我买Q我乎ͼq有吗?”
MaryQ?#8220;你的弟弟必要?0cm?#8221;
我脑袋嗡的一壎ͼ坐在椅子上,一咬牙Q?#8220;我剪Q我剪,q有吗?”
……
q代子模式:q代子模式可以顺序访问一个聚集中的元素而不必暴露聚集的内部表象。多个对象聚在一起Ş成的MUC集,聚集对象是能够包容一l对象的容器对象。P代子模式P代逻辑装C个独立的子对象中Q从而与聚集本n隔开。P代子模式化了聚集的界面。每一个聚集对象都可以有一个或一个以上的q代子对象,每一个P代子的P代状态可以是彼此独立的。P代算法可以独立于聚集角色变化?
17、MEDIATOR—四个MM打麻,怺之间谁应该给谁多钱不清楚了,q怺当时我在旁边Q按照各自的{码数算钱,赚了q从我q里拿,赔了q也付l我Q一切就O(jin)K啦,俺得C四个MM的电(sh)话?
调停者模式:调停者模式包装了一pd对象怺作用的方式,使得q些对象不必怺明显作用。从而他们可以松散偶合。当某些对象之间的作用发生改变时Q不会立卛_响其他的一些对象之间的作用。保证这些作用可以彼此独立的变化。调停者模式将多对多的怺作用转化Z对多的相互作用。调停者模式将对象的行为和协作抽象化,把对象在尺度的行ؓ上与其他对象的相互作用分开处理?
18、MEMENTO—同时跟几个MM聊天Ӟ一定要记清楚刚才跟MM说了些什么话Q不然MM发现了会不高兴的哦,q怺我有个备忘录Q刚才与哪个MM说了什么话我都拯一份放到备忘录里面保存Q这样可以随时察看以前的记录啦?
备忘录模式:备忘录对象是一个用来存储另外一个对象内部状态的快照的对象。备忘录模式的用意是在不破坏装的条件下Q将一个对象的状态捉住,q外部化Q存储v来,从而可以在来合适的时候把q个对象q原到存储v来的状态?
19、OBSERVER—想知道׃公司最新MM情报吗?加入公司的MM情报邮gl就行了Qtom负责搜集情报Q他发现的新情报不用一个一个通知我们Q直接发布给邮gl,我们作ؓ订阅者(观察者)可以及时收到情报啦
观察者模式:观察者模式定义了一U一队多的依赖关p,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化Ӟ会通知所有观察者对象,使他们能够自动更新自己?
20、STATE—跟MM交往Ӟ一定要注意她的状态哦Q在不同的状态时她的行ؓ会有不同Q比如你U她今天晚上ȝ?sh)媄Q对你没兴趣的MM׃?#8220;有事情啦”Q对你不讨厌但还没喜Ƣ上的MM׃?#8220;好啊Q不q可以带上我同事么?”Q已l喜Ƣ上你的MM׃?#8220;几点钟?看完?sh)媄再去泡吧怎么P”Q当然你看电(sh)pE中表现良好的话Q也可以把MM的状态从不讨厌不喜欢变成喜欢哦?
状态模式:状态模式允怸个对象在其内部状态改变的时候改变行为。这个对象看上去象是改变了它的类一栗状态模式把所研究的对象的行ؓ包装在不同的状态对象里Q每一个状态对象都属于一个抽象状态类的一个子cR状态模式的意图是让一个对象在其内部状态改变的时候,其行Z随之改变。状态模式需要对每一个系l可能取得的状态创立一个状态类的子cR当pȝ的状态变化时Q系l便改变所选的子类?
21、STRATEGY—跟不同cd的MMU会Q要用不同的{略Q有的请?sh)媄比较好,有的则去吃小吃效果不错,有的LvҎ(gu)漫最合适,单目的都是ؓ了得到MM的芳心,我的qMM锦囊中有好多Strategy哦?
{略模式Q策略模式针对一l算法,每一个算法封装到h共同接口的独立的cMQ从而得它们可以相互替换。策略模式得算法可以在不媄响到客户端的情况下发生变化。策略模式把行ؓ和环境分开。环境类负责l持和查询行为类Q各U算法在具体的策略类中提供。由于算法和环境独立开来,法的增减,修改都不会媄响到环境和客L(fng)?
22、TEMPLATE METHOD——看q《如何说服女生上床》这部经典文章吗Q女生从认识C床的不变的步骤分为y遇、打破僵局、展开q求、接吅R前戏、动手、爱抚、进d大步?Template method)Q但每个步骤针对不同的情况,都有不一L(fng)做法Q这p看你随机应变?具体实现)Q?
模板Ҏ(gu)模式Q模板方法模式准备一个抽象类Q将部分逻辑以具体方法以及具体构造子的Ş式实玎ͼ然后声明一些抽象方法来q子类实现剩余的逻辑。不同的子类可以以不同的方式实现q些抽象Ҏ(gu)Q从而对剩余的逻辑有不同的实现。先制定一个顶U逻辑框架Q而将逻辑的细节留l具体的子类d现?
23、VISITOR—情CQ要l每个MM送一束鲜花和一张卡片,可是每个MM送的花都要针对她个h的特点,每张卡片也要Ҏ(gu)个h的特Ҏ(gu)挑,我一个h哪搞得清楚,q是找花店老板和礼品店老板做一下VisitorQ让花店老板Ҏ(gu)MM的特炚w一束花Q让C品店老板也根据每个h特点选一张卡Q这样就L多了Q?
讉K者模式:讉K者模式的目的是封装一些施加于某种数据l构元素之上的操作。一旦这些操作需要修改的话,接受q个操作的数据结构可以保持不变。访问者模式适用于数据结构相Ҏ(gu)定的pȝQ它把数据结构和作用于结构上的操作之间的耦合解脱开Q得操作集合可以相对自q演化。访问者模式得增加新的操作变的很Ҏ(gu)Q就是增加一个新的访问者类。访问者模式将有关的行为集中到一个访问者对象中Q而不是分散到一个个的节点类中。当使用讉K者模式时Q要尽可能多的对象览逻辑攑֜讉K者类中,而不是放到它的子cM。访问者模式可以跨q几个类的等U结构访问属于不同的{l构的成员类?nbsp;
虽然自认己对设计模式已经很了解了,但是从来没有pȝ的看q设计模式相关的?最q在公司发现一?lt;java与模?gt;,正好pȝ的看一?下面是这几天记的W记.(q不是系l的讲解书中的内?
一 lD:
1、不要用接口定义常?br />
2、自己少用标志接?br />
3、不要承具体类
4、类层次的中间节点应该是接口或者抽象类Q叶子是具体c?br />
5、子cd当扩展父cȝ责QQ而不是覆写父cȝ责Q
6、面向接口编E?br />
7、不要滥用承,l合优先于?
java中设计不当的c:calendar:作ؓ接口Q含有与具体的历法(|马历法Q相关的帔RQ不能扩展到中国的阴历历法(不符合开闭原则)
properiesc:滥用l承Q承至hashtableQ应当用聚?
8、笛比特法则Q只与自q直接朋友通信Q不与陌生h通信Q?Q狭义笛比特法则Q只与朋友通讯Q通过自己的朋友传递间接的调用Q?Q结合依赖倒{原则修改Q不必通过朋友传递间接的调用Q通过陌生人的抽象接口调用陌生人的行ؓQ依旧不能与具体的陌生h发生通信Q?br />
9、尽量降低类中成员的讉K权限Q不要设计退化类Q类似c中structQ?br />
java中的point2D以及Dinmension2DcLq种设计~陷Q不q这U情况问题不大)
10、如果多个具体的产品cL有共同的商业逻辑Q就可以把它们抽象到一个接口中Q如果有共同的商业逻辑Q就把共同的部分抽象到抽象类中,共同的部分尽量向cȝ承层ơ的上层UdQ以辑ֈ复用的目?br />
?nbsp; 工厂模式
1、简单工厂模式:参与角色Q工?抽象产品c?具体产品c?
~点Q添加新产品的时候,虽然产品相关代码W合开闭原则,但对工厂cLwƈ不符合,需要修改其中的产生产品Ҏ(gu)或者添加新的生方法(工厂里实现的不同造成的修改不同)来支持新的品类
退化方式:省略掉工厂角Ԍ抽象产品cLd体品类的工厂角Ԍ提供静态的getInstanceҎ(gu)Q比如javacd中的DateFormatc,Q本样很不符合开闭原则,父类中出C具体子类相关的代码,不方便扩展,dC品的时候,修改的时候缺点与原简单工厂的工厂角色cMQ?
2、工厂方法模式:参与角色Q抽象工厂类/具体工厂c?抽象产品c?具体产品c?br /> 消除了简单工厂的~点
3、抽象工厂模式:单工厂模式与工厂Ҏ(gu)模式的结?
4、单例模式:饿汉和懒汉两U,前者将本n对象作ؓ静态私有属性事先生成,后者推q到调用的时候,后者需要考虑多线E的时候,前面需要加U程安全关键字(注意Q,java中还是前者ؓ优?br />
不要滥用单例Q只有系l要求只有一个类的实例的时候才调用
有的单例可能有状态属性,q就为多例模式提供了可能
含有U有属性的cM成单例的时候尤其要注意Q一是私有属性的U程安全Q确实需要的时候可以加U程安全关键字,比如pȝ中的logc,二是认q些属性是不是可以所有线E共享的Q类似普通类的static
?nbsp; 各种具体模式Q?Q?br />
1、徏造模式:参与角色4个:指导者、抽象徏造对象、具体徏造对象、?br />
一个复杂的产品有很多的雉Ӟ可以用具体的建造对象来一一构?br />
2、原始模式:深拷贝、浅拯
3、适配器模式:adapteec适配成目标接?br />
4、合成模式:参与角色Qcomposite接口、树(wi)枝节点类、树(wi)叶节点类
分成透明式和安全式两U,各有优缺?br />
(1)前者将理子对象的Ҏ(gu)攑ֈ接口中,q样?wi)型l构中的所有对象都是透明的,都可以统一调用Q但是叶节点q没有管理子对象的能力,因此透明但不安全
(2)后者将理子对象的Ҏ(gu)下放到树(wi)枝节点类中,q样安全但不透明
5、装饰模式:l承已有cȝ接口Q提供和已有cȝ同的Ҏ(gu)Qƈ对已有类的功能提供扩展(通过l合已有对象Q调用已有对象方法的时候加入新的代码)
(1)透明的装饰模式(Ua的装饰模式)Q装饰类、被装饰cȝ承于同一接口Q而且装饰cd实现接口的方法,不提供额外方法的实现Q调用该cȝ时候用接口声明调用(实例化当然还是自q构造函敎ͼQ即该类的所有方法都是透明?br />
(2)半透明的装饰模式(退化的装饰模式Q:装饰cR被装饰cȝ承于同一接口Q装饰类不仅实现接口的方法,q提供额外方法的实现Q这栯调用它独特的Ҏ(gu)的时候就必须使用它本w来调用Q退化到一半装饰模式、一半适配器模式?/p>
用法Qjavac <选项> <源文?gt;
可能的选项包括Q?
-g 生成所有调试信?
-g:none 生成无调试信?
-g:{lines,vars,source} 生成只有部分调试信息
-O 优化Q可能妨调试或者增大类文g
-nowarn 生成无警?
-verbose 输出关于~译器正在做的信?
-deprecation 输出使用了不鼓励使用的API的源E序位置
-classpath <路径> 指定用户cL件的位置
-sourcepath <路径> 指定输入源文件的位置
-bootclasspath <路径> 覆盖自DcL件的位置
-extdirs <目录(多个)> 覆盖安装的扩展类的位|?
-d <目录> 指定输出cL件的位置
-encoding <~码> 指定源文件中所用的字符集编?
-target <版本> 生成指定虚拟机版本的cL?
-help Print a synopsis of standard options
appletviewer.exe
用法Qappletviewer <options> url
其中Q?lt;options> 包括Q?
-debug ?Java 调试器中启动 applet 程序查看器
-encoding <encoding> 指定?HTML 文g使用的字W编?
-J<runtime flag> ?Java 解释器传递参?
-J 选项不是标准选项Q如有更改,不另行通知?
jar.exe
用法Qjar {ctxu}[vfm0M] [jar-文g] [manifest-文g] [-C 目录] 文g?...
选项Q?
-c 创徏新的存档
-t 列出存内容的列?
-x 展开存中的命名的(或所有的〕文?
-u 更新已存在的存档
-v 生成详细输出到标准输Z
-f 指定存文g?
-m 包含来自标明文g的标明信?
-0 只存储方式;未用ZIP压羃格式
-M 不生所有项的清单(manifest〕文?
-i 为指定的jar文g产生索引信息
-C 改变到指定的目录Qƈ且包含下列文Ӟ
如果一个文件名是一个目录,它将被递归处理?
清单Qmanifest〕文件名和存档文件名都需要被指定Q按'm' ?'f'标志指定的相同顺序?
CZ1Q将两个class文g存C个名?'classes.jar' 的存文件中Q?
jar cvf classes.jar Foo.class Bar.class
CZ2Q用一个存在的清单QmanifestQ文?'mymanifest' ?foo/ 目录下的所?
文g存C个名?'classes.jar' 的存文件中Q?
jar cvfm classes.jar mymanifest -C foo/ .
javadoc.exe
用法Qjavadoc [options] [packagenames] [sourcefiles] [classnames] [@files]
-overview <file> d HTML 格式的概q文?
-public 仅显C?public cd成员
-protected 昄 protected/public cd成员Q缺省)
-package 昄 package/protected/public cd成员
-private 昄所有类和成?
-help 昄命o行选项
-doclet <class> 通过候?doclet 生成输出
-docletpath <path> 指定 doclet cL件的查找位置
-sourcepath <pathlist> 指定源文件的查找位置
-classpath <pathlist> 指定用户cL件的查找位置
-exclude <pkglist> Specify a list of packages to exclude
-subpackages <subpkglist> Specify subpackages to recursively load
-breakiterator Compute 1st sentence with BreakIterator
-bootclasspath <pathlist> 覆盖自Dcd载器所加蝲的类文g的位|?
-source <release> Provide source compatibility with specified release
-extdirs <dirlist> 覆盖已安装的扩展的位|?
-verbose 有关 Javadoc 所做工作的输出信息
-locale <name> 所用的 LocaleQ例?en_US ?en_US_WIN
-encoding <name> 源文件编码名U?
-J<flag> ?<flag> 直接传给q行时系l?
由标?doclet 提供Q?
-d <directory> 输出文g的目标目?
-use 创徏cd包的用法?
-version 包含 @version D?
-author 包含 @author D?
-docfilessubdirs Recursively copy doc-file subdirectories
-splitindex 烦引分为每个字母对应一个文?
-windowtitle <text> 文档的浏览器H口标题
-doctitle <html-code> 包含包烦引页Q首)的标?
-header <html-code> 包含每一늚늜文本
-footer <html-code> 包含每一늚脚文本
-bottom <html-code> 包含每一늚底文本
-link <url> Create links to javadoc output at <url>
-linkoffline <url> <url2> Link to docs at <url> using package list at <url2>
-excludedocfilessubdir <name1>:.. Exclude any doc-files subdirectories with given name.
-group <name> <p1>:<p2>.. Group specified packages together in overview page
-nocomment Supress description and tags, generate only declarations.
-nodeprecated 不包?@deprecated 信息
-noqualifier <name1>:<name2>:... Exclude the list of qualifiers from the output.
-nosince Do not include @since information
-nodeprecatedlist 不生成不鼓励使用的列?
-notree 不生成类层次
-noindex 不生成烦?
-nohelp 不生成帮助链?
-nonavbar 不生成导航栏
-quiet Do not display status messages to screen
-serialwarn Generate warning about @serial tag
-tag <name>:<locations>:<header> Specify single argument custom tags
-taglet The fully qualified name of Taglet to register
-tagletpath The path to Taglets
-charset <charset> Charset for cross-platform viewing of generated documentation.
-helpfile <file> 包含帮助链接功能链接到目标的文g
-linksource Generate source in HTML
-stylesheetfile <path> 改变所生成文的样式的文g
-docencoding <name> 输出~码名称
javah.exe
用法Qjavah [options] <classes>
其中 [options] 包括Q?br />
-help 打印该帮助信?
-classpath <path> cȝ加蝲路径
-bootclasspath <path> 自Dcȝ加蝲路径
-d <dir> 输出目录
-o <file> 输出文gQ仅能?-d ?-o 之一Q?
-jni 生成 JNI 风格的头文gQ缺省)
-old 生成 JDK1.0 风格的头文g
-stubs 生成 stubs 文g
-version 打印版本信息
-verbose 输出有关本命令所做工作的信息
-force 始终写输出文?
指定 <classes> 时必M用全名(例如 java.lang.ObjectQ?
javaw.exe
HtmlConverter.exe
用法QHtmlConverter [-option1 value1 [-option2 value2 [...]]] [-simulate] [filespecs]
其中Q选项包括Q?br />
-source: 获取源文件的路径?~省| <userdir>
-dest: 写入已{换文件的路径?~省| <userdir>
-backup: 写备份文件的路径?~省| <dirname>_BAK
-f: 强制覆写备䆾文g?
-subdirs: 应处理子目录中的文g?
-template: 模板文g的\径?如果不确定,请用缺省倹{?
-log: 写日志的路径?如果没有提供Q则不会写入M日志?
-progress: 转换时显C度?~省| true
-simulate: 在没有进行{换时昄特定于{换的信息?
-latest: 使用最新的 JRE 支持发行?mimetype?
-gui: 昄转换E序的图形用L(fng)面?
filespecs: 用空格分开的文件说明列表?~省| "*.html *.htm" Q需要引P
orbd.exe
用法Qorbd <选项>
其中Q?lt;选项> 包括Q?
-port 启动 ORBD 的激zȝ口,~省gؓ 1049 (可?
-defaultdb ORBD 文g的目录,~省gؓ "./orb.db" (可?
-serverid ORBD 的服务器标识W,~省gؓ 1 (可?
-ORBInitialPort 初始端口Q必需Q?
-ORBInitialHost 初始L名称Q必需Q?
policytool.exe
用法Qpolicytool [选项]
[-file <file>] 规则文g位置
rmic.exe
用法Qrmic <选项> <cd>
其中 <选项> 包括Q?
-keep 不删除中间生成的源文?
-keepgenerated Q同 "-keep")
-v1.1 ?1.1 stub 协议版本创徏 stubs/skeleton
-vcompat Q缺省)创徏?1.1 ?
1.2 stub 协议版本兼容?stubs/skeleton
-v1.2 仅ؓ 1.2 stub 协议版本创徏 stubs
-iiop ?IIOP 创徏 stubs。当使用该选项Ӟ<选项>q应包括Q?
-always d?stubs Q即使在它们同时出现时?
-alwaysgenerate (?"-always")
-nolocalstubs 不创Zؓ同一q程优化?stubs
-idl 创徏 IDL。当使用该选项Ӟ<选项>q应包括Q?
-noValueMethods 不生成值类型的Ҏ(gu)
-always d?IDL Q即使在它们同时出现时?
-alwaysgenerate (?"-always")
-g 一般调试信?
-depend 以递归方式重编译过期的文g
-nowarn 不警?
-nowrite 不将~译q的cd入到文gpȝ
-verbose 输出有关~译器所做工作的信息
-classpath <path> 指定输入源和cL件的查找位置
-sourcepath <path> 指定用户源文件的查找位置
-bootclasspath <path> 覆盖自DcL件的位置
-extdirs <path> 覆盖安装扩展cȝ位置
-d <directory> 指定所生成cL件的攄位置
-J<runtime flag> 参Cl?java 解释E序
rmid.exe
用法Qrmid <option>
其中Q?lt;option> 包括:
-port <option> 指定?rmid 使用的端?
-log <directory> 指定 rmid 日志写入的目录
-stop 停止当前?rmid 调用Q对指定端口Q?
-C<runtime 标记> 向每个子q程传递参敎ͼȀzȝQ?
-J<runtime 标记> ?java 解释E序传递参?
rmiregistry.exe
用法Q?rmiregistry <选项> <端口>
其中Q?lt;选项> 包括Q?
-J<runtime 标记> 参C递到 java 解释E序
serialver.exe
用法Qserialver [-classpath classpath] [-show] [classname...]
servertool.exe
Ƣ迎使用 Java IDL 服务器工?
请在提示处输入命?br />
servertool > help
可用命oQ?
register - 注册一个可Ȁzȝ服务?
unregister - 取消服务器注?
getserverid - q回应用E序名称的服务器标识W?
list - 列D所有已注册服务?
listappnames - 列D当前定义的应用程序名U?
listactive - 列D当前zd的服务器
locate - 已注册服务器定位在特定cd的端?
locateperorb - 为已注册服务器的特定对象h代理E序定位端口?
orblist - 对象h代理E序 (orb) 名称及其映射列表
shutdown - 关闭一个已注册服务?
startup - 启动一个已注册服务?
help - 取得帮助
quit - 退出此工具
rmic
功能说明Q?
rmic E对象生?stub ?skeleton?
语法Q?
rmic [ options ] package-qualified-class-name(s)
补充说明Q?
rmic ~译器根据编译后?Java c(含有q程对象实现Q名Qؓq程对象生成 stub ?skeletonQ远E对象是指实?java.rmi.Remote 接口的对象)。在 rmic 命o中所l的cdLl?javac 命o成功~译且是完全包限定的cR?
命o选项
-classpath[路径] 指定 rmic 用于查询cȝ路径。如果设|了该选项Q它?yu)覆盖缺省值或 CLASSPATH 环境变量。目录用冒号分隔?
-d[目录] 指定cdơ的根目录。此选项可用来指?stub ?skeleton 文g的目标目录?
-depend 使编译器考虑重新~译从其它类引用的类?一般来_它只重新~译从源代码引用的遗漏或q期的类?
-g 允许生成调试表格。调试表格含有行号和局部变量的有关信息Q即 Java 调试工具所使用的信息。缺省情况下Q只生成行号?
-J ?-D 选项联用Q它?yu)紧跟其后的选项Q?-J ?-D 之间无空|传给 java 解释器?
-keepgenerated ?stub ?skeleton 文g保留所生成?.java 源文Ӟq将q些源文件写C .class 文g相同的目录中Q如果要指定目录Q则使用 -d 选项?
-nowarn 关闭警告。如果用该选项Q则~译器不输出M警告信息?
-show 昄 rmic ~译器的 GUIQ图形用L(fng)面)。输入一个或多个包限定类名(以空格分隔)Qƈ按回车键?#8220;昄”按钮Q创?stub ?skeleton?
-vcompat Q缺省|创徏?JDK 1.1 ?1.2 stub 协议版本都兼容的 stub ?skeleton?
-verbose 使编译器和链接器输出关于正在~译哪些cd正在加蝲哪些cL件的信息?
-v1.1 创徏 JDK 1.1 stub 协议版本?stub ?skeleton?
-v1.2 只创?JDK 1.2 stub 协议版本?stub?
rmid
功能说明Q?
rmid 启动Ȁzȝl守护进E,以便能够?Java 虚拟Z注册和激zd象?
语法Q?
rmid [-port port] [-log dir]
补充说明Q?
rmid 工具启动Ȁzȝl守护进E。必d启动Ȁzȝl守护进E,才能向激zȝl注册可被激zȝ对象或在 Java 虚拟ZȀzd被激zȝ对象?
命o选项
-C<某些命o行选项> 指定一个选项Q在创徏每个 rmid 的子守护q程Q激zȝQ时Q该选项以命令行参数的Ş式传l该子守护进E?
-log[目录] 指定目录的名UͼȀzȝl守护进E在该目录中写入其数据库及相关信息。缺省状态下Q将在执?rmid 命o的目录中创徏一?log 目录?
-port[端口] 指定 rmid 的注册服务程序所使用的端口。激zȝl守护进E将 ActivationSystem 与该注册服务E序中的名称java.rmi.activation.ActivationSystem 捆绑在一赗?
-stop 停止 -port 选项所指定端口上的当前 rmid 调用。若未指定端口,则将停止在端?1098 上运行的 rmid?
rmiregistry
功能说明Q?
rmiregistry 命o可在当前L的指定端口上启动q程对象注册服务E序?
语法Q?
rmiregistry [port]
补充说明Q?
rmiregistry 命o在当前主机的指定 port 上创建ƈ启动q程对象注册服务E序。如果省?portQ则注册服务E序在 1099 端口上启动。rmiregistry 命o不生Q何输且一般在后台q行。远E对象注册服务程序是自D命名服务。主Z?RMI 服务器将利用它将q程对象l定到名字上。客h卛_查询q程对象q进行远E方法调用。注册服务程序一般用于定位应用程序需调用其方法的W一个远E对象。该对象反过来对各应用程序提供相应的支持Q用于查扑օ它对象。java.rmi.registry.LocateRegistry cȝҎ(gu)可用于在某台L或主机和端口上获取注册服务程序操作。java.rmi.Naming cȝZ URL 的方法将Ҏ(gu)册服务程序进行操作,q可用于查询q程对象、将单(字符Ԍ名称l定到远E对象、将新名U重新绑定到q程对象Q覆盖旧l定Q、取消远E对象的l定以及列出l定在注册服务程序上?URL?
serialver
功能说明Q?
serialver 命oq回 serialVersionUID?
语法Q?
serialver [ 命o选项 ]
补充说明Q?
serialver 以适于复制到演变类的Ş式返回一个或多个cȝ serialVersionUID。不带参数调用时Q它输出用法行?
命o选项
-show 昄一个简单的用户界面。输入完整的cdq按回R键或“昄”按钮可显C?serialVersionUID?
jarsigner
功能说明Q?
?Java 归档 (JAR) 文g产生{Qƈ校验已签名的 JAR 文g的签名?
语法Q?
jarsigner [ 命o选项 ] jar-file alias
jarsigner -verify [ 命o选项 ] jar-file
补充说明Q?
jarsigner 工具用于两个目的Q?
1:?Java 归 (JAR) 文g{
2:校验已签名的 JAR 文g的签名和完整?
命o选项
-keystore[url] 指定密钥仓库?URL。缺省值是用户的宿ȝ录中?.keystore 文gQ它ql属?#8220;user.home”军_?
-storetype[storetype] 指定要被实例化的密钥仓库cd。默认的密钥仓库cd是安全属性文件中 "keystore.type" 属性值所指定的那个类型,?java.security.KeyStore 中的静态方?getDefaultType q回?
-storepass[password] 指定讉K密钥仓库所需的口令。这仅在{Q不是校验)JAR 文g旉要。在q种情况下,如果命o行中没有提供 -storepass 选项Q用户将被提C入口令?
-keypass[password] 指定用于保护密钥仓库(由命令行中指定的别名标出Q的U钥的口令。?jarsigner ?JAR 文g{旉要该口o。如果命令行中没有提供口令,且所需的口令与密钥仓库的口令不同,则将提示用户输入它?
-sigfile[file] 指定用于生成 .SF ?.DSA 文g的基本文件名?
-signedjar[file] 指定用于已签名的 JAR 文g的名U?
-verify 如果它出现在命o行中Q则指定?JAR 文g被校验Q而不是签名。如果校验成功,显C?#8220;jar verified”。如果试图校验未{?JAR 文gQ或校验被不支持的算法(例如未安?RSA 提供者时使用?RSAQ签名的 JAR 文gQ则有如下昄Q?"jar is unsigned. (signatures missing or not parsable)" ?
-certs 如果它与 -verify ?-verbose 选项一起出现在命o行中Q则输出包?JAR 文g的每个签名h的证书信息?
-verbose 如果它出现在命o行中Q则代表“verbose”模式Q它?jarsigner ?JAR {或校验过E中输出额外信息?
-internalsf q去QJAR 文g被签名时产生?.DSAQ签名块Q文件包含一个同时生的 .SF 文gQ签名文Ӟ的完整编码副本。这U做法已被更攏Vؓ了减输?JAR 文g的整个大,~省情况?.DSA 文g不再包含 .SF 文g的副本。但是如?-internalsf 出现在命令行中,采用旧的做法。该选项主要在测试时有用Q实际上不应使用它,因ؓq样消除有用的优化?
-sectionsonly 如果它出现在命o行中Q则 JAR 文g被签名时生成?.SF 文gQ签名文Ӟ不包括含有整个清单文g的散列的头。它仅包??JAR 中每个单独的源文件相关的信息和散列。该选项主要在测试时有用Q实际上不应使用它,因ؓq样消除有用的优化?
-J[javaoption] 指定的 javaoption 串直接传递到 Java 解释器?Qjarsigner 实际上是解释器的一?“wrapper”Q。该选项不应含有MI格。它有助于调整执行环境或内存使用。要获得可用的解释器选项的清单,可在命o行键?java -h ?java -X?
keytool
功能说明Q?
理q钥和认证相关公钥?X.509 证书铄成的密钥仓库Q数据库Q。还理来自可信d体的证书?
语法Q?
keytool [ 命o ]
补充说明Q?
keytool 是个密钥和证书管理工兗它使用戯够管理自q公钥/U钥对及相关证书Q用于(通过数字{Q自我认证(用户向别的用?服务认证自己Q或数据完整性以及认证服务。它q允许用户储存他们的通信对等者的公钥Q以证书形式Q?
native2ascii
功能说明Q?
含有本地编码字W(既非 Latin1 又非 Unicode 字符Q的文g转换?Unicode ~码字符的文件?
语法Q?
native2ascii [options] [inputfile [outputfile]]
补充说明Q?
Java ~译器和其它 Java 工具只能处理含有 Latin-1 ??Unicode ~码Qudddd 记号Q字W的文g。native2ascii 含有其它字W编码的文g转换成含 Latin-1 ??Unicode ~码字符的文件。若省略 outputfileQ则使用标准输出讑֤输出。此外,如果也省?inputfileQ则使用标准输入讑֤输入?
命o选项
-reverse 执行相反的操作:含 Latin-1 ??Unicode ~码字符的文件{换成含本地编码字W的文g?
-encoding[encoding_name] 指定转换q程使用的编码名U。缺省的~码从系l属?file.encoding 中得到?
appletviewer
功能说明Q?
Java applet 览器。appletviewer 命o可在q万维|浏览器环境的情况下q行 applet?
语法Q?
appletviewer [ threads flag ] [ 命o选项 ] urls ...
补充说明Q?
appletviewer 命oq接?url 所指向的文或资源上,q在其自w的H口中显C文档引用的每个 applet。注意:如果 url 所指向的文档不引用M带有 OBJECT、EMBED ?APPLET 标记?appletQ那?appletviewer ׃做Q何事情?
命o选项
-debug ?Java 调试?jdb 中启?appletviewerQ(zhn)可以调试文中?applet?
-encoding[~码名称] 指定输入 HTML 文g的编码名U?
-J[javaoption] ?javaoption 字符串作为单个参Cl运?appletviewer ?Java 解释器。参C能含有空根{由多重参数l成的字W串Q其中的每个参数都必M前缀 -J 开_该前~以后被除去。这在调整编译器的执行环境或内存使用时将很有用?
extcheck
功能说明Q?
extcheck 目?jar 文g与当前安装方式扩?jar 文g间的版本冲突?
语法Q?
extcheck [ -verbose ] targetfile.jar
补充说明Q?
extcheck 实用E序查指?Jar 文g的标题和版本?JDK TM 软g中所安装的扩展是否有冲突。在安装某个扩展前,可以用该实用E序查看是否已安装了该扩展的相同版本或更高的版本?
extcheck 实用E序?targetfile.jar 文g清单?specification-title ?specification-version 头与当前安装在扩展目录下所?Jar 文g的相对应的头q行比较Q缺省扩展目录ؓ jre/lib/extQ。extcheck 实用E序比较版本L(fng)方式?java.lang.Package.isCompatibleWith Ҏ(gu)相同。若未检到冲突Q则q回代码?0。如果扩展目录中M一?jar 文g的清单有相同?specification-title 和相同的或更新的 specification-version P则返回非雉误代码。如?targetfile.jar 的清单中没有 specification-title ?specification-version 属性,则同栯回非雉误代码?
命o选项
-verbose Ҏ(gu)展目录中?Jar 文gq行查时Q列出文件。此外,q报告目?jar 文g的清单属性及所有冲H的 jar 文g?
jar
功能说明Q?
Java归档工具
语法Q?
jar [ 命o选项 ] [manifest] destination input-file [input-files]
补充说明Q?
jar工具是个java应用E序Q可多个文件合qؓ单个JAR归档文g。jar是个多用途的存档及压~工P它基于ZIP和ZLIB压羃格式。然而,设计jar的主要目的是便于java applet或应用程序打包成单个归文g。将applet或应用程序的lg(.class 文g、图像和声音)合ƈ成单个归文件时Q可以用java代理(如浏览器)在一ơHTTP事务处理q程中对它们q行下蝲Q而不是对每个lg都要求一个新q接。这大大~短了下载时间。jarq能压羃文gQ从而进一步提高了下蝲速度。此外,它允许applet的作者对文g中的各个进行签名,因而可认证其来源。jar工具的语法基本上与tar命o的语法相同?
命o选项
-c 在标准输Z创徏新归或I归档?
-t 在标准输Z列出内容表?
-x[file] 从标准输入提取所有文Ӟ或只提取指定的文件。如果省略了fileQ则提取所有文Ӟ否则只提取指定文件?
-f W二个参数指定要处理的jar文g。在-c(创徏)情Ş中,W二个参数指的是要创建的jar文g的名U?不是在标准输Z)。在-t(??x(抽取)q两U情形中Q第二个参数指定要列出或抽取的jar文g?
-v 在标准错误输备上生成长格式的输出l果?
-m 包括指定的现有清单文件中的清单信息。用法D例:“jar cmf myManifestFile myJarFile *.class”
-0 只储存,不进?ZIP 压羃?
-M 不创建项目的清单文g?
-u 通过d文g或更Ҏ(gu)单来更新现有?JAR 文g。例如:“jar -uf foo.jar foo.class”文?foo.class d到现有的JAR文gfoo.jar中,?#8220;jar umf manifest foo.jar”则用manifest中的信息更新foo.jar的清单?
-C 在执?jar 命o期间更改目录。例如:“jar -uf foo.jar -C classes *”classes目录内的所有文件加到foo.jar中,但不dcȝ录本w?
E序CZ
1:当前目录下所有CLASS文g打包成新的JAR文gQ?
jar cf file.jar *.class
2:昄一个JAR文g中的文g列表
jar tf file.jar
3:当前目录下的所有文件增加到一个已l存在的JAR文g?
jar cvf file.jar *
javadoc
功能说明
Java API文档生成器从Java源文件生成API文档HTMLc?
语法Q?
javadoc [ 命o选项 ] [ 包名 ] [ 源文件名 ] [ @files ]
其中[ 包名 ]为用I格分隔的一pd包的名字Q包名不允许使用通配W,如(*Q。[ 源文件名 ]为用I格?/p>