1. 程式人生 > 其它 >封裝,建構函式,UML

封裝,建構函式,UML

技術標籤:學習總結java

這裡寫目錄標題

封裝

封裝是指將現實世界中存在的某個客體的屬性與行為繫結在一起,並放置在一個邏輯單元內。在面向物件程式設計方法中,封裝是指一種將抽象性函式介面的實現細節部分包裝、隱藏起來的方法。

  • 既可以實現對客體屬性的保護作用,又可以提高軟體系統的可維護性
  • 只要使用者介面不改變,任何封裝體內部的改變都不會對軟體系統的其他部分造成影響

封裝隱藏實現細節,並對外提供了公共的訪問方式

  • 封裝可以被認為是一個保護屏障,防止該類的程式碼和資料被外部類定義的程式碼隨機訪問
  • 要訪問該類的程式碼和資料,必須通過嚴格的介面控制。
  • 封裝最主要的功能在於能修改自己的實現程式碼,而不用修改那些呼叫程式碼的程式片段
  • 適當的封裝可以讓程式碼更容易理解與維護,也加強了程式碼的安全性。
    方法或者類都是一個封裝體。Java的基本封裝單元就是類class,組成類的程式碼或資料稱為類的成員。

封裝的好處

  • 良好的封裝能夠減少耦合
  • 類內部的結構可以自由修改
  • 可以對成員進行更精確的控制
  • 隱藏資訊,實現細節
    類定義規則:要求類內高內聚,類間弱耦合
  • 封裝確實可以使容易地修改類的內部實現,而無需修改使用了該類的客戶程式碼

抽象

抽象是人類解決問題的基本法寶。良好的抽象策略可以控制問題的複雜程度,增強系統的通用性和可擴充套件性抽象主要包括過程抽象和資料抽象

  • 過程抽象是將問題域中具有明確功能定義的操作抽取出來,並將其作為一個實體看待
  • 資料抽象是較過程抽象更高級別的抽象方式,將描述客體的屬性和行為繫結在一起,實現統一的抽象,從而
    達到對現實世界客體的真正模擬

範圍限定詞

private 私有的
protected 受保護的
預設(就是沒有限定詞、package限制不能寫成default)

public 公共的

限定類

public class A{ //外部類
class B{} //這個類定義在類A中,所以叫做內部類
}

public class A{} 外部的獨立類上可以使用的範圍限定詞有public和預設兩種;內部類可以使用4大範圍限定詞中的任意一個。

  • 在一個.java檔案中可以定義無數個class,但是隻能定義一個public class,而且要求檔名稱和public class類名稱必須一致,包括大小都必須一致

public類可以在任意包中進行引用,沒有範圍限定詞的class則只能在同包中訪問

  • 如果類位於預設包中,則只能同包訪問,其它位置不能訪問【不管是public class或者預設 class】

屬性上的範圍限定詞

public 表示到處可見
protected表示同包或者子類中可見
預設表示同包可見
private當前類內可見

public class B1 {
public int ab1; //公共屬性
}
B1 aa=new B1();
System.out.println(aa.ab1);
public class B1 {
protected String ab2;
}
//同包中可以直接訪問,不同包中不能直接訪問,但是子類中可以方法
B1 b=new B1();
System.out.println(b.ab2);
//子類,不同包
public class T extends B1{
public void pp() {
System.out.println(ab2); ///可以訪問
}
public static void main(String[] args) {
B1 aa=new B1();
System.out.println(aa.ab2); //語法報錯,不能訪問
}
}
public class B1 {
double ab3;
}
//同包可以直接訪問
B1 b=new B1();
System.out.println(b.ab3);
//不同包
public class T extends B1{
public void pp() {
System.out.println(ab3);//語法報錯
}
public static void main(String[] args) {
B1 aa=new B1();
System.out.println(aa.ab3); //語法報錯
}
}

方法上的範圍限定詞

