新四季網

java面向對象分析(深入理解面向對象)

2023-04-16 03:58:05

一、結構化程序設計與面向對象1. 概述

早期的程式語言如:C、Basic、Pascal等都是結構化程式語言。結構化程序設計的核心思想就是程序的開發採用自上而下的設計(稱為瀑布模式)。對於大型的應用來說,採用函數和庫的方式來對代碼進行管理。而C 、java、C#、Ruby等都是面向對象的程式語言,將現實世界採用類、對象的概念進行建模。

2. 結構化程序設計簡介

結構化程序設計方法主張按功能來分析系統需求,其主要原則可概括為自頂向下、逐步求精、模塊化等。

結構化程序設計首先採用結構化分析(Structured Analysis,SA)方法對系統進行需求分析,然後使用結構化設計(Structured Design,SD)方法對系統進行概要設計、詳細設計、最後採用結構化編程(Structured Program,SP)方法來實現系統。使用這種 SA、SD、SP的方式可以較好的保證軟體系統的開發進度和質量。

結構化程序使用三種基本控制結構構造程序,即:

順序選擇循環三種基本控制結構構造。

結構化程序設計主要強調的是程序的易讀性。

詳細描述處理過程常用三種工具:圖形、表格和語言。

圖形:程序流程圖、N-S圖、PAD圖表格:判定表語言:過程設計語言(PDL)

結構化程序設計曾被稱為軟體發展中的第三個裡程碑,要點是:

主張使用順序、選擇、循環三種基本結構來嵌套連結成複雜層次的結構化程序,嚴格控制GOTO語句的使用自頂而下、逐步求精獨立功能、單出口、單入口,減少模塊的相互聯繫使模塊可作為插件或積木使用,降低程序的複雜性,提高可靠性。2. 面向對象程序設計

基本思想是使用類、對象、繼承、封裝、消息等基本概念來進行程序設計。最小的程序單元是類,這些類可以生成系統中的多個對象,而這些對象則直接映像成客觀世界的各種事務。採用面向對象方式開發的軟體系統邏輯上的組成結構如:

面向對象的軟體系統由多個類組成。類還會提供操作這些狀態數據的方法,為這些行為提供相應的實現。

二、類的定義與修飾符1. 定義類

[修飾符] class 類名{ 零到多個構造器定義.. 零到多個Field… 零到多個方法…}

一個實際的例子:

public class Person{ public String name; public int age; public void say(String content){ System.out.println(content); }}Person p; //p變量,放在棧內存裡p=new Person; //Person對象放在堆內存裡

類也是一種引用數據類型,因此程序中定義的Person類型的變量實際上是一個引用,它被存放在棧內存裡,指向實際的Person對象,而真正的Person對象則存放在堆(heap)內存中。Java程序不允許直接訪問堆內存中的對象,只能通過該對象的引用操作該對象。不管是數組還是對象,都只能通過引用來訪問它們。

堆內存裡的對象可以有多個引用,即多個引用變量指向同一個對象。如接上面的程序:

Person p2=p;

如果堆內存裡的對象沒有任何變量指向該對象,那程序將無法再訪問該對象,這個對象就變成了垃圾,Java的垃圾回收機制將回收該對象,釋放該對象所佔的內存區。因此,如果希望通知垃圾回收機制回收某個對象,只需切斷該對象的所有引用變量和它之間的關係即可,也就是把這些引用變量賦值為null。

2. 修飾符public 公共類與公共屬性、方法protected 保護類與保護屬性、方法private 私有類與私有屬性、方法static 靜態類與靜態屬性、方法final 表示修飾的類、方法、變量不可改abstract 虛類abstract和final最多只能出現其中之一,可以與static組合起來修飾方法3. final修飾符

final類似C#裡的sealed關鍵字,用於表示它修飾的類、方法和變量不可改變

2.3.1 final 成員變量

final修飾的成員變量必須由程式設計師顯示地指定初始值類 Field:在靜態初始化塊中或聲明該Field時指定初始值實例Field:必須在非靜態初始化塊、聲明Field或構造函數中指定初始值

2.3.2 final 局部變量2.3.3 final 修飾基本類型變量和引用類型變量的區別

final修飾基本類型變量,變量的值不能改變但修飾引用類型變量,只保證這個引用類型變量所引用的地址不會改變,即一直引用同一個對象,但這個對象可以發生改變。

2.3.4 可執行「宏替換」的final變量

對一個final變量來說,不管它是類Field、實例Field,還是局部變量,只要該變量滿足3個條件,這個final變量就不再是一個變量,而是相當於一個直接量

使用final修飾符修飾在定義該final變量時指定了初始值該初始值可以在編譯時就被確定下來示例:

public class test{ public static void main(String[] args) { final int a=5; System.out.println(a); }}

上面所示變量a其實不存在,在編譯時就轉換成System.out.println(5);

Java使用常量池來管理用過的字符串直接量,如String a=「java」;如果再定義String b=「java」;這時a==b 是true。

2.3.5 final方法

final修飾的方法不可被重寫。如果不希望子類重寫父類的某個方法,就可以使用final修飾該方法 。Object類的getClass就是一個final方法。

2.3.6 final 類

final修飾的類不可以有子類。如:java.lang.Math

2.3.7 不可變類(immutable)

