|
我的評論
re: java文件操作大全[分享] JavaSuns 2008-06-25 17:54
@minrui
好好學習,天天向上
re: 申請加入鄭州java小組 JavaSuns 2007-04-03 11:57
我是新鄉的,現在中山,Sunspl,申請加入,謝謝您.
re: [oop] 面向對象由淺入深 JavaSuns 2006-09-06 11:41
class Cup
{
Cup(int marker)
{
System.out.println("Cup(" + marker + ")");
}
void f(int marker)
{
System.out.println("f(" + marker + ")");
}
}
class Cups
{
static Cup c1=new Cup(1);
Cup c3=new Cup(3);
static Cup c2= new Cup(2);
Cups()
{
System.out.println("Cups()");
}
Cup c4=new Cup(4);
}
public class ExplicitStatic
{
Cups c=new Cups();
{
System.out.println("Hello");
}
public static void main(String[] args)
{
System.out.println("Inside main()");
Cups.c1.f(99);
ExplicitStatic x=new ExplicitStatic();
}
static Cups x = new Cups();
}
大家可以手動執行一下這個程序,考慮一下結果是什么,然后參照下面的答案對照一下,看看是否正確:
Cup(1)
Cup(2)
Cup(3)
Cup(4)
Cups()
Inside main()
f(99)
Cup(3)
Cup(4)
Cups()
Hello
我總結了四個初始化的要點,如下:
1、 如果有static,即靜態成員定義,首先初始化static的變量,如,在類Cups中c3在c2前面,可是在輸出的結果中,你可以發現,c2是在c3前執行的,這就是因為,所有的static都在第一時間被初始化。
2、 Static只初始化一次,在第二次創建類的對象的時候,就不會去執行static的語句,如,在第二次執行new Cups()的時候,就只輸出了Cup(3)和Cup(4),顯然,static的兩個創建對象的語句沒有做。
3、 變量的初始化在方法前。如,在Cups類中,方法Cups()在語句Cup c4=new Cup(4)之前,可是輸出結果的時候,打印的Cups()卻在Cup(4)之后。
4、 在含有main的類中執行順序是先做static,然后就是main,而不是像其它類一樣,除了static就按順序做下來。如,在main函數中,如果去掉語句ExplicitStatic x=new ExplicitStatic(),則Cups c=new Cups()和System.out.println("hello")都不會執行。另外,留個小問題,如果去掉了System.out.println("hello")外的括號會怎么樣呢?
re: [oop] 面向對象由淺入深 JavaSuns 2006-09-06 11:41
雖然Java只支持從一個父類繼承,但它使用接口的方式支持多重繼承.
接口實現了多態,使得我們能夠給與對象不同特性以滿足不同的需要.
你可以使用多態機制讓完成相似功能的不同的方法擁有相同的名字但是擁有不同的參數列表.
動態/運行時的綁定機制允許一個對象在運行時被強制轉化成你所需要的對象類型,前提是這個對象實現了必需的接口或者括展了特定的父類.
下面我們將討論通過限制對對象屬性和方法的訪問來強制實現對多重接口實現和父類拓展的正確使用的目的和實用性.
黑箱方法:封裝
一個基本的面向對象的概念就是封裝--將表示一個對象狀態的數據與其它對象隔離開來.這一點是通過一個通常叫做作用域的概念來實現的.作用域指的是編程語言的一種能力,這種能力被用來實現一些限制對類或者結構體成員變量的訪問的規則.大多數面向對象的語言支持作用域機制,這些機制通常是通過諸如public, protected, 和 private之類的特殊關鍵字來實現的.
Java提供了四種不同的作用范圍:public, package, protected, 和 private.任何類,方法或者成員變量都能通過使用public, protected, 和 private關鍵字來顯式的加以保護.任何類,方法,或者成員變量如果沒有使用上面的關鍵字都將被隱式的給與package的作用范圍.所有這些就構成了Java中命名空間的概念.
命名空間和軟件包
一個命名空間可以被看成是在一個給定的上下文中一組相關的名字或是標識符.命名空間避免了擁有相同名字或標識符的實體存在于同一個上下文里.這里隱含的意思是只要實體是存在于不同的命名空間中,那么擁有相同名字或者標識符的實體就能夠呆在一塊兒.Java使用軟件包的概念來實現命名空間和作用范圍控制.
軟件包是一個在統一的名字下的類和接口的集合.每一個類或者接口都必須存在于用package關鍵字構成的軟件包申明語句定義的命名空間中.例如,下面的申明語句:
package com.mycompany.apps.HelloWorld;
它申明了一個存在于com.mycompany.apps軟件包中的名叫HelloWorld的類或者接口.軟件包申明總是放在包含了類或者接口定義的文件的頂部.
在java開發界,目前對軟件包的命名有一個建議,就是使用公司或組織的域名(以相反的順序),作為你的軟件包的第一部分.因為域名是全球唯一的,所以使用你的域名來命名你的軟件包也能使你軟件包的名字全球唯一.
如果一個Java類或者接口沒有包含一個軟件包申明,那么它就屬于"unamed package,"也就是沒有名字的軟件包.無名的軟件包應該只用來測試程序或是代碼原型等等.
re: [oop] 面向對象由淺入深 JavaSuns 2006-09-06 11:40
深入繼承性
一些面向對象的語言提供叫做"多重繼承"的特點,當一個對象需要從多于一個的基類繼承行為和屬性的時候這是有價值的.多重繼承在有些情況下是復雜的.例如,假設我們需要定義一個基類,Animal,然后是Animal的兩個子類,LandAnimal 和 WaterAnimal.現在我們想要定義一個類來代表青蛙.青蛙是兩棲動物,所以我們自然會想到定義Frog類從LandAnimal和WaterAnimal類繼承.這使得Frog類能夠同時從LandAnimal 和WaterAnimal類繼承所需的行為和屬性.
初看起來這是相當簡單的;但是,讓我們為Animal添加一個叫做LivingEnvironment的屬性,并用方法getLivingEnvironment來返回它.我們假設LandAnimal 和 WaterAnimal類都重載了這個方法來實現特殊的功能.LandAnimal將返回Land作為它的LivingEnvironment屬性的值,而WaterAnimal將返回Water作為它的LivingEnvironment屬性的值.現在,當我們將Frog類作為LandAnimal 和 WaterAnimal 子類實現的時候,想要得到Frog的LivingEnvironment屬性值,這時將遇到一個麻煩:Frog類的getLivingEnvironment方法是返回Land值呢還是Water值?答案取決于編譯器如何處理多重繼承.
我在前面的文章里就已經說過,Java不支持多重繼承.但它確實允許一個對象通過使用叫做"接口"的功能擁有多個特性.下面的例子顯示了定義LandAnimal的接口的可能的定義代碼:
public interface LandAnimal
{
public int getNumberOfLegs();
public boolean hasATail();
}
一個使用接口的類在類定義語句的開始添加implements+接口名.例如,在Java中,我們會以下面的方式定義Frog類:
public class Frog extends Animal implements LandAnimal, WaterAnimal
接口并沒有什么實際的功能;相反,它的作用是聯系使用者和實現了這個接口的對象.接口保證了對象實現接口定義的方法.而且,一個實現接口的對象能夠在運行時被強制轉換成接口類型.例如,使用上面的Frog定義,并且假設LandAnimal類定義了一個叫做getNumberOfLegs的方法而WaterAnimal定義了一個叫做hasGills的方法,那么一個Frog類的實例可以在運行時被強制轉換成LandAnimal或WaterAnimal對象:
Frog aFrog = new Frog();
int legCount = ((LandAnimal)aFrog).getNumberOfLegs();
Boolean gillFlag = ((WaterAnimal)aFrog).hasGills();
注意Forg為什么能夠被強制轉換成一個LandAnimal對象即使實際的LandAnimal對象并沒有被創建.這使得我們能夠在運行時以其帶有的任何"身份"調用一個對象,這就是所謂的"動態綁定"或"運行時綁定".
re: [oop] 面向對象由淺入深 JavaSuns 2006-09-06 11:39
對象詳論
使用對象的一個關鍵是當你在瀏覽系統分析文檔或者設計文檔的時候如何來確定它們.因為對象一般代表人,地方或者事物,所以一個確定對象的基本的方法就是找出句子中所使用的名詞.這里有一個簡單的例子.在句子"一個顧客可以擁有多于一個的銀行帳號",我們就確定了兩個對象,客戶和帳號.在句子"小貓喵喵叫"中,我們能夠確定一個對象,貓.
類詳論
前面,我們學習了一個類是定義了對象如何動作以及當對象創建或者說實例化的時候應該包含些什么的實體.在對動物的討論中,我們可以說,"狗兒汪汪叫,貓喵喵叫,鴨子嘎嘎叫."確定句子中的對象我們就得到了狗,貓和鴨子.至于汪汪叫,喵喵叫,嘎嘎叫,那都是我們對象發出的行為動作.
要實現這些對象,我們需要創建三個對象分別叫Dog,Cat和Duck.要實現它們的行為,我們可以為每一個這些對象創建代表每個對象發出的聲音的方法,而且我們把這個方法叫做speak或者,如果我們發揮想象力的話還可以把這個方法叫做sayHello.
在程序的上下文中為了演示這些概念,讓我們修改上篇文章中的HelloWorld程序,添加這三個新對象并給它們中的每一個添加sayHello方法,如下所示:
public class HelloWorld
{
public static void main(String[] args)
{
Dog animal1 = new Dog();
Cat animal2 = new Cat();
Duck animal3 = new Duck();
animal1.sayHello();
animal2.sayHello();
animal3.sayHello();
}
}
class Dog
{
public void sayHello()
{
System.out.println("Bark");
}
}
class Cat
{
public void sayHello()
{
System.out.println("Meow");
}
}
class Duck
{
public void sayHello()
{
System.out.println("Quack");
}
}
在編譯并運行了這個程序以后,輸出應該如下:
Bark
Meow
Quack
看看我們的程序,我們馬上就注意到了一些事情:每個對象代表了一種動物,而每個對象實現了一個相同的方法,sayHello.假設我們想要給對象更多的功能以及用來代表對象所指的動物的方法和屬性.比方說,我們可以添加一個方法來確定一個動物是不是哺乳類的,或者我們添加一個方法來確定一個動物是不是肉食性的.我們可以通過給每一個對象添加這兩種方法來實現或者我們也能夠使用OOP的兩個最強大的功能:繼承和多態.
因為所有的對象都代表一個對象,所以我們將創建一個被稱為"基類"或是"超類"的類,它的名字是Animal.我們然后可以讓我們的對象從Animal類繼承相同的特點并強制每個對象只實現與Animal類不同的功能.
Java用extends關鍵字指明一個類從另一個繼承.讓我們利用繼承和多態的概念獲得代碼重用的好處來重建我們的程序并使得每個對象只實現與基類Animal不同的功能:
public class HelloWorld
{
public static void main(String[] args)
{
Dog animal1 = new Dog();
Cat animal2 = new Cat();
Duck animal3 = new Duck();
System.out.println("A dog says " +animal1.getHello()
+", is carnivorous: " +animal1.isCarnivorous()
+", is a mammal: " +animal1.isAMammal());
System.out.println("A cat says " +animal2.getHello()
+", is carnivorous: " +animal2.isCarnivorous()
+", is a mammal: " +animal2.isAMammal());
System.out.println("A duck says " +animal3.getHello()
+", is carnivorous: " +animal3.isCarnivorous()
+", is a mammal: " +animal3.isAMammal());
}
}
abstract class Animal
{
public boolean isAMammal()
{
return(true);
}
public boolean isCarnivorous()
{
return(true);
}
abstract public String getHello();
}
class Dog extends Animal
{
public String getHello()
{
return("Bark");
}
}
class Cat extends Animal
{
public String getHello()
{
return("Meow");
}
}
class Duck extends Animal
{
public boolean isAMammal()
{
return(false);
}
public boolean isCarnivorous()
{
return(false);
}
public String getHello()
{
return("Quack");
}
}
在編譯并運行我們的程序以后,輸出應該如下:
A dog says Bark, is carnivorous: true, is a mammal: true
A cat says Meow, is carnivorous: true, is a mammal: true
A duck says Quack, is carnivorous: false, is a mammal: false
看看我們的例子,你將發現我們定義了一個叫做Animal的新類,它定義了三個方法:isAMammal, isCarnivorous, 和 getHello.你一概還注意到了,我們在每個現存的類申明的前面都添加了extends Animal這個語句.這個語句告訴編譯器這些對象是Animal類的子類.
因為方法isAMammal 和 isCarnivorous 都返回 true,所以Dog和Cat類用不著重新實現--即"重載"這兩個方法.但是鴨子既不是哺乳動物又不是肉食性的,所以Duck類需要重載這兩種方法來返回正確的值.我們所有的對象都以自己獨特的方式說"hello",所以它們都需要重載getHello方法.因為每種動物說"hello"的方式都不同,所以我們在基類中將getHello方法申明為抽象的,而且我們沒有給這個方法一個函數體.這就迫使Animal的每一個子類重載getHello方法并根據每一個特定動物的需要來定義它.
因為我們將getHello方法申明為虛擬的,我們就不能直接實例化Animal對象.因此,我們需要將Animal類也申明為抽象的.我們通過在Animal類定義的開始行添加abstract關鍵字來實現這一點.子類重載它們基類的方法的能力就是多態.多態使得子類能夠使用基類的方法或是在這些方法不足的時候重載它們.這就實現了代碼重用,加快了代碼的實現過程,而且它還隔離和程序中的bug,使得程序的維護更容易.
總結
在本文中,我們學習了如何確定潛在的對象.我們還學習了如何使用繼承和多態來加快我們的代碼實現過程并隔離錯誤,這使得代碼的維護過程更加容易.下一次,我們將展開討論多態和繼承的概念并開始我們對動態綁定的討論.
re: [oop] 面向對象由淺入深 JavaSuns 2006-09-06 11:38
一種語言是面向對象的究竟意味著什么呢?如果一種編程語言是真正的面向對象的語言,它必須支持以下的特點:
封裝--隱藏實現細節
多態--將同一個消息發送給不同的對象并使各個對象以預定的方式對消息做出響應的能力
繼承--拓展現存的類來生成專有類繼承原來類的狀態和行為的能力
動態綁定--在編程時不必知道對象的具體類型就能向它們發送消息的能力
讓我們考察一下Java是如何支持這些功能的以及它又如何提供了附加的功能來使得從過程化的程序設計到面向對象的開發的轉變過程相對容易.
Java中面向對象的特點
Java是由Sun Microsystems公司在九十年代中期發布的面向對象(OOP)的編程語言.你可以從Sun公司的網站上下載最新的Java開發包(JDK).Java是一種解釋性的語言,這意味著其源程序首先被編譯成中間代碼的形式,然后在每次運行之前都要經過虛擬機的解釋,它是徹頭徹尾的面向對象的編程語言.
Java對程式員隱藏了許多傳統的面向對象編程語言--比方說C++和Object Pascal--的復雜性和讓人容易混淆的地方.例如,Java中沒有了指針,Java會為程序員自動的清除引用類型,而且所有變量將被自動初始化成適當的缺省值.除了原始數據類型以外,Java中的所有東西都是對象,必要的時候,甚至可以為原始數據類型也提供封裝機制.
對象簡介
對象是代表現實生活中的實物的軟件編程實體,比如說銀行帳號,計算機用戶,用戶介面上的按鈕,窗口菜單等等.對象是由它們的狀態和行為定義的.例如,一個銀行帳號擁有一種狀態,諸如當前的收支狀況,賬戶的所有人,允許的最小交易額,等等,而它的行為則包括提取,存入,收支平衡等.
一個對象的狀態是由只有對象自己知道的變量定義的.Java把這些變量稱為數據域或者成員變量.數據域對對象來說是私有的除非顯式的使用關鍵字來定義它們的作用域,使它們對其它類可見.我們將在以后討論變量作用域的問題.
一個對象的行為是由它上面的操作定義的.在Java中,這些操作被叫做方法.方法可以改變一個對象的狀態,創建新對象,實現實用的功能等.
類
類是一個實體,它定義了一個對象的運行方式以及在對象被創建或者說實例化的時候所包含的數據.類的作用就象一個模板,一個或者多個對象可以依照它來創建.下面是使用Java面向對象的概念申明HelloWorld應用程序的例子:
public class HelloWorld
{
private String helloMsg = "Hello World!";
public static void main(String[] args)
{
HelloWorld hw = new HelloWorld();
}
public HelloWorld()
{
// 顯示我們的"Hello World"消息
System.out.println(helloMsg);
}
}
上面的例子定義了一個模板,真實的HelloWorld對象可以從這個模板創建.你還會注意到從public static void main(String[] args)這一行開始的一段奇怪的代碼.這一段代碼定義的是一個特殊的方法main,它其實就是我們這個HelloWorld程序的入口點,上面的程序是一個典型的演示所有的Java應用程序如何定義它們的入口點.注意到即使是這個main入口點也被封裝在類里面.對于這個例子,我們就是將它封裝在HelloWorld類里.上面的程序展示了如何定義一個類,HelloWorld,以及其中的一個數據域,helloMsg和兩個方法main和HelloWorld.HelloWorld方法是一種特殊的方法,這種方法被稱做構造函數.我們將在后面的文章里討論常規方法,構造函數和靜態成員函數的細節和區別.
在Java中,所有與一個特殊的類有關的源代碼都寫在一個與類同名的擁有后綴名.java的文件里.Java編譯器讀取源文件并將它們翻譯成平臺無關的,二進制格式的代碼,成為字節代碼,然后將這些代碼分類保存在與類同名的但是后綴為.class的文件里.你最終會為每一個類得到一個class文件.
編譯并運行我們的例子程序
一旦你已經從Sun的Web站點上下載了JDK并在你的機器上安裝了它,你就可以開始編譯并運行Java程序了.要編譯并運行我們的例子程序,將HelloWorld類的代碼粘貼到你最喜歡的文檔編輯器里,將文件保存為HelloWorld.java,然后,在命令提示符下,將當前路徑改變到包含了這個文件的路徑里.現在你就可以在命令行提示符下鍵入下面的命令來編譯程序了:
Windows:
<你的JDK所在目錄>\bin\javac HelloWorld.java
UNIX or Linux:
<你的JDK所在目錄>/bin/javac HelloWorld.java
這個命令將在同一個目錄里產生一個新的文件,叫做HelloWorld.class.要運行這個程序,請在命令提示符下鍵入下面的命令:
Windows:
<你的JDK所在目錄>\bin\java HelloWorld
UNIX or Linux:
<你的JDK所在目錄>/bin/java HelloWorld
你應該可以看到屏幕上顯示Hello World!
總結
我們已經接觸到了使用Java程序設計語言進行面向對象的編程的一些皮毛知識.下次,我們將剖析我們的例子程序,給它添加更多的功能,并討論更多的有關對象,類和其它面向對象編程的基本概念以及用Java如何實現它們.
|