public class A{
public void pp(){} //public就是範圍限定詞,其中可以使用4箇中任何一個
}

同屬性上的範圍限定詞一致
public 表示到處可見
protected表示同包或者子類中可見處可見
預設表示同包可見
private當前類內可見

記憶方法在這裡插入圖片描述

package和import

在Java中為了方便開發,會將多個功能相似的類放在一個組內,而這個組就是包,包就像一個目錄結構package將一些類組合在一起,起到名空間的作用,在一定程度上可以避免出現類名衝突的問題.

  • package com.yan;定義了一個包,包和資料夾路徑沒有關係,但是實際上可以看到一些對應的效果,這個包對應的資料夾為com/yan/

包名稱一般採用域名反轉的方式進行定義lanou.com為com.lanou,包名稱採用全小寫

在Java中呼叫其它包中的公共類時,必須告知具體類的位置。使用類名稱有兩種寫法:全名和簡名

  • 全名寫法: java.util.Date now=new java.util.Date();
  • 簡名寫法
import java.util.Date;
public class B1 {
public Date now=new Date();
}
  • 特例
 package com.yan;
public class B1 {
public A1 aa=new A1(); //同包的類不要import語句
}

注意:在同一個包中的類名稱不允許衝突
注意:預設包中的類只能在預設包中進行呼叫,其它包中不能訪問預設包中的類。預設包中的類可以訪問命名包中的類

Java虛擬機器在執行時,系統會自動匯入java.lang包,只要程式用到這個包的類時,不需要匯入,要使用其它包時,都必須手工匯入。例輸出使用的System.out.println的System類實際上全名為java.lang.System

  • 類路徑CLASSPATH就是讓系統找到需要匯入的類

封裝特點

隔離變數。一般建議對於屬性採用:私有屬性,共有的get/set方法的形式進行定義

public class B1 {
//私有屬性
private String name;
private int age;
//共有的get/set方法,get方法稱為讀取器,set方法稱為設定器
public int getAge() {//如果手寫方法請注意命名規則
return age;
}
public void setAge(int age) {//可以新增驗證邏輯
if(age>0 && age<18)
this.age = age;
else this.age=0;
}
public void setName(String name) {
this.name = name;
}
}
  • 不是所有的屬性都有get/set方法,取決於是否允許讀寫;允許讀則只有get,沒有set;如果只允許寫,則只有set,沒有get
  • 針對boolean型別,不是Boolean型別的特殊命名規則
public class B1 {
//私有屬性
private boolean sex;
//共有的get/set方法,get方法稱為讀取器,set方法稱為設定器
public boolean isSex() { //注意get方法的命名,如果需要生成get方法可以使用Boolean來聲return sex;
}
public void setSex(boolean sex) {
this.sex = sex;
}
}

便於使用,需要匯入
提高複用
提高安全性

建構函式

建構函式是一種特殊的方法。主要用來在建立物件時初始化物件,即為物件成員變數賦初始值,總與new運算子一起使用在建立物件的語句中。

  • 一個類可以有多個建構函式 ,可根據其引數個數的不同或引數型別的不同來區分它們,即建構函式的過載
  • 不算成員方法
    使用語法可建立物件: new 建構函式();
public class B1 {
//方法名稱和類名稱一致,包括大小寫
//方法沒有返回值型別的宣告
public B1() {}
public B1(int k) {}
//在一個類中允許方法同名【方法過載】,要求引數不同:型別、個數、順序【引數型別不同】
public int B1(){}//從語法的角度上說是正確的,同時可以直接呼叫,不是構造器
}
//構造器方法不能直接呼叫,只能通過new運算子間接呼叫,例如new B1()呼叫無參構造器。。
public class A1 {
public A1() {//構造器中可以有return語句,但是不能return任何值
System.out.println("no argument constructor..");
}
public void A1() { //因為有返回值型別宣告,所以不是構造器,是普通的成員方法
System.out.println("no argument method...");
}
}
//呼叫
A1 aa=new A1();//呼叫無參構造
aa.A1();//呼叫A1方法