創建實例後,該實例的Field是不可改變的。Java的8個包裝類和java.lang.String都是不可在。

使用private final修飾Field提供帶參數構造器,用於根據傳入參數來初始化類的Field僅為該類的Field提供getter方法,不要為該類的Field提供setter方法如果有必要,重寫Object類的hashCode和equals方法。2.3.8 緩存實例的不可變類

Java的Integer類,使用了緩存策略。在使用new構造對象時,返回全新的integer對象。如果使用valueOf創建Integer對象,則在創建該對象的同時,會緩存該方法創建的對象Integer只緩存-128到127之間的Integer對象,超過範圍的對象不會緩存。

如果程序經常使用某個不可變類的實例,則可以把該實例保存進緩存,減少系統開銷。

三、深入理解java的面向對象1. 一切皆對象,包裝類

在Java語言中,除了8個基本數據類型值,一切都是對象。對於8個基本的數據類型,Java也提供了包裝類:

基本數據類型包裝類byteByteshortShortintIntegerlongLongcharCharacterfloatFloatdoubleDoublebooleanBoolean

對象是Java程序的核心,所以Java裡的對象具有唯一性,每個對象都有一個標識來引用它,如果某個對象失去了標識,這個對象將變成垃圾。Java語言不允許直接訪問對象,而是通過對對象的引用來操作對象。

使用示例:

Float f1=new Float("4.56");Booean blObj = new Boolean(b1);

當包裝類創建失敗時,會引發

java.lang.NumberFormatException異常。

獲得包裝類的基本類型變量

int i = integerObject.intValue;

2. 類成員

Java類包含5種成員:

Field方法構造器初始化塊內部類(包括接口、枚舉)

類Field(static修飾)屬於整個類,當系統第一次準備使用該類時,系統會為該類Field分配內存空間。類Field開始生效,直到該類被卸載,所佔內存才會被垃圾回收機制回收。類Field生存範圍幾乎等同於該類的生存範圍。當類的初始化完成後,類Field也被初始化完成。

類Field既可通過類訪問,也可通過類的對象來訪問。通過類的對象來訪問類Field時,實際上訪問的不是該類所擁有的Field。而C#其實不允許通過對象訪問類Field。

3. 類的結構關係繼承整體->部分結構關係,也稱為組裝結構,這是典型的組合關係。Java語言通過在一個類裡保存另一個Java語言是純粹的面向對象的程序設計語言,這主要表現為Java完全支持面向對象的三種基本特徵:繼承、封裝、多態。Java語言完全以對象為中心,Java程序的最小程序單位是類,整個Java程序由一個一個的類組成。Java完全支持使用對象、類、繼承、封裝、消息等基本概念來進行程序設計,允許從現實世界中客觀存在的事物(即對象)出發來構造軟體系統,在系統構造中儘可能運行人類的自然思維方式。面向對象的方式實際上由:OOA(面向對象分析)OOD(面向對象設計)OOP(面向對象編程)

三個部分有機組成,其中OOA和OOD的結構需要使用一種方式來描述並記錄,目前業界統一採用UML(統一建模語言)來描述並記錄OOA和OOD的結果。

UML的2.0 一共包括13種類型的圖形。使用這13種圖形中的某些就可以很好地描述並記錄軟體分析、設計的摘要。通常而言,我們沒有必要為軟體系統繪製13種UML圖形,常用的UML圖形有用例圖、類圖、組件圖、部署圖、順序圖、活動圖和狀態圖。

4. 面向對象的基本特徵3.4.1 封裝(Encapsulation)

將對象的實現細節隱藏起來,然後通過一些公用方法來暴露該對象的功能

3.4.2 繼承(Inheritance)

面向對象實現軟體復用的重要手段,當子類繼承父類後,子類作為一種特殊的父類,將直接獲得父類的屬性和方法

3.4.3 多態(Polymorphism)

子類對象可以直接賦給父類變量,但運行時依然表現出子類的行為特徵,這意味著同一個類型的對象在執行同一個方法時,可能表現出多種行為特徵

3.4.4 抽象

忽略一個主題中與當前目標無關的那些方法,以便更充分地注意與當前目標有關的方面。抽象並不打算了解全部問題,而只是考慮部分問題。例如,考慮考察Person對象時,我們不可能在程序中把Person的所有細節都定義出來,通常只能定義Person的部分數據、部分行為特徵—而這些數據、行為特徵是軟體系統所關心的部分

3.4.5 其它功能對象是面向對象方法中最基本的概念,它的基本特點有:標識唯一性、分類性、多態性、封裝性、模塊獨立性好類是具有相同屬性、共同方法的一類事務。類的封裝性將各種信息細節隱藏起來,並通過公用方法來暴露該類對外所提供的功能,從而提高了類的內聚性,降低了對象之間的耦合性。對象間的這種相互合作機制協助進行,這樣的機制稱為「消息」,消息是一個實例與另一個實例之間相互通信的機制。在面向對象方法中,類之間共享屬性的機制稱為繼承。繼承具有傳遞性。繼承分為單繼承(一個繼承只允許有一個直接父類,即類等級為樹形結構)與多繼承(一個類允許有多個直接父類)。Java不支持多繼承。5. 抽象類3.5.1 抽象類的特性使用abstract修飾,抽象方法不能有方法體。抽象類不能被實例化,無法使用new創建實例,只能當作父類被繼承抽象類可以有Field、方法、構造函數、初始化塊、內部類、枚舉類含有抽象方法的類只能被定義成抽象類abstract不能用來修飾局部變量、構造函數static 和 abstract不能共同修飾同一個方法3.5.2 接口

