??xml version="1.0" encoding="utf-8" standalone="yes"?> 2、在tryQcatch中如果有return语句Q则在执行return之前先执行finally?/strong> 请大家仔l看下面的例子:(x)
以下是引用片D:(x)
public class TryTest {
public static void main(String[] args) {
try {
System.out.println(TryTest.test());// q回l果为true其没有Q何异?nbsp;
} catch (Exception e) {
System.out.println("Exception from main");
e.printStackTrace();
}
doThings(0);
}
public static boolean test() throws Exception {
try {
throw new Exception("Something error");// W??抛出异常
} catch (Exception e) {// W??捕获的异常匹?声明cL其父c)(j)Q进入控制块
System.out.println("Exception from e");// W??打印
return false;// W?? return前控制{Udfinally?执行完后再返回(q一步被吃掉?jin),不执行?j)
} finally {
return true; // W?? 控制转移Q直接返回,吃掉?jin)异?nbsp;
}
}
public static void doThings(int i)
{
try
{
if(i==0)
{
//在执行return之前?x)先执行finally
return;
}
int t=100/i;
System.out.println(t);
}catch(Exception ex)
{
ex.printStackTrace();
}
finally
{
System.out.println("finally");
}
}
}
Java对多U程的支持与同步机制深受大家的喜爱,g看v来用了(jin)synchronized关键字就可以L地解军_U程׃n数据同步问题。到底如何?――还得对synchronized关键字的作用q行深入?jin)解才可定论?/span>
ȝ说来Q?/span>synchronized关键字可以作为函数的修饰W,也可作ؓ(f)函数内的语句Q也是qx说的同步Ҏ(gu)和同步语句块。如果再l的分类Q?/span>synchronized可作用于instance变量?/span>object referenceQ对象引用)(j)?/span>static函数?/span>class literals(cdU字面常?/span>)w上?/span>
在进一步阐qC前,我们需要明几点:(x)
AQ无?/span>synchronized关键字加在方法上q是对象上,它取得的锁都是对象,而不是把一D代码或函数当作锁――而且同步Ҏ(gu)很可能还?x)被其他U程的对象访问?/span>
BQ每个对象只有一个锁Q?/span>lockQ与之相兌?/span>
CQ实现同步是要很大的pȝ开销作ؓ(f)代h(hun)的,甚至可能造成死锁Q所以尽量避免无谓的同步控制?/span>
接着来讨?/span>synchronized用到不同地方对代码生的影响Q?/span>
假设P1?/span>P2是同一个类的不同对象,q个cM定义?jin)以下几U情늚同步块或同步Ҏ(gu)Q?/span>P1?/span>P2都可以调用它们?/span>
1Q?/font> ?/span>synchronized当作函数修饰W时Q示例代码如下:(x)
Public synchronized void methodAAA()
{
//….
}
q也是同步Ҏ(gu)Q那q时synchronized锁定的是哪个对象呢?它锁定的是调用这个同步方法对象。也是_(d)当一个对?/span>P1在不同的U程中执行这个同步方法时Q它们之间会(x)形成互斥Q达到同步的效果。但是这个对象所属的Class所产生的另一对象P2却可以Q意调用这个被加了(jin)synchronized关键字的Ҏ(gu)?/span>
上边的示例代码等同于如下代码Q?/font>
public void methodAAA()
{
synchronized (this) // (1)
{
//…..
}
}
(1)处的this指的是什么呢Q它指的是调用q个Ҏ(gu)的对象,?/span>P1。可见同步方法实质是?/span>synchronized作用?/span>object reference。――那个拿C(jin)P1对象锁的U程Q才可以调用P1的同步方法,而对P2而言Q?/span>P1q个锁与它毫不相qԌE序也可能在q种情Ş下摆脱同步机制的控制Q造成数据混ؕQ(
2Q同步块Q示例代码如下:(x)
public void method3(SomeObject so)
{
synchronized(so)
{
//…..
}
}
q时Q锁是soq个对象Q谁拿到q个锁谁可以运行它所控制的那D代码。当有一个明的对象作ؓ(f)锁时Q就可以q样写程序,但当没有明确的对象作为锁Q只是想让一D代码同步时Q可以创Z个特D的instance变量Q它得是一个对象)(j)来充当锁Q?/span>
class Foo implements Runnable
{
private byte[] lock = new byte[0]; // Ҏ(gu)?/span>instance变量
Public void methodA()
{
synchronized(lock) { //… }
}
//…..
}
注:(x)雉度的byte数组对象创徏h比M对象都经――查看编译后的字节码Q生成零长度?/span>byte[]对象只需3条操作码Q?/span>Object lock = new Object()则需?/span>7行操作码?/span>
3Q将synchronized作用?/span>static 函数Q示例代码如下:(x)
Class Foo
{
public synchronized static void methodAAA() // 同步?/span>static 函数
{
//….
}
public void methodBBB()
{
synchronized(Foo.class) // class literal(cdU字面常?/span>)
}
}
代码中的methodBBB()Ҏ(gu)是把class literal作ؓ(f)锁的情况Q它和同步的static函数产生的效果是一L(fng)Q取得的锁很特别Q是当前调用q个Ҏ(gu)的对象所属的c(ClassQ而不再是p?/span>Class产生的某个具体对象了(jin)Q?/span>
记得在?/span>Effective Java》一书中看到q将 Foo.class?/span> P1.getClass()用于作同步锁q不一P不能?/span>P1.getClass()来达到锁q个Class的目的?/span>P1指的是由FoocM生的对象?/span>
可以推断Q如果一个类中定义了(jin)一?/span>synchronized?/span>static函数AQ也定义?jin)一?/span>synchronized ?/span>instance函数BQ那么这个类的同一对象Obj在多U程中分别访?/span>A?/span>B两个Ҏ(gu)Ӟ不会(x)构成同步Q因为它们的锁都不一栗?/span>AҎ(gu)的锁?/span>Objq个对象Q?/span>B的锁?/span>Obj所属的那个Class?/span>
结如下Q?/font>
搞清?/span>synchronized锁定的是哪个对象Q就能帮助我们设计更安全的多U程E序?/span>
q有一些技巧可以让我们对共享资源的同步讉K更加安全Q?/font>
1Q?/font> 定义private ?/span>instance变量+它的 getҎ(gu)Q而不要定?/span>public/protected?/span>instance变量。如果将变量定义?/span>publicQ对象在外界可以l过同步Ҏ(gu)的控制而直接取得它Qƈ改动它。这也是JavaBean的标准实现方式之一?/span>
2Q?/font> 如果instance变量是一个对象,如数l或ArrayList什么的Q那上述Ҏ(gu)仍然不安全,因ؓ(f)当外界对象通过getҎ(gu)拿到q个instance对象的引用后Q又其指向另一个对象,那么q个private变量也就变了(jin)Q岂不是很危险?/span> q个时候就需要将getҎ(gu)也加?/span>synchronized同步Qƈ且,只返回这?/span>private对象?/span>clone()――这P调用端得到的是对象副本的引用了(jin)?/span>
Java的类库日益庞大,所包含的类和接口也不计其数。但其中有一些非帔R要的cd接口Q是Javacd中的核心(j)部分。常见的有String、Object、Class、Collection、ClassLoader、Runtime、Process...Q熟(zhn)这些类是学好Java的基。而这些类一般不Ҏ(gu)理解Q需要做深入的研I和实践才能掌握。下面是我对q些cȝ解和使用的一些ȝ。欢q你在阅d你宝贵的意见和d感留下!
leizhimin 51cto技术博?br>
leizhimin 51cto技术博?br>一、概q?br> Runtimecd装了(jin)q行时的环境。每?Java 应用E序都有一?Runtime cd例,使应用程序能够与其运行的环境相连接?br> 一般不能实例化一个Runtime对象Q应用程序也不能创徏自己?Runtime cd例,但可以通过 getRuntime Ҏ(gu)获取当前Runtimeq行时对象的引用?br> 一旦得C(jin)一个当前的Runtime对象的引用,可以调用Runtime对象的方法去控制Java虚拟机的状态和行ؓ(f)?
当Applet和其他不被信ȝ代码调用MRuntimeҎ(gu)Ӟ常常?x)引起SecurityException异常?
leizhimin 51cto技术博?br>
leizhimin 51cto技术博?br>二、API预览
addShutdownHook(Thread hook)
注册新的虚拟机来关闭挂钩?
availableProcessors()
?Java 虚拟回可用处理器的数目?
exec(String command)
在单独的q程中执行指定的字符串命令?
exec(String[] cmdarray)
在单独的q程中执行指定命令和变量?
exec(String[] cmdarray, String[] envp)
在指定环境的独立q程中执行指定命令和变量?
exec(String[] cmdarray, String[] envp, File dir)
在指定环境和工作目录的独立进E中执行指定的命令和变量?
exec(String command, String[] envp)
在指定环境的单独q程中执行指定的字符串命令?
exec(String command, String[] envp, File dir)
在有指定环境和工作目录的独立q程中执行指定的字符串命令?
exit(int status)
通过启动虚拟机的关闭序列Q终止当前正在运行的 Java 虚拟机?
freeMemory()
q回 Java 虚拟Z的空闲内存量?
gc()
q行垃圾回收器?
InputStream getLocalizedInputStream(InputStream in)
已过时??JDK 1.1 开始,本地编码字节流转换?Unicode 字符的首选方法是使用 InputStreamReader ?BufferedReader cR?
OutputStream getLocalizedOutputStream(OutputStream out)
已过时??JDK 1.1 开始,?Unicode 字符{换ؓ(f)本地~码字节的首选方法是使用 OutputStreamWriter、BufferedWriter ?PrintWriter cR?
getRuntime()
q回与当?Java 应用E序相关的运行时对象?
halt(int status)
l止目前正在q行?Java 虚拟机?
load(String filename)
加蝲作ؓ(f)动态库的指定文件名?
loadLibrary(String libname)
加蝲h指定库名的动态库?
maxMemory()
q回 Java 虚拟图用的最大内存量?
removeShutdownHook(Thread hook)
取消注册某个先前已注册的虚拟机关闭挂钩?
runFinalization()
q行挂v finalization 的所有对象的l止Ҏ(gu)?
runFinalizersOnExit(value)
已过时?此方法本w具有不安全性。它可能Ҏ(gu)在用的对象调用l结Ҏ(gu)Q而其他线E正在操作这些对象,从而导致不正确的行为或死锁?
totalMemory()
q回 Java 虚拟Z的内存总量?
traceInstructions(on)
启用Q禁用指令跟t?
traceMethodCalls(on)
启用Q禁用方法调用跟t?
leizhimin 51cto技术博?br>
leizhimin 51cto技术博?br>三、常见的应用
leizhimin 51cto技术博?br>1、内存管理:(x)
Java提供?jin)无用单元自动收集机制。通过totalMemory()和freeMemory()Ҏ(gu)可以知道对象的堆内存有多大,q剩多少?br>Java?x)周期性的回收垃圾对象Q未使用的对象)(j)Q以侉K攑ֆ存空间。但是如果想先于攉器的下一ơ指定周期来攉废弃的对象,可以通过调用gc()Ҏ(gu)来根据需要运行无用单元收集器。一个很好的试验Ҏ(gu)是先调用gc()Ҏ(gu)Q然后调用freeMemory()Ҏ(gu)来查看基本的内存使用情况Q接着执行代码Q然后再ơ调用freeMemory()Ҏ(gu)看看分配?jin)多内存。下面的E序演示?jin)这个构惟?
leizhimin 51cto技术博?br>//此实例来自《java核心(j)技术》卷一
class MemoryDemo{
public static void main(String args[]){
Runtime r = Runtime.getRuntime();
long mem1,mem2;
Integer someints[] = new Integer[1000];
System.out.println("Total memory is Q? + r.totalMemory());
mem1 = r.freeMemory();
System.out.println("Initial free is : " + mem1);
r.gc();
mem1 = r.freeMemory();
System.out.println("Free memory after garbage collection : " + mem1);
//allocate integers
for(int i=0; i<1000; i++) someints[i] = new Integer(i);
leizhimin 51cto技术博?br> mem2 = r.freeMemory();
System.out.println("Free memory after allocation : " + mem2);
System.out.println("Memory used by allocation : " +(mem1-mem2));
leizhimin 51cto技术博?br> //discard Intergers
for(int i=0; i<1000; i++) someints[i] = null;
r.gc(); //request garbage collection
mem2 = r.freeMemory();
System.out.println("Free memory after collecting " + "discarded integers : " + mem2);
}
}
leizhimin 51cto技术博?br>~译后运行结果如下(不同的机器不同时间运行的l果也不一定一P(j)Q?br>Total memory is Q?031616
Initial free is : 1818488
Free memory after garbage collection : 1888808
Free memory after allocation : 1872224
Memory used by allocation : 16584
Free memory after collecting discarded integers : 1888808
leizhimin 51cto技术博?br>
leizhimin 51cto技术博?br>2、执行其他程?br>在安全的环境中,可以在多d操作pȝ中用JavaL行其他特别大的进E(也就是程序)(j)。ecec()Ҏ(gu)有几UŞ式命名想要运行的E序和它的输入参数。ecec()Ҏ(gu)q回一个Process对象Q可以用这个对象控制JavaE序与新q行的进E进行交互。ecec()Ҏ(gu)本质是依赖于环境?br>下面的例子是使用ecec()Ҏ(gu)启动windows的记事本notepad。这个例子必dWindows操作pȝ上运行?
leizhimin 51cto技术博?br>//此实例来自《Java核心(j)技术》卷一
class ExecDemo {
public static void main(String args[]){
Runtime r = Runtime.getRuntime();
Process p = null;
try{
p = r.exec("notepad");
} catch (Exception e) {
System.out.println("Error executing notepad.");
}
}
}
leizhimin 51cto技术博?br>ecec()q有其他几种形式Q例子中演示的是最常用的一U。ecec()Ҏ(gu)q回Process对象后,在新E序开始运行后可以用Process的方法了(jin)。可以用destory()Ҏ(gu)杀dq程Q也可以使用waitFor()Ҏ(gu){待E序直到子程序结束,exitValue()Ҏ(gu)q回子进E结束时q回的倹{如果没有错误,返?Q否则返回非0。下面是关于ecec()Ҏ(gu)的例子的改进版本。例子被修改为等待,直到q行的进E退出:(x)
leizhimin 51cto技术博?br>//此实例来自《Java核心(j)技术》卷一
class ExecDemoFini {
public static void main(String args[]){
Runtime r = Runtime.getRuntime();
Process p = null;
try{
p = r.exec("notepad");
p.waitFor();
} catch (Exception e) {
System.out.println("Error executing notepad.");
}
System.out.println("Notepad returned " + p.exitValue());
}
}
下面是运行的l果Q当关闭C本后Q会(x)接着q行E序Q打C息)(j)Q?br>Notepad returned 0
hL键l? . .
当子q程正在q行Ӟ可以Ҏ(gu)准输入输?gu)行读写。getOutputStream()Ҏ(gu)和getInPutStream()Ҏ(gu)q回对子q程的标准输入和输出?
理解抽象c?br> abstract class和interface在Java语言中都是用来进行抽象类Q本?nbsp;中的抽象cdƈ非从abstract class译而来Q它表示的是一个抽象体Q而abstract class为Java语言中用于定义抽象类的一U方法, 误者注意区分)(j)定义的,那么什么是抽象c,使用抽象c能为我们带来什么好处呢Q?/p>
?nbsp;面向对象的概念中Q我们知道所有的对象都是通过cL描绘的,但是反过来却不是q样。ƈ不是 所有的c都是用来描l对象的Q如果一个类中没有包含够的信息来描l一个具体的对象Q这L(fng)cd是抽象类。抽象类往往用来表征我们在对问题领域q行分析?nbsp;设计中得出的抽象概念Q是对一pd看上M同,但是本质上相同的具体概念的抽象。比如:(x)如果我们q行一个图形编辑Y件的开发,׃(x)发现问题领域存在着圆?nbsp;三角形这样一些具体概念,它们是不同的Q但是它们又都属于Ş状这样一个概念,形状q个概念在问题领域是不存在的Q它?yu)是一个抽象概c(din)正是因为抽象的概念 在问题领域没有对应的具体概念Q所以用以表征抽象概늚抽象cL不能够实例化的?/p>
在面向对象领域,抽象cM要用来进行类型隐藏?nbsp;我们可以构造出一个固定的一l行为的抽象?nbsp;qͼ但是q组行ؓ(f)却能够有L个可能的具体实现方式。这个抽象描q就是抽象类Q而这一lQ意个可能的具体实现则表现为所有可能的zcR模块可以操作一?nbsp;抽象体。由于模块依赖于一个固定的抽象体,因此它可以是不允怿改的Q同Ӟ通过从这个抽象体zQ也可扩展此模块的行为功能。熟(zhn)OCP的读者一定知 道,Z(jin)能够实现面向对象设计的一个最核心(j)的原则OCP(Open-Closed Principle)Q抽象类是其中的关键所在?/p>
从语法定义层面看abstract class ?nbsp;interface
在语法层面,Java语言对于abstract class和interfacel出?jin)不同的定义方式Q下面以定义一个名为Demo的抽象类Z来说明这U不同?/p>
使用abstract class的方式定义Demo抽象cȝ方式如下Q?/p>
abstract class Demo?br> abstract void method1();
abstract void method2();
…
?/p>
使用interface的方式定义Demo抽象cȝ方式如下Q?/p>
interface Demo{
void method1();
void method2();
…
}
在abstract class方式中,Demo可以有自q数据成员Q也可以有非 abstract的成员方法,而在interface方式的实CQDemo只能够有?rn)态的不能被修改的数据成员Q也是必须是static final 的,不过在interface中一般不定义数据成员Q,所有的成员Ҏ(gu)都是abstract的。从某种意义上说Qinterface是一U特DŞ式的 abstract class?/p>
从编E的角度来看Qabstract class和interface都可以用来实?nbsp;"design by contract" 的思想。但是在具体的用上面还是有一些区别的?/p>
首先Qabstract class ?nbsp;Java 语言中表C的是一U承关p,一个类只能使用一ơ承关p?因ؓ(f)Java不支持多l承 -- 转注)。但是,一个类却可以实现多个interface。也许,q是Java语言的设计者在考虑Java对于多重l承的支持方面的一U折中考虑吧?/p>
其次Q在abstract class的定义中Q我们可以赋予方法的默认行ؓ(f)。但是在interface的定义中Q方法却不能拥有默认行ؓ(f)Qؓ(f)?jin)绕q这个限Ӟ必须使用委托Q但是这?x)增加一些复杂性,有时?x)造成很大的麻?ch)?/p>
?nbsp;抽象cM不能定义默认行ؓ(f)q存在另一个比较严重的问题Q那是可能?x)造成l护上的ȝ(ch)。因 为如果后来想修改cȝ界面Q一般通过 abstract class 或者interface来表C)(j)以适应新的情况Q比如,d新的Ҏ(gu)或者给已用的方法中?nbsp;加新的参敎ͼ(j)Ӟ׃(x)非常的麻?ch),可能要花费很多的旉Q对于派生类很多的情况,ؓ(f)如此Q。但是如果界面是通过abstract class来实现的Q那 么可能就只需要修改定义在abstract class中的默认行ؓ(f)可以了(jin)?/p>
同样Q如果不能在抽象cM定义默认行ؓ(f)Q就?x)导致同L(fng)Ҏ(gu)实现出现在该抽象cȝ每一个派生类中,q反?nbsp;"one ruleQone place" 原则Q造成代码重复Q同样不利于以后的维护。因此,在abstract class和interface间进行选择时要非常的小?j)?/p>
从设计理念层面看 abstract class ?nbsp;interface
?nbsp;面主要从语法定义和编E的角度?jin)abstract class和interface的区 别,q些层面的区别是比较低层ơ的、非本质的。本节从另一个层面:(x)abstract class和interface所反映出的设计理念Q来分析一下二 者的区别。作者认为,从这个层面进行分析才能理解二者概늚本质所在?/p>
?nbsp;面已l提到过Qabstract class在Java语言中体C(jin)一U承关p,要想使得 l承关系合理Q父cdzcM间必d?is-a"关系Q即父类和派生类在概忉|质上应该是相同的Q参考文献?〕中有关?is-a"关系的大幅?nbsp;入的 Q有兴趣的读者可以参考)(j)。对于interface来说则不?dng)q不要求interface的实现者和interface定义在概忉|质上是一致的Q?nbsp;仅仅是实C(jin)interface定义的契U而已。ؓ(f)?jin)便于理解Q下面将通过一个简单的实例q行说明?/p>
考虑q样一个例子,假设在我们的问题领域中有一个关于Door的抽象概念,该Doorh执行两个动作open和closeQ此时我们可以通过abstract class或者interface来定义一个表C抽象概念的类型,定义方式分别如下所C:(x)
使用abstract class方式定义DoorQ?/p>
abstract class Door{
abstract void open();
abstract void close()Q?br> }
使用interface方式定义DoorQ?/p>
interface Door{
void open();
void close();
}
其他具体的Doorcd可以extends使用abstract class方式定义的Door或者implements使用interface方式定义的Door。看h好像使用abstract class和interface没有大的区别?/p>
?nbsp;果现在要求Doorq要h报警的功能。我们该如何设计针对该例子的cȝ构呢Q在本例中, 主要是ؓ(f)?jin)展C?nbsp;abstract class 和interface 反映在设计理念上的区别,其他斚w无关的问题都做了(jin)化或者忽略)(j)Q下面将|列出可能的?nbsp;x案,q从设计理念层面对这些不同的Ҏ(gu)q行分析?/p>
解决Ҏ(gu)一Q?/p>
单的在Door的定义中增加一个alarmҎ(gu)Q如下:(x)
abstract class Door{
abstract void open();
abstract void close()Q?br> abstract void alarm();
}
或?/p>
interface Door{
void open();
void close();
void alarm();
}
那么h报警功能的AlarmDoor的定义方式如下:(x)
class AlarmDoor extends Door{
void open(){…}
void close(){…}
void alarm(){…}
}
或?/p>
class AlarmDoor implements Door?br> void open(){…}
void close(){…}
void alarm(){…}
?/p>
q种Ҏ(gu)q反?jin)面向对象设计中的一个核?j)原?nbsp;ISP (Interface Segregation Principle)Q在Door的定义中把Door概念本n固有的行为方法和另外一个概?报警?的行为方 法在了(jin)一赗这样引L(fng)一个问题是那些仅仅依赖于Doorq个概念的模块会(x)因ؓ(f)"报警?q个概念的改变(比如Q修改alarmҎ(gu)的参敎ͼ(j)而改变,?nbsp;之依然?/p>
解决Ҏ(gu)二:(x)
?nbsp;然open、close和alarm属于两个不同的概念,Ҏ(gu)ISP原则应该把它们分别定 义在代表q两个概늚抽象cM。定义方式有Q这两个概念都?nbsp;abstract class 方式定义Q两个概念都使用interface方式定义Q一个概?nbsp;使用 abstract class 方式定义Q另一个概念用interface方式定义?/p>
昄Q由于Java语言不支持多重承,所以两个概念都使用abstract class方式定义是不可行的。后面两U方式都是可行的Q但是对于它们的选择却反映出对于问题领域中的概念本质的理解、对于设计意囄反映是否正确、合理。我们一一来分析、说明?/p>
?nbsp;果两个概念都使用interface方式来定义,那么反映出两个问题Q?、我们可能没?nbsp;理解清楚问题领域QAlarmDoor在概忉|质上到底是Doorq是报警器?2、如果我们对于问题领域的理解没有问题Q比如:(x)我们通过对于问题领域的分 析发现AlarmDoor在概忉|质上和Door是一致的Q那么我们在实现时就没有能够正确的揭C我们的设计意图Q因为在q两个概늚定义上(均?nbsp;interface方式定义Q反映不Zq含义?/p>
?nbsp;果我们对于问题领域的理解是:(x)AlarmDoor在概忉|质上是DoorQ同时它有具有报 警的功能。我们该如何来设计、实现来明确的反映出我们的意思呢Q前面已l说q,abstract class在Java语言中表CZU承关p,而承关p?nbsp;在本质上?is-a"关系。所以对于Doorq个概念Q我们应该用abstarct class方式来定义。另外,AlarmDoor又具有报警功能,?nbsp;明它又能够完成报警概念中定义的行为,所以报警概念可以通过interface方式定义。如下所C:(x)
abstract class Door{
abstract void open();
abstract void close()Q?br> }
interface Alarm{
void alarm();
}
class Alarm Door extends Door implements Alarm{
void open(){…}
void close(){…}
void alarm(){…}
}
q?nbsp;U实现方式基本上能够明确的反映出我们对于问题领域的理解,正确的揭C我们的设计意图。其 实abstract class表示的是"is-a"关系Qinterface表示的是"like-a"关系Q大家在选择时可以作Z个依据,当然q是建立在对 问题领域的理解上的,比如Q如果我们认为AlarmDoor在概忉|质上是报警器Q同时又hDoor的功能,那么上述的定义方式就要反q来?jin)?/p>
结
1.abstract class ?nbsp;Java 语言中表C的是一U承关p,一个类只能使用一ơ承关pR但是,一个类却可以实现多个interface?br> 2.在abstract class 中可以有自己的数据成员,也可以有非abstarct的成员方法,而在interface中,只能够有?rn)态的不能被修改的数据成员Q也是必须是static final的,不过?nbsp;interface中一般不定义数据成员Q,所有的成员Ҏ(gu)都是abstract的?br> 3.abstract class和interface所反映出的设计理念不同。其实abstract class表示的是"is-a"关系Qinterface表示的是"like-a"关系?nbsp;
4.实现抽象cd接口的类必须实现其中的所有方法。抽象类中可以有非抽象方法。接口中则不能有实现Ҏ(gu)?br> 5.接口中定义的变量默认是public static final 型,且必ȝ其初|所以实现类中不能重新定义,也不能改变其倹{?br> 6.抽象cM的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋倹{?nbsp;
7.接口中的Ҏ(gu)默认都是 public,abstract cd的?br> l论
abstract class ?nbsp;interface ?nbsp;Java语言中的两种定义抽象cȝ方式Q它们之间有很大的相似性。但是对于它们的选择却又往往反映出对于问题领域中的概 忉|质的理解、对于设计意囄反映是否正确、合理,因ؓ(f)它们表现?jin)概念间的不同的关系Q虽焉能够实现需求的功能Q。这其实也是语言的一U的惯用法,希望 读者朋友能够细l体?x)?/p>
参考文?br> [1] Thinking in Java, Bruce Eckel
[2] Design Patterns Explained: A New Perspective on Object-Oriented Design, Alan Shalloway and James R. Trott
[3] Effective C++: 50 Specific Ways to Improve Your Programs and Design, Scott Meyers
下面列出?jin)原始类型以及(qing)它们的对象装cR?/p>
原始cd封装类
booleanBoolean
char Character
byte Byte
shortShort
intInteger
long Long
floatFloat
double?Double
引用cd和原始类型的行ؓ(f)完全不同Qƈ且它们具有不同的语义。例如,假定一个方法中有两个局部变量,一个变量ؓ(f) int 原始cdQ另一个变量是对一?Integer 对象的对象引用:(x)
int i = 5; // 原始cd
Integer j = new Integer(10); // 对象引用
q两个变量都存储在局部变量表中,q且都是?Java 操作数堆栈中操作的,但对它们的表C却完全不同。(本文中以下部分将用通用术语堆栈代替操作数堆栈或局部变量表。)(j)原始cd int 和对象引用各占堆栈的 32 位。(要表CZ?int 或一个对象引用,Java 虚拟机实现至需要?32 位存储。)(j)Integer 对象的堆栈项q不是对象本w,而是一个对象引用?/p>
Java 中的所有对象都要通过对象引用讉K。对象引用是指向对象存储所在堆中的某个区域的指针。当声明一个原始类型时Q就为类型本w声明了(jin)存储。前面的两行代码表示如下Q?/p>
引用cd和原始类型具有不同的特征和用法,它们包括Q大和速度问题Q这U类型以哪种cd的数据结构存储,当引用类型和原始cd用作某个cȝ实例数据时所指定的缺省倹{对象引用实例变量的~省gؓ(f) nullQ而原始类型实例变量的~省g它们的类型有兟?/p>
许多E序的代码将同时包含原始cd以及(qing)它们的对象封装。当(g)查它们是否相{时Q同时用这两种cdq了(jin)解它们如何正相互作用和共存成为问题。程序员必须?jin)解q两U类型是如何工作和相互作用的Q以避免代码出错?/p>
例如Q不能对原始cd调用Ҏ(gu)Q但可以对对象调用方法:(x)
int j = 5;
j.hashCode(); // 错误
//...
Integer i = new Integer(5);
i.hashCode(); // 正确
使用原始cd无须调用 newQ也无须创徏对象。这节省?jin)时间和I间。合用原始类型和对象也可能导致与赋值有关的意外l果。看h没有错误的代码可能无法完成?zhn)希望做的工作。例如:(x)
import java.awt.Point;
class Assign
{
public static void main(String args)
{
int a = 1;
int b = 2;
Point x = new Point(0,0);
Point y = new Point(1,1); // 1
System.out.println("a is " + a);
System.out.println("b is " + b);
System.out.println("x is " + x);
System.out.println("y is " + y);
System.out.println("Performing assignment and " +
"setLocation...");
a = b;
a++;
x = y; // 2
x.setLocation(5,5); // 3
System.out.println("a is "+a);
System.out.println("b is "+b);
System.out.println("x is "+x);
System.out.println("y is "+y);
}
}
q段代码生成以下输出Q?/p>
a is 1
b is 2
x is java.awt.Point
y is java.awt.Point
Performing assignment and setLocation...
a is 3
b is 2
x is java.awt.Point
y is java.awt.Point
修改整数 a ?b 的结果没什么意外的地方。b 的D赋予整型变量 aQ结?a 的值增加了(jin) 1。这一输出反映?jin)我们希望发生的情况。但是,令h感到意外的,是在赋值ƈ调用 setLocation之后 x ?y 对象的输出。我们在完成 x = y 赋g后特意对 x 调用?setLocationQx ?y 的值怎么?x)相同呢Q我们毕竟将 y 赋予 xQ然后更改了(jin) xQ这与我们对整数 a ?b q行的操作没什么不同?/p>
q种h是由原始cd和对象的使用造成的。赋值对q两U类型所L(fng)作用没什么不同。但它可能看h所有不同。赋gɽ{号 (=) 左边的值等于右边的倹{这一点对于原始类型(如前面的 int a ?bQ是显而易见的。对于非原始cdQ如 Point 对象Q,赋g改的是对象引用,而不是对象本w。因此,在语?x = y; 之后Qx {于 y。换句话_(d)因ؓ(f) x ?y 是对象引用,它们现在引用同一个对象。因此,?x 所作的M更改也会(x)更改 y?br>
因ؓ(f) x ?y 引用同一个对象,所以对 x 执行的所有方法与?y 执行的方法都作用于同一个对象?/p>
区分引用cd和原始类型ƈ理解引用的语义是很重要的。若做不到这一点,则会(x)使编写的代码无法完成预定工作?/p>
=========================================================================
Java 提供两种不同的类型:(x)引用cd和原始类型(或内|类型)(j)。Int是java的原始数据类型,Integer是java为int提供的封装类。Java
为每个原始类型提供了(jin)装cR?br>原始cd装c?booleanBoolean,charCharacter,byteByte,shortShort,intInteger,longLong,floatFloat,doubleDouble
引用cd和原始类型的行ؓ(f)完全不同Qƈ且它们具有不同的语义。引用类型和原始cdh不同的特征和用法Q它们包括:(x)大小和速度问题Q?/font>
q种cd以哪U类型的数据l构存储Q当引用cd和原始类型用作某个类的实例数据时所指定的缺省倹{对象引用实例变量的~省gؓ(f) nullQ?/font>
而原始类型实例变量的~省g它们的类型有?br>
在java中一切都是以cMؓ(f)基础的,q且java对基本的数据cd也进行了(jin)装Q如下所C,介l几个基本的数据cd?qing)其装c:(x)
1 Boolean VS boolean
public final class Boolean
Boolean cd基本cd? 的值包装在一个对象中。一?
cd的对象只包含一个类型ؓ(f)
的字Dc(din)?
此外Q此c还? ?
的相互{换提供了(jin)许多Ҏ(gu)Qƈ提供?jin)处?
旉常有用的其他一些常量和Ҏ(gu)?br>.............
Byte QCharacter QDouble {等都是一?br>
表A Java原始数据cd
单类?大小 范围/_ֺ
float 4 字节 32位IEEE 754单精?
double 8 字节 64位IEEE 754双精?
byte 1字节 -128?27
short 2 字节 -32,768?2,767
int 4 字节 -2,147,483,648?,147,483,647
long 8 字节 -9,223,372,036,854,775,808?,223,372,036, 854,775,807
char 2 字节 整个Unicode字符?
boolean 1 ?True或者f(xi)alse
h......exe4jQ,呵呵 不用说了(jin)吧?/p>