建構函式特點

  • 函式名與類名相同,包括大小寫
  • 不用定義返回值型別,沒有具體的返回值,但不用寫void
  • 一個類可以有多個不同的構造器,但是引數一定不能相同
  • 構造器不能直接呼叫,總是和new運算子一起被呼叫

在建構函式前面加上返回值就只是一般函數了,不是構造器

建構函式作用

給物件進行初始化
public class Student{
private String name;
private int age;
//出現了2個同名的name變數,一個成員變數,一個區域性變數。可以使用this進行區分,this.name標識成
員變數,直接使用name表示區域性變數。
public Student(String name,int age){
this.name=name;
this.age=age;
System.out.println(name);//按照就近原則,這個name用於指代區域性變數
}
}
//呼叫
Student s1=new Student("xiaozeng",18); //如果類中定義了多個構造器,具體執行哪個構造器,是按照引數型別進行最佳匹配



public class A1 {
public A1() {
System.out.println("no argument");
}
public A1(String a1) {
System.out.println("String");
}
public A1(String a1,short b1) {
System.out.println("string short");
}
public A1(String a1,int b1) {
System.out.println("string int");
}
public static void main(String[] args) {
A1 aa=new A1("123",(short)12);
}
}

使用下列語法可建立物件: new 建構函式();
當使用new運算子時自動進行呼叫,但是構造方法不能直接呼叫

  • 關鍵字 new 通常稱為建立運算子,用於分配物件記憶體,並將該記憶體初始化為預設值
    **成員變數有預設值,區域性變數如果不賦值則沒有預設值
    ****簡單型別中的數值型別預設為0,char型別預設’\0’,boolean型別預設false
    ****引用型別預設null
  • 一旦 new 完成分配和初始化記憶體,它就將呼叫建構函式來執行物件初始化
    當定義Java類時沒有定義構造器,則Java自動為類自動提供無參構造器, 將成員變數的值初始化為預設值
 public class A{}//沒有定義構造器,則系統自動提供一個無參的預設構造器
//構建物件
A a=new A();

一旦建立了自己的建構函式,預設的建構函式將不復存在

public class A{
public A(int k){}
}
//構建物件
A a=new A();//語法錯誤,因為A類中沒有無參構造器,解決方法則是在class A中新增程式碼public A(){}

建立物件都必須通過建構函式初始化

每個類至少有一個構造方法。

  • 一個類中如果沒有定義過建構函式,那麼該類中會有一個預設的空引數建構函式
  • 如果在類中定義了指定的建構函式,那麼類中的預設建構函式就沒有了
    儘量不在類的構造器中建立、初始化大量的物件或執行某種複雜、耗時的運算邏輯

拷貝建構函式

一個類的建構函式中入參也是其類的一個物件,對這個物件的屬性拷貝後建立新的物件

/* 拷貝建構函式 */
public Clock(Clock clock){
this.hour=clock.hour;
this.minute=clock.minute;
this.second=clock.second;
}

一般函式和建構函式什麼區別

建構函式:物件建立時,就會呼叫與之對應的建構函式,對物件進行初始化
一般函式:物件建立後,需要函式功能時才呼叫
建構函式:物件建立時,會呼叫並且只調用一次
一般函式:物件建立後,可以被呼叫多次

練習內容

設計空調類,Air Conditioner
定義空調類常用屬性:品牌名,匹數,空調型別(壁掛式,櫃機),溫度
常用功能行為:製冷,制熱
建立一個空調物件,呼叫製冷功能

//空調類
public class AirConditioner {
//品牌名,匹數,空調型別(壁掛式,櫃機),溫度
private String pinPai;
private float piShu; // 0.f
private String type = "壁掛式";// 可以在宣告的同時賦初始值
private double wenDu;
//根據業務規則可以考慮是否需要定義該構造器,從理論上說呼叫無參構造器
//public AirConditioner() { }
public AirConditioner(String pinPai, float piShu) {
this.pinPai = pinPai;
this.piShu = piShu;
}
public AirConditioner(String pinPai, float piShu, String type) {
this.pinPai = pinPai;
this.piShu = piShu;
// NullPointerException
if ("壁掛式".equals(type) || "櫃機".equals(type))
this.type = type;
}
// 製冷
public void zhiLeng() {
System.out.println("製冷");
}
// 制熱
public void zhiRe() {
System.out.println("制熱");
}
public String getPinPai() {
return pinPai;
}
public float getPiShu() {
return piShu;
}
public String getType() {
return type;
}
public double getWenDu() {
return wenDu;
}
public void setWenDu(double wenDu) {
this.wenDu = wenDu;
}
}

構造方法—構造器—初始化,new呼叫

AirConditioner ac=new AirConditioner();//語法報錯,因為沒有無參構造器
AirConditioner ac=new AirConditioner("格力",1.5);
AirConditioner ac=new AirConditioner("格力",3.5,"櫃機");

析構方法

析構方法–析構器—在垃圾回收之前執行的方法—資源回收
由於垃圾回收的執行時機不確定,而且不能保證一定會執行析構器,所以一般不能使用析構方法執行資源回收

//空調類
public class AirConditioner {
@Override
protected void finalize() throws Throwable {
System.out.println("進行資源回收");
super.finalize();
}
}

UML

統一建模語言(Unied Modeling Language,UML)是一種為面向物件系統的產品進行說明、視覺化和編制文件的
一種標準語言,是非專利的第三代建模和規約語言。UML使用面向物件設計的的建模工具,但獨立於任何具體程式
設計語言

UML主要作用

為軟體系統建立視覺化模型
為軟體系統建立構件
為軟體系統建立文件

UML系統開發中三個主要的模型

功能模型:從使用者的角度展示系統的功能,包括用例圖。
物件模型:採用物件,屬性,操作,關聯等概念展示系統的結構和基礎,包括類別圖、物件圖。
動態模型:展現系統的內部行為。包括序列圖,活動圖,狀態圖

繪製UML圖的工具

StarUML免費、Rational Rose(IBM)、Visio(Microsoft)
線上工具https://www.processon.com/
在學習階段不要求繪製UML圖,要求可以讀UML圖

類圖

在UML類圖中,常見的有以下幾種關係: 泛化Generalization, 實現Realization,關聯Association,聚合
Aggregation,組合Composition,依賴Dependencyl
在這裡插入圖片描述
+表示public -表示private #表示protected ~表示預設也就是包許可權 _下劃線表示static

斜體表示抽象

繼承關係—泛化Generalization指的是一個類(稱為子類、子介面)繼承另外的一個類(稱為父類、父介面)的功能,並可以增加它自己的新功能的能力。泛化關係是一種繼承關係,表示一般與特殊的關係,它指定了子類如何特化父類的所有特徵和行為。例如:貓頭鷹是鳥的一種,即有鳥的特性也有貓頭鷹的共性

練習內容

1、猜數字遊戲一個類A有一個成員變數v。定義一個類對A類的成員變數v進行猜。如果大了則提示大了小了則提示
小了。等於則提示猜測成功。
在這裡插入圖片描述

public class A {
private Integer v=0;
public String guess(Integer parameter1) { //比較實現的寫法1
String res="小了";
if(parameter1!=null) {
if(v.intValue()>parameter1.intValue())
res="大了";
else if(v.intValue()==parameter1.intValue())
res="相等";
}
return res;
}
}
public class A {
private Integer v=0;
public A() {
Random r=new Random();
v=r.nextInt(1000);
}
public String guess(Integer parameter1) {
String res="小了";
if(parameter1!=null) {
if(v.compareTo(parameter1)==0)
res="相等";
else if(v.compareTo(parameter1)>0)
res="大了";
}
return res;
}
}