抽象類是從多個類中抽象出來的模板,如果將這種抽象進行是更徹底,則可以提煉出一種更加特殊的抽象類——接口。接口層不能包含應運,接口裡所有方法都是抽象方法。

JAVA接口是一些方法特徵的集合,接口中只有方法的特徵沒有方法的實現,因此這些方法可以在不同的地方被實現並且具有完全不同的行為。當然,JAVA還允許在接口中定義常量。JAVA接口中的方法只能是abstract和public,接口中不能有構造器,可以有public、static和final屬性。接口將方法的特徵和方法的實現分割開來,這種分割體現在接口常常代表一種角色,它封裝與該角色相關的操作和屬性,而實現這個接口的類就是扮演這個角色的演員。一個接口可以被多個類實現,一個類可以實現多個接口。3.5.3 接口的定義

[修飾會] interface 接口中 extends 父接口1,父接口2...{ 常量定義; 抽象方法定義;}

示例:

package lee;public interface Output{ int MAC_CACHE_LINE=50; void out; void getData(String msg);}

3.5.4 接口的繼承

接口完全支持多繼承,一個接口可以有多個直接父接口。多個父接口排在extends後,用,隔開。

3.5.5 使用接口

接口不能用於創建實例,但接口中以用於聲明引用類型爆裂。當使用接口為聲明引用類型變量地,這個引用類型盤龍乃至其實現類的對象。除此之外,接口的主要用途不是被實現類實現。

示例:

