目錄
一.封裝
二.封裝擴展之包
三.static成員
四.?代碼塊
五.?內部類(重要)
大家好呀,我是北緯,接著上節我們繼續講解Java中關于類和對象的相關知識,今天著重給大家介紹一下關于面向對象程序的特性之一——封裝。
一.封裝
1.什么是封裝
封裝是面向對象程序三大特性之一,面向對象程序有三大特性:封裝、繼承、多態。而類和對象階段,主要研究的就是封裝特性,何為封裝呢?簡單來說就是套殼屏蔽細節。
類比一下比如說:對于電腦這樣一個復雜的設備,提供給用戶的就只是:開關機、通過鍵盤輸入,顯示器,USB插孔等,讓用戶來和計算機進行交互,完成日常事務。但實際上電腦真正工作的卻是CPU、顯卡、內存等一些硬件元件。
封裝:將數據和操作數據的方法進行有機結合,隱藏對象的屬性和實現細節,僅對外公開接口來和對象進行交互。
2.訪問限定符
Java中主要通過類和訪問權限來實現封裝:類可以將數據以及封裝數據的方法結合在一起,更符合人類對事物的認知,而訪問權限用來控制方法或者字段能否直接在類外使用。Java中提供了四種訪問限定符:【說明】:
? ? ? ? ? 1.private同一包中的同一類,也就相當于自己的秘密只有自己知道,所以被private修? ? ? ? ? ? ? ?飾的成員變量和方法只能在本類中的成員方法中可以調用。
? ? ? ? ? 2.default是什么都不寫時的默認權限,同一包中的不同類,被default修飾的成員方法? ? ? ? ? ? ? ?和成員變量在同一個包中可以被其他類中的成員方法調用。? ?
? ? ? ? ? 3.protected主要是用在繼承中,后期會有詳細講解這里就不贅述了。
? ? ? ? ? 4.?訪問權限除了可以限定類中成員的可見性,也可以控制類的可見性。
3.如何實現封裝
使用private關鍵字對類里面的成員變量進行隱藏,這里可以利用setter和getter方法對隱藏的成員變量進行訪問。
代碼示例:
【說明】:這里的setter和getter方法可以借助我們的編譯器idea自動生成。
二.封裝擴展之包
1 .包的概念
在面向對象體系中,提出了一個軟件包的概念,即:為了更好的管理類,把多個類收集在一起成為一組,稱為軟件包。有點類似于目錄。比如:為了更好的管理電腦中的歌曲,一種好的方式就是將相同屬性的歌曲放在相同文件下,也可以對某個文件夾下的音樂進行更詳細的分類。
在Java中引入了包,包是對類、接口等的封裝機制的體現,是一種對類或者接口等的很好的組織方式。包還有一個重要的作用:在同一個工程中允許存在相同名稱的類,只要處在不同的包中即可。
2.導入包中的類
Java 中已經提供了很多現成的類供我們使用。例如Date類:可以使用 java.util.Date 導入java.util 這個包中的 Date類,但是這種寫法比較麻煩一些,可以使用 import語句導入包。
import java.util.Date;
public class Test {
public static void main(String[] args) {
Date date = new Date();
// 得到一個毫秒級別的時間戳
System.out.println(date.getTime());
}
}
如果需要使用 java.util 中的其他類, 可以使用 import java.util.*
import java.util.*;
public class Test {
public static void main(String[] args){
Date date = new Date();
// 得到一個毫秒級別的時間戳
System.out.println(date.getTime());}
}
但是我們更建議顯式的指定要導入的類名,否則還是容易出現沖突的情況。也可以使用import static導入包中靜態的方法和字段。
import static java.lang.Math.*;
public class Test {
public static void main(String[] args){
double x = 30;
double y = 40;
// 靜態導入的方式寫起來更方便一些.
// double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
double result = sqrt(pow(x, 2) + pow(y, 2));
System.out.println(result);}
}
注意事項: import 和 C++ 的 #include 差別很大。C++ 必須 #include 來引入其他文件內容, 但是 Java 不需要。import 只是為了寫代碼的時候更方便?import 更類似于 C++ 的 namespace 和using
3.如何自定義包
基本規則:
?1.在文件的最上方加上一個 package 語句指定該代碼在哪個包中。
?2.包名需要盡量指定成唯一的名字, 通常會用公司的域名的顛倒形式(例com.baidu.demo1? )。
?3.包名要和代碼路徑相匹配。例如創建 com.baidu.demo1 的包, 那么會存在一個對應的路? ? ?徑?com/bit/demo1來存儲代碼。
?4.如果一個類沒有 package 語句, 則該類被放到一個默認包中。
操作步驟
? ? ? ? ? ? ??1. 在 IDEA 中先新建一個包: 右鍵 src -> 新建 -> 包。
? ? ? ? ? ? ? 2. 在彈出的對話框中輸入包名, 例如 com.bite.demo1。
? ? ? ? ? ? ? 3. 在包中創建類, 右鍵包名 -> 新建 -> 類, 然后輸入類名即可。
? ? ? ? ? ? ? 4. 此時我們可以看到, 在新創建的 Test.java 文件的最上方, 就出現了一個 package 語句
三.static成員
1.static修飾成員變量
在Java中,被static修飾的成員,稱之為靜態成員,也可以稱為類成員,其最大的特性就是不屬于某個具體的對象,是所有對象所共享的。
【靜態成員變量特性】
? ? ? ? ? 1. 不屬于某個具體的對象,是類的屬性,所有對象共享的,不存儲在某個對象的空間中。
? ? ? ? ? 2. 既可以通過對象訪問,也可以通過類名訪問,但一般更推薦使用類名訪問。
? ? ? ? ? 3. 類變量存儲在方法區當中。
? ? ? ? ? 4. 生命周期伴隨類的一生(即:隨類的加載而創建,隨類的卸載而銷毀)。
public class Student{
public String name;
public String gender;
public int age;
public double score;
public static String classRoom = "Bit306";
// ...
public static void main(String[] args) {
// 靜態成員變量可以直接通過類名訪問
System.out.println(Student.classRoom);
Student s1 = new Student("Li leilei", "男", 18, 3.8);
Student s2 = new Student("Han MeiMei", "女", 19, 4.0);
Student s3 = new Student("Jim", "男", 18, 2.6);
// 也可以通過對象訪問:但是classRoom是三個對象共享的
System.out.println(s1.classRoom);
System.out.println(s2.classRoom);
System.out.println(s3.classRoom);}
}
大家可以以調試的方式運行上述代碼,然后在監視窗口中可以看到,靜態成員變量并沒有存儲到某個具體的對象中。
2.static修飾成員方法
Java中,被static修飾的成員方法稱為靜態成員方法,是類的方法,不是某個對象所特有的,靜態成員一般是通過靜態方法來訪問的。
【靜態方法特性】
? ? ? ? ? ? ? 1. 不屬于某個具體的對象,是類方法。
? ? ? ? ? ? ? 2. 可以通過對象調用,也可以通過類名.靜態方法名(..)方式調用,更推薦使用后者。
? ? ? ? ? ? ? 3. 不能在靜態方法中訪問任何非靜態成員變量。
? ? ? ? ? ? ? 4. 靜態方法中不能調用任何非靜態方法,因為非靜態方法有this參數,在靜態方法? ? ? ? ? ? ? ? ? ? ? 中調用時無法傳遞this引用。
? ? ? ? ? ? ? 5. 靜態方法無法重寫,不能用來實現多態。
public static String getClassRoom(){
doClass();
return classRoom;
}
上述程序就會編譯錯誤,因為無法從靜態方法中引用非靜態方法 doClass()。
四.代碼塊
1. 代碼塊概念以及分類
使用 {} 定義的一段代碼稱為代碼塊。根據代碼塊定義的位置以及關鍵字,又可分為以下四種即普通代碼塊,構造代碼塊,靜態代碼塊,同步代碼塊。
普通代碼塊用的較少這里重點介紹一下構造代碼塊和靜態代碼塊,同步代碼塊后期會講到。
2. 構造代碼塊
構造代碼塊:定義在類中的代碼塊(不加修飾符),也叫:實例代碼塊,構造代碼塊一般用于初始化實例成員變量。
//實例代碼塊
{
this.name = "beiwei";
this.age = 20;
this.sex = "man";
System.out.println("實例代碼塊!");
}
3. 靜態代碼塊
使用static定義的代碼塊稱為靜態代碼塊,一般用于初始化靜態成員變量。
代碼示例:
注意事項:
? ? ? ?1.?靜態代碼塊不管生成多少個對象,其只會執行一次。
? ? ? ?2.?靜態成員變量是類的屬性,因此是在JVM加載類時開辟空間并初始化的。
? ? ? ?3.如果一個類中包含多個靜態代碼塊,在編譯代碼時,編譯器會按照定義的先后次序依次執行
? ? ? ?4.?實例代碼塊只有在創建對象時才會執行。
五.?內部類(重要)
當一個事物的內部,還有一個部分需要一個完整的結構進行描述,而這個內部的完整的結構又只為外部事物提供服務,那么這個內部的完整結構最好使用內部類。在 Java 中,可以將一個類定義在另一個類或者一個方法的內部,前者稱為內部類,后者稱為外部類,內部類也是封裝的一種體現。
注意:
? ?1. 定義在class 類名{}花括號外部的,即使是在一個文件里,都不能稱為內部類。
? ?2. 內部類和外部類共用同一個java源文件,但是經過編譯之后,內部類會形成單獨的字節碼文件1 .內部類的分類
根據內部類定義的位置不同,一般可以分為這幾種形式,實例內部類,靜態內部類,局部內部類。
public class OutClass {
// 成員位置定義:未被static修飾 --->實例內部類
public class InnerClass1{
} /
/ 成員位置定義:被static修飾 ---> 靜態內部類
static class InnerClass2{
}
public void method(){
// 方法中也可以定義內部類 ---> 局部內部類:幾乎不用
class InnerClass5{}}
}
2.實例內部類
即未被static修飾的成員內部類。
代碼示例:
如何實例化內部類對象,這里語法有點怪異,大家適應一下。
注意:
1. 外部類中的任何成員都可以在實例內部類方法中直接訪問。
2. 實例內部類所處的位置與外部類成員位置相同,因此也受public、private等訪問限定符的約束。
3. 在實例內部類方法中訪問同名的成員時,優先訪問自己的,如果要訪問外部類同名的成員,必須:外部類名稱.this.同名成員 來訪問。
4. 實例內部類對象必須在先有外部類對象前提下才能創建。
5. 實例內部類的非靜態方法中包含了一個指向外部類對象的引用。
6. 外部類中,不能直接訪問實例內部類中的成員,如果要訪問必須先要創建內部類的對象。
3.靜態內部類
被static修飾的內部成員類稱為靜態內部類。
對靜態內部類對象的實例化:
public static void main(String[] args) {OuterClass2.InnerClass2 innerClass2 = new OuterClass2.InnerClass2(); //靜態內部類對象的實例化}
【注意事項】
? ? ? ? ? ?1. 在靜態內部類中只能訪問外部類中的靜態成員。
? ? ? ? ? ?2. 創建靜態內部類對象時,不需要先創建外部類對象。
?