interface Product{ int getProduceTime;}public class Printer implements Out , Product{ private String[] printDate=new String[MAX_CACHE_LINE]; private int dataNum=0; public void out{ while(dataNum>0){ System.out.println("印表機列印" printDate); System.arraycopy(printDate,1,printDate,0,--dataNum); } } public void getData(String msg){ if(dataNum >= MAX_CACHE_LINE){ System.out.println("輸出隊列已滿,添加失敗"); }else { printData[dataNum ]=msg; } } public int getProducteTime{ return 45; } public static void main(String[] args){ Output o = new Printer; o.getData("輕量級Java EE企業應用實戰"); o.getData("瘋狂Java 講義"); o.out; o.getData("瘋狂Android講義"); o.getData("瘋狂Ajax講義"); o.out; Product p = new Printer; System.out.println(p.getProduceTime); //所有接口類型的引用變量都可直接賦給Object類型的變量 Object obj=p; }}

3.5.6 接口和抽象類比較相同點接口和抽象類都不能被實例化接口 抽象類都可以包含抽象方法,繼承接口或繼承抽象類的普通子類都必須實現這些抽象方法差別接口體現的是一種規範。對接口實現者而言,接口規定了實現者必須對外提供哪些服務(以方法的形式為提供);對於接口調用者而言,接口規定了調用者可以調用哪些服務,以及如何去調用這些服務。…3.5.7 面向接口編程

可以實現簡單工廠模式、命令模式等。

6. 內部類3.6.1 非靜態內部類

public class OuterClass{}

3.6.2 靜態內部類

public class StaticInnerClassTest{ private int prop1=5; private static int prop2=9; static class StaticInnerClass{ private static int age; public void accessOuterProp{ System.out.println(prop1); System.out.println(prop2); } }}

3.6.3 局部內部類

定義在代碼中間

public class LocalInnerClass{ public static void main(String[] args){ class InnerBase{ int a; } class InnerSub extends InnerBase{ int b; } InnerSub is=new InnerSub; is.a=5; is.b=8; System.out.println(is.a "," is.b"); }}

3.6.4 匿名內部類

interface Product{ public double getPrice; public String getName;}public class AnonymousTest{ public void test(Product p){ System.out.println("購買了一個" p.getName ",花掉了" p.getPrice); public static void main(String[] args){ AnonymousTest ta = new AnonymousTest; ta.test(new Product{ public double getPrice{ return 567.8; } public String getName{ return "AGP"; } }) } }}

3.6.5 閉包和回調

閉包(Closure)是一種能被調用的對象,它保存創建它的作用域信息。Java7沒有顯式支持閉包,但可以把非靜態內部類當成面向對象領域的閉包。通過這種仿閉包的非靜態內部類,就可以很方便地實現回調功能。

interface Teachable{ void work;}public class Programmer{ private String name; public Programmer{} public Programmer(String name){ this.name=name; } //...getter & setter public void work{ System.out.println(name "doing..."); }}public class TeachableProgrammer extends Programmer implements Teachable{ public void work{ System.out.println(getName "doing ..."); }}

3.6.6 lambda實現匿名類

java8開始支持lambda表達式,可以看成一種閉包,允許把函數當成參數使用,是面向函數式編程的思想。lambda表達式語法:

(paramters) -> expression;

(paramters) -> {statements;} 展開如: (Type1 param1, Type2 param2, Type2 param2, ...) -> { statement1; statement2; statement3; ... return statementX; }

實例:

//匿名內部類寫法 new Thread(new Runnable { @Override public void run { System.out.println("內部類寫法"); } }).start;

改用lambda:

//lambda 寫法new Thread( -> System.out.println("lambda寫法")).start;

lambda表達式特徵

可選類型聲明:不需要聲明參數類型,編譯器可以統一識別參數值。可選的參數圓括號:一個參數無需定義圓括號,但多個參數需要定義圓括號。可選的大括號:如果主體包含了一個語句,就不需要使用大括號。可選的返回關鍵字:如果主體只有一個表達式返回值則編譯器會自動返回值,大括號需要指定明表達式返回了一個數值。

幾個示例:

//入參為空 TestDemo no_param = -> "hi, no param"; TestDemo no_param2 = -> { return "hi, no param"; }; System.out.println(no_param.hi); //單個參數 TestDemo2 param = name -> name; TestDemo2 param2 = name -> { return name;}; System.out.println(param.hei("hei, grils")); //多個參數 TestDemo3 multiple = (String hello, String name) -> hello " " name; //一條返回語句,可以省略大括號和return TestDemo3 multiple2 = (hello, name) -> hello name; //多條處理語句,需要大括號和return TestDemo3 multiple3 = (hello, name) -> { System.out.println("進入內部"); return hello name; }; System.out.println(multiple.greet("hello", "lambda"));

7. 枚舉類

public class Season{ private final String name; private final String desc; public static final Season SPRING=new Season("春天",""); public static final Season SUMMBER=new Season("夏天",""); public static final Season FALL=new Season("秋天",""); ... public static Season getSeason(int seasonNum){ switch(seasonNum){ case 1: return SPRING; case 2: return SUMMBER; ... } } private Season(String name,String desc){ this.name=name; this.desc=desc; } public String getName{ return this.name; } public String getDesc { return this.desc; }}

使用

public class SeasonTest{ public SeasonTest(Season s) { System.out.println(s.getName); } public static void main(String[] args) { new SeasonTest(Season.FALL); }}

3.7.1 使用enum 枚舉類SeasonEnum.java

public enum SeasonEnum{ SPRING,SUMMBER,FALL,WINTER;}

EnumTest.java

public class EnumTest{ public void judge(SeasonEnum s) { switch(s) { case SPRING: System.out.println("描述"); break; ... } } public static void main(String[] args) { for(SeasonEnum s:SeasonEnum.values){ System.out.println(s); } new EnumTest.judge(SeasonEnum.SPRING); }}

java.lang.Enum類提供了以下方法:

int compareTo(E o)String nameint ordinalString toStringpublic static T valueOf(Class enumType,String name)3.7.2 枚舉類的Field,方法 和構造函數

枚舉類也可以定義Field、方法。枚舉為的實例只能是枚舉值,不能隨意通過new創建枚舉類對象。

在setName裡可以對賦值進行驗證。

3.7.3 實現接口的枚舉類

枚舉類也可以實現一個或多個接口。與普通類實現一個或多個接口完全一樣,枚舉類實現一個或多個接口時,也需要實現該接口所包含的方法。

8. 對象的this引用

this關鍵字總是指向調用該方法的對象。根據this出現位置的不同,this作為對象的默認引用有兩種情形:

構造器中引用該構造器正在初始化的對象在方法中引用調用該方法的對象this關鍵字最大的作用就是讓類中一個方法,訪問該類裡的另一個方法或Field。但要注意的是,在static修飾的方法裡不能使用this引用,且靜態成員不能直接訪問非靜態成員。

有些時候this可以省略,編譯器會自動在引用內部方法時加上this.classname.方法名。Java允許使用對象來調用static修飾的Field方法,但應避免這樣使用,現代的IDE一般會給出報警。

9. 對象的方法3.9.1 參數值的傳遞方式

Java的方法參數傳遞只有一種方式:值傳遞,這是因為Java沒有指針的概念。正如前面提到過的,Java的一個對象可以拆為兩部分:

指向對象的變量名,存在棧中對象真正內容,存在堆中

當把一個對象作為參數時,傳遞的值是對象的引用地址,即棧裡的變量複製了,但指向的堆仍然沒有變。為了便於理解,往往可以認為Java傳遞複雜參數時(非8種基本類型)採用的是按引用傳值,但要注意面試時不能這樣講。

3.9.2 形參個數可變的方法

public class Varargs{ public static void test(int a,String... books) { for(String tmp : books) { System.out.println(tmp); } } public static void main(String[] args) { test(5,"參數2","參數3"); }}

11. 繼承3.11.1 super限定

如果需要在子類方法中調用父類被覆蓋的實例方法,則可使用super限定來調用父類被覆蓋的實例方法:

public void callOverrideMethod{ super.fly;}

3.11.2 多態

Java引用變量有兩個類型:一個是編譯時類型,一個是運行時類型。如果編譯與運行時類型不一到處,就可能出現所謂的多態(Polymorphism)

3.11.3 instanceof運算符

instanceof運算符的前一個操作數通常是一個引用類型變量,後一個操作數通常是一個類(也可以是接口,可以把接口理解成一種特殊的類),它用於判斷前面的對象是否是後面的實例,或者其子類,實現類的實例。

3.11.4 繼承與組合

初始化塊初始化塊是Java類裡可出現的第4種成員,一個類裡可以有多個初始化塊,相同類型的初始化塊之間有順序:前面定義的初始化塊先執行,後面定義的初始化後執行

public class Person{ { ; //先執行 } { ; //2 } public Person { ; //3 } public static void main(String[] args) { new Person; }}

初始化塊只在創建Java對象時隱匿執行,而且在構造函數之前執行。

12. 靜態初始化塊

在類初始化階段執行靜態初始化塊,因此比普通初始化塊先執行。靜態初始化塊會一直上溯到頂父類靜態初始化類先執行,最後才執行該類的靜態初始化塊。

JDK1.5後新增引入靜態成員:

import static java.lang.Math.*;

可以引入所有靜態Field和方法。

13. 列印對象和toString方法

class Person{}Person p=new Person;//下面兩句效果是一樣的System.out.println(p);System.out.println(p.toString);

所有Java對象都有toString實例方法Java對象都可以與字符串進行連接運算Object類提供的toString方法總是返回該對象實現類的「類名 @ hashCode」toString可以重寫14. == 和 equals

Java程序中測試兩個變量是否相等有兩種方式。

==判斷兩個變量是否相等時,如果兩個變量是基本類型變量,且都是數值類型(不一定要求數據類型嚴格相同),則只要兩個變量的值相等,即返回true對於兩個引用類型的變量,必須指向同一個對象時,==才返回true==不可用於比較類型上沒有父子關係的兩個對象15. 「hello」 和 new String(「hello」)「hello」,JVM將會使用常量池來管理這些字符串當使用new String(「hello」)時,JVM會先使用常量池來管理"hello"直接量,再用String類的構造器來創建一個新的String對象,新創建的String對象被保存在堆內存中。new String(「hello」)一共產生兩個對象。

常量池(constant pool)專門用於管理在編譯期被確定並被保存在已編譯的.class文件中的一些數據。它包括了關於類、方法、接口中的常量,還包括字符串常量。

JVM常量池保證相同的字符串(在編譯期間可運算的值)直接量只有一個,不會產生多個副本。

使用new String創建的字符串對象是運行時創建出來的,它被保存在運行時內存區內(堆內存),不會放入常量池中。

要判斷兩個引用變量的值是否相等時,可以使用.equals判斷。equals方法也可以重寫。

16. 自動裝箱與自動拆箱(Autoboxing AutoUnboxing)

從JDK1.5之後,提供了自動裝箱(Autoboxing)和自動拆箱(AutoUnboxing)功能。即:

Integer intObj=5;boolean b = (Boolean)boolObj;

包裝類的parseXxx(String)靜態方法提供了字符串值轉換為基本類型的值的方法;也可以使用包裝類的構造器實現String 類提供了多個重載valueOf方法,用於將基本類型變量轉換成字符串包裝類的實例可與數值類型的值進行比較而兩個包裝類的實例進行比較的情況比較複雜,只有兩個包裝類引用指向同一個對象時才會返回true自動裝箱的特例

Integer a=2;Integer b=2;a==b //trueInteger a=128;Integer b=128;a==b //false

其原因是-128~127之間的整數自動裝箱成一個Integer實例時,會放入一個名為cache的數組中緩存起來。不在這個範圍內的,系統總是重新創建一個Integer實例。

Java7 增強了包裝類的功能,為所有包裝類提供了一個靜態的compare(xxx var1,xxx val2)方法,以方便進行值比較四、類的設計原則一、類的設計原則1.單一職責原則(SRP)

每個類只擔任一個職責,每個類應只有一個引起它變化的原因。一個類只負責一項職責,應該僅有一個引起它變化的原則

2.裡氏替換原則(LSP)和依賴倒置原則(DIP)

子類可以擴展父類的功能,但不能改變父類原有的功能

子類可以實現父類的抽象方法,但不能覆蓋父類的非抽象方法。子類中可以增加自己特有的方法。當子類的方法重載父類的方法時,方法的前置條件(即方法的形參)要比父類方法的輸入參數更寬鬆。當子類的方法實現父類的抽象方法時,方法的後置條件(即方法的返回值)要比父類更嚴格。3.依賴倒置原則(DIP)

高層模塊不應該依賴低層模塊,二者都應該依賴其抽象;抽象不應該依賴細節;細節應該依賴抽象。即針對接口編程,不要針對實現編程依賴倒置原則的中心思想是面向接口編程,傳遞依賴關係有三種方式,以上的說的是是接口傳遞,另外還有兩種傳遞方式:構造方法傳遞和setter方法傳遞。

低層模塊儘量都要有抽象類或接口,或者兩者都有。變量的聲明類型儘量是抽象類或接口。使用繼承時遵循裡氏替換原則。4.接口隔離原則(ISP)

建立單一接口,不要建立龐大臃腫的接口,儘量細化接口,接口中的方法儘量少。也就是說,我們要為各個類建立專用的接口,而不要試圖去建立一個很龐大的接口供所有依賴它的類去調用。在程序設計中,依賴幾個專用的接口要比依賴一個綜合的接口更靈活。接口是設計時對外部設定的「契約」,通過分散定義多個接口,可以預防外來變更的擴散,提高系統的靈活性和可維護性。

5.開閉原則(OCP)

開閉原則要求軟體有一個良好的基本結構,確保面對「變化」的時候,僅僅擴展而不是修改現有對象的組織框架就可以隨需而動。抽象化是關鍵,定義抽象類或接口,使其可以有很多的具體實現預見所有的需要,在任何情況下都不再修改上層商業邏輯。

抽象類的用法:

抽象類應當擁有儘可能多的共同代碼在一個抽象類到多個具體類的繼承關係中,共同的代碼應當儘量移動到抽象類中,這樣可以提高代碼利用率。當需要修改這些共同的代碼時,設計師只需要修改一個地方。抽象類應當擁有儘可能少的數據與代碼移動方向相反,數據的移動方向是從抽象類到具體類,一個數據對象無論是否使用都會佔用資源,因此數據應當儘量放到具體類或等級結構的低端。五、對象與垃圾回收

垃圾回收只負責回收堆內存中的對象,不會回收任何物理資源程序無法精確控制垃圾回收的運行垃圾回收前,會調用finalize方法,該方法可能使該對象重新復活,從而導致垃圾回收機製取消回收

1. 對象在內存中的狀態可達狀態:一個對象被創建後,若有一個以上的引用變量引用它,就處理可達狀態可恢復狀態:不再有變量引用,即進入了可恢復狀態不可達狀態:已經調用finalize後依然沒有使該對象變成可達狀態2. 強制垃圾回收調用System.gc靜態方法調用Runtime.getRuntime.gc實例方法

測試:

public class GcTest { public static void main(String[] args){ for(int i=0;i<4;i ){ new GcTest; } } public void finalize { System.out.println("系統正在清理資源"); }}

可以看到finalize不會被調用。而如果:

public class GcTest { public static void main(String[] args){ for(int i=0;i<4;i ){ new GcTest; Runtime.getRuntime.gc; } } public void finalize { System.out.println("系統正在清理資源"); }}

則finalize會被調用。使用java -verbose:gc GcTest查看垃圾回收後的提示信息:

但上面語句只是建議垃圾回收,系統仍有可能不立即進行垃圾回收。

3. finalize方法不要調動調用對象的finalize方法finalize方法調用時間有不確定性,不要把它當成一定會被執行的方法當JVM執行可恢復對象的finalize方法時,可能使對象或系統中其它對象重新變成可達狀態當JVM執行finalize方法出現異常時,垃圾回收機制不會報告異常,程序繼續執行。

System和Runtime類提供了runFinalization方法,可以強制垃圾回收機制調用系統中可恢復對象的finalize方法

4. 對象的軟、弱、虛引用六、使用JAR文件

常用命令:

1. 創建JAR文件

jar cf test.jar test //test是目錄

2. 創建JAR文件並顯示壓縮過程

jar cvf test.jar test

3. 不使用清單文件

jar cvfM test.jar test

4. 自定義清單文件內容

jar cvfm test.jar manifest.mf test

5. 查看jar包內容

jar tf test.jar

6. 查看JAR包詳細內容

jar tvf test.jar

7. 解壓縮

jar xf test.jar

8. 帶提示信息解壓縮

jar xvf test.jar

9. 更新JAR文件

jar uf test.jar Hello.class

10. 更新時顯示詳細信息

jar uvf test.jar Hello.class

11. 創建可執行的jar包

程序發布的方式:

使用平臺相關的編譯器,使用第三方編譯器為應用編輯一個批處理,如windows

java package.MainClass

start javaw package.MainClass

將一個應用程式製作成可執行的JAR包,通過JAR包來發布應用程式

jar cvfe test.jar Test *.class

該命令把目錄下的*.class壓縮到test.jar,並指定使用Test類為程序入口。運行的方法:

java -jar test.jarjavaw test.jar

七、UML(統一建模語言)介紹

面向對象軟體開發需要經過OOA(面向對象分析)、OOD(面向對象設計)和OOP(面向對象編程)三個階段,OOA對目標系統進行分析,建立分析模型,並將之文檔化;OOD用面向對象的思想對OOA的結果進行細化,得出設計模型。OOA和OOD的分析、設計結果需要統一的符號來描述、交流並記錄,UML就是這種用於描述、記錄OOA和OOD結果的符號表示法。面向對象的分析與設計方法在20世紀80年代末至90年代出現了一個高潮,UML是這個高潮的產物。在些期間出現了三種具有代表性的表示方法。Booch是面向對象方法最早的倡導者之一,他提出了面向對象軟體工程的概念。Booch1993表示法比較適合於系統的設計和構造。Rumbaugh等人提出了面向對象的建模技術(OMT)方法,採用面向對象的概念,並引入了各種獨立於語言的表示符。這種方法用對象模型、動態模型、功能模型和用例模型共同完成對整個系統的建模,所定義的概念和符號可用於軟體開發的分析、設計和實現的全過程,軟體開發人員不必在開發過程的不同階段進行概念和符號的轉換。OMT-2特別適用於分析和描述以數據為中心的信息系統。Jacobson於1994年提出了OOSE方法,其最大特點是面向用例(Use-Case),並在用例的描述中引入了外部角色的概念。用例的概念是精確描述需求的重要武器,但用例貫穿於整個開發過程,包括對系統的測試和驗證。OOSE比較適合支持商業工程和需求分析。UML統一了Booch、Rumbaugh和Jacobson的表示方法,而且對其進行了進一步的發展,並最終統一為大眾所接受的標準建模語言。UML是一種定義良好、易於表達、功能強大且普遍適用的建模語言,它的作用域不限於支持面向對象的分析與設計,還支持從需求分析開始的軟體開發全過程。UML的大致發展過程如圖所示:

UML2.0一共包括13種正式圖形:

活動圖 activity diagram類圖 class diagram通信圖 communication diagram組件圖 component diagram複合結構圖 composite structure diagram部署圖 deplyment diagram交互概觀圖 interactive overview diagram對象圖 object diagram包圖 package diagram順序圖 sequence diagram狀態機圖 state machine diagram定時圖 timing diagram用例圖 use case diagram很少有一個軟體系統在分析、設計階段對每個細節都使用13種圖形來表現。1. 用例圖

用例圖用於描述系統提供的系列功能,而每個用例則代表系統的一個功能模塊。用例圖的主要目的是幫助開發團隊以一種可視化的方式理解系統的需求功能,用例圖對系統的實現不作任何說明,僅僅是系統功能的描述。用例圖包括用例(以一個橢圓表示,用例的名稱放在橢圓的中心或橢圓下面)、角色(Actor,也就是與系統交互的其它實體,以一個人形符號表示)、角色和用例之間的關係(以簡單的線段來表示),以及系統內用例之間的關係。用例圖一般表示出用例的組織關係—要麼是整個系統的全部用例,要麼是完成具體的一組用例。下面是BBS系統的部分用例示意圖。

用例圖通常用於表達系統或者系統範疇的高級功能。用例圖主要在需求分析階段使用,用於描述系統實現的功能,方便與客戶交流,保證系統需求的無二性,用實例圖表示系統外觀,不要指望用例圖和系統的各個類之間有任何聯繫。不要把用例做得過多,過多的用例將導致難以閱讀,難以理解;儘可能多地使用文字說明。

2. 類圖

類圖是最古老、功能最豐富、使用最廣泛的UML圖。類圖表示系統中應該包含哪些實體,各實體之間如何關聯;換句話說,它顯示了系統的靜態結構,類圖可用於表示邏輯類,邏輯類通常就是業務人員所談及的事物種類。類在類圖上使用包含三個部分的矩形來描述,最上面的部分顯示類的名稱,中間部分包含類的屬性,最下面的部分包含類的方法。類之間有三種基本關係:

關聯(包括聚合、組合)泛化(與繼承同一個概念)依賴關聯

關聯具有一定的方向性,如果僅能從一個類單方向地訪問另一個類,則被稱為單向關聯;如果兩個類可以互相訪問對象,則稱為雙向關聯。一個對象能訪問關聯對象的數目被稱為多重性。關聯使用一條實線表示,帶箭頭的實線表示單向關聯。關聯關係包括兩種特例:聚合和組合。它們都有部分和整體的關係,但通常認為組合比聚合更加嚴格。如:

學生既可以是籃球俱樂部的成員,也可以是書法俱樂部的成員,稱為聚合。使用空心菱形框的實線表示當某個實體組合成另一個實體時,該實體則不能同時是一個實體的部分,使用實心菱形框表示:

圖中描述Teacher與Student之間的關聯關係:

它們是雙向關聯關係,而且使用了多重性來表示Teacher和Student之間存在1:N的關聯關係(1…*表示可以是一個到多個),即一個Teacher實體可以有1個或多個關聯的Student實體;Student和BasketBallClud存在聚合關係,即1個或多個Student實體可以聚合成一個BascketBallClud實體;而Arm和Student之間存在組合關係。2個Arm實體組合成一個Student實體。泛化

泛化與繼承是同一個概念,都是指子類是一種特殊的父類,類與類之間的繼承關係是非常普遍的,繼承關係使用帶空心三角形的實線表示。從下圖可以看出,Student和Person類之間的繼承關係。

依賴

如果一個類的改動會導致另一個類的改動,則稱兩個類之間存在依賴。依賴關係使用帶箭頭的虛線表示,其中箭頭指向被依賴的實體。依賴的常見可能原因如下:

改動的類將消息發給另一個類改動的類以另一個類作為數據部分改動的類以另一個類作為操作參數通常而言,依賴是單向的,尤其是當數據表現和數據模型分開設計時,數據表現依賴於數據模型。例如:JDK基礎類庫中的JTable和DefaultTableModel。

3. 組件圖

對於現代的大型應用程式而言,通常不只是單獨一個類或單獨一組類所能完成的,通常會由一個或多個可部署組件組成。對Java程序而言,可復用的組件通常打包成一個JAR、WAR等文件;對C/C 應用而言,通常是DLL動態連結庫文件。組件圖提供系統的物理視圖,它的用途是顯示系統中的軟體對其它軟體組件的依賴關係。組件圖可以在一個非常高的層次上顯示,僅顯示系統中粗粒度的組件,也可以在組件包層次上顯示。組件圖通常包含組件、接口和Port等圖元,UML使用帶插頭符號的矩形來表示組件,使用圓圈代表接口,使用位於組件邊界上的小矩形代表Port。組件的接口表示它能對外提供的服務規範,這個接口通常有兩種表現形式:

用一條實線連接到組件邏輯的圓圈表示使用位於組件內部的圓圈表示組件除了可以對外提供服務接口之外,還可能依賴於某個接口,組件依賴於某個接口使用一條帶半圓的實現來表示。如圖一個簡單的Order組件,對外提供一個Payable接口,該組件需要依賴於一個CustomerLookup接口——通常這個CustomerLookup接口也是系統中已有的接口。

4. 部署圖

部署圖用於描述軟體系統如何部署到硬體環境中,它的用途是顯示軟體系統不同的組件將在何處物理運行,以及它們將如何彼此通信。

5. 順序圖

順序圖顯示具體用例(或者是用例的一部分)的詳細流程,並且顯示流程中不同對象之間的調用關係,同時還可以很詳細地顯示對不同對象的不同調用。順序圖描述了對象之間的交互(順序圖和通信圖都被稱為交互圖),重點在於描述消息及其時間順序。順序圖有兩個維度:垂直維度,以發生的時間順序顯示消息/調用的序列;水平維度,顯示消息被發送的對象實例。順序圖的頂部每個框表示每個類的實例(對象),框中的類實例名稱和類名稱之間用冒號或空格來分隔,例如myReportGenerator:ReportGenerator。如果某個類實例向另一個類實例發送一條消息,則繪製一條指向接收類實例的帶箭頭的連線,並把消息/方法的名稱放在連線上面。對於某些特別重要的消息,還可以繪製一條帶箭頭的指向發起類實例的虛線,將返回值標註在虛線上,繪製帶返回值的信息可以使得序列圖更易於閱讀。用戶登錄順序圖:

當繪製順序圖時,消息可以向兩個方向擴展,消息穿梭在順序圖中,通常應該把消息發送者與接收者相鄰擺放,儘量避免消息跨越多個對象。對象的激活期不是其存在的時間,而是它佔據CPU的執行時間,繪製順序圖時,激活期要精確。

6. 活動圖

活動圖和狀態機圖都被稱為演化圖。

7. 狀態機圖

上圖描繪了Hibernate 實體具有3個狀態:瞬態、持久化和脫管。繪製狀態機圖時應該保證對象只有一個初始狀態,可以有多個終結狀態。狀態要表示對象的關鍵快照,有重要的實際意義,無關緊要的狀態則無須考慮,繪製狀態機時事件和方法要明確。狀態機圖擅長表現單個對象的跨用例行為,對於多個對象的交互行為應該考慮採用順序圖,不要對系統的每個對象都畫狀態機圖,只對真正需要關心各個狀態的對象才繪製狀態機圖。

本文學習資源來自《瘋狂Java講義》。UML部分摘自一本書忘了名稱,如有侵權請告知,我將立刻予以刪除。

,
同类文章
葬禮的夢想

葬禮的夢想

夢見葬禮,我得到了這個夢想,五個要素的五個要素,水火只好,主要名字在外面,職業生涯良好,一切都應該對待他人治療誠意,由於小,吉利的冬天夢想,秋天的夢是不吉利的
找到手機是什麼意思?

找到手機是什麼意思?

找到手機是什麼意思?五次選舉的五個要素是兩名士兵的跡象。與他溝通很好。這是非常財富,它擅長運作,職業是仙人的標誌。單身男人有這個夢想,主要生活可以有人幫忙
我不怎麼想?

我不怎麼想?

我做了什麼意味著看到米飯烹飪?我得到了這個夢想,五線的主要土壤,但是Tu Ke水是錢的跡象,職業生涯更加真誠。他真誠地誠實。這是豐富的,這是夏瑞的巨星
夢想你的意思是什麼?

夢想你的意思是什麼?

你是什​​麼意思夢想的夢想?夢想,主要木材的五個要素,水的跡象,主營業務,主營業務,案子應該抓住魅力,不能疏忽,春天夢想的吉利夢想夏天的夢想不幸。詢問學者夢想
拯救夢想

拯救夢想

拯救夢想什麼意思?你夢想著拯救人嗎?拯救人們的夢想有一個現實,也有夢想的主觀想像力,請參閱週宮官方網站拯救人民夢想的詳細解釋。夢想著敵人被拯救出來
2022愛方向和生日是在[質量個性]中

2022愛方向和生日是在[質量個性]中

[救生員]有人說,在出生88天之前,胎兒已經知道哪天的出生,如何有優質的個性,將走在什麼樣的愛情之旅,將與生活生活有什么生活。今天
夢想切割剪裁

夢想切割剪裁

夢想切割剪裁什麼意思?你夢想切你的手是好的嗎?夢想切割手工切割手有一個真正的影響和反應,也有夢想的主觀想像力。請參閱官方網站夢想的細節,以削減手
夢想著親人死了

夢想著親人死了

夢想著親人死了什麼意思?你夢想夢想你的親人死嗎?夢想有一個現實的影響和反應,還有夢想的主觀想像力,請參閱夢想世界夢想死亡的親屬的詳細解釋
夢想搶劫

夢想搶劫

夢想搶劫什麼意思?你夢想搶劫嗎?夢想著搶劫有一個現實的影響和反應,也有夢想的主觀想像力,請參閱週恭吉夢官方網站的詳細解釋。夢想搶劫
夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂

夢想缺乏缺乏紊亂什麼意思?你夢想缺乏異常藥物嗎?夢想缺乏現實世界的影響和現實,還有夢想的主觀想像,請看官方網站的夢想組織缺乏異常藥物。我覺得有些東西缺失了