目錄
1. 封裝概述(封裝與隱藏)
2. private關鍵字
3. Getter & Setter方法
4. 變量訪問原則和this關鍵字
5. 構造方法
5.1 構造方法概述
5.2 構造方法和set方法的比較
6. 靜態
6.1 靜態概述
6.2 靜態效果
6.3 靜態變量和非靜態變量的區別
6.4 工具類
7. 代碼塊
7.1 概述
7.2 局部代碼塊
7.3 構造代碼塊
7.4 靜態代碼塊
1. 封裝概述(封裝與隱藏)
封裝:隱藏事物的屬性和實現細節,對外提供公共的訪問方式。
為什么需要封裝?封裝的作用和含義?
-
我要用洗衣機,只需要按一下開關和洗滌模式就可以了。有必要了解洗衣機內部的結構嗎?有必要碰電動機嗎?
-
我要開車,...
我們程序設計追求“高內聚,低耦合”。
-
高內聚 :類的內部數據操作細節自己完成,不允許外部干涉;
-
低耦合 :僅對外暴露少量的方法用于使用。
封裝性的設計思想
隱藏對象內部的復雜性,只對外公開簡單的接口。便于外界調用,從而提高系統的可擴展性、可維護性。通俗的說,把該隱藏的隱藏起來,該暴露 的暴露出來。這就是封裝性的設計思想。
封裝的好處:
-
隱藏了事物的實現細節
-
提高了代碼的復用性
-
提高了安全性
封裝的原則:
-
隱藏事物的屬性
-
隱藏事物的實現細節
-
對外提供公共的訪問方式
-
代碼體會:
public class Animal {String name;int legs;
?void move() {System.out.println("我叫" + name + ",我用" + legs + "條腿跑步!");}
}
?
public class AnimalTest {public static void main(String[] args) {Animal pig = new Animal();pig.name = "佩奇";pig.legs = 4; // 修改一下試試?pig.move();}
}
-
使用者對類內部定義的屬性(對象的成員變量)的直接操作會導致數據的錯誤、混亂或安全性問題。
2. private關鍵字
-
含義:私有的
-
可以修飾的內容:
-
修飾成員變量
-
修飾成員方法
-
修飾構造方法
-
修飾內部類
-
-
修飾之后的效果:被
private
修飾的成員,只能在本類中被訪問。 -
注意事項:
private
只是封裝的一種體現形式,封裝還可以使用其他的修飾符來完成。 -
示例:
public class Animal {private String name;private int legs; ?void move() {System.out.println("我叫" + name + ",我用" + legs + "條腿跑步!");} }
3. Getter & Setter方法
-
當屬性被私有之后,外界無法直接訪問,所以需要提供公共的訪問方式,讓外界可以間接的訪問屬性。對于當前類,就可以控制外界訪問屬性的方式。(我讓你怎么訪問,你就只能怎么訪問)
-
一般提供
get
方法,獲取成員變量的值;提供set
方法,設置成員變量的值。 -
示例:
public class Animal {private String name;private int legs; ?public String getName() {return name;} ?public int getLegs() {return legs;} ?public void setName(String n) {name = n;}public void setLegs(int l) {if (l >= 0 && l % 2 == 0) {legs = l;}} ?public void move() {System.out.println("我叫" + name + ",我用" + legs + "條腿跑步!");} } ? //********************************************* ? public class AnimalTest {public static void main(String[] args) {Animal pig = new Animal();pig.setName("佩奇");pig.setLegs(-3);pig.move();} }
-
以上是封裝性的體現之一,但是它并不等同于封裝性!!!這點需要牢記,關于封裝性的體現還有其他方面等等。比如我們將某個方法添加上private關鍵字,那么該方法只作為內部使用,并不會對外暴露。你是好人并不等同于你真的好!
封裝性的體現,需要權限修飾符來配合。
-
Java規定了4種權限(從小到大排列):private、缺省、protected、public
-
4種權限可以用來修飾類及類的內部結構:屬性、方法、構造器、內部類
-
對于class的權限修飾只可以用public和default(缺省), public類可以在任意地方被訪問,default類只可以被同一個包內部的類訪問。
-
開心一笑
A man and woman are in a computer programming lecture. The man touches the woman's hand.
"Hey!" she says. "Those are private!"
The man says, "But we're in the same class!"
4. 變量訪問原則和this關鍵字
-
對于先前標識符的使用我們還是希望可以見明知意:我們將setName與setLegs方法中的形參都變成name和legs,我們發現方法體中的賦值出現了問題。產生問題的原因就是因為變量的訪問機制。
-
變量訪問原則:
-
就近原則:當在訪問某個變量名稱的時候,會先尋找最近的該變量名稱的定義,如果尋找到了,就使用該變量,如果沒有找到,才到更遠的位置尋找該變量名稱的定義。
-
當局部變量和成員變量同名的時候,一定是先使用局部位置定義的變量,如果沒有,才會使用成員位置定義的變量。
-
-
this
關鍵字:-
表示當前類型當前對象的引用:哪個來調用this所在的方法,this就代表哪個對象
-
作用:用于區分局部變量和成員變量同名的情況。使用
this.屬性名稱
的一定是成員變量,沒有使用this.
的變量,根據就近原則來確定使用哪個變量。
-
-
示例:
public class Animal {private String name;private int legs; ?public String getName() {return name;} ?public int getLegs() {return legs;} ?public void setName(String name) {this.name = name;} ?public void setLegs(int legs) {if (legs >= 0 && legs % 2 == 0) {this.legs = legs;}} ?public void move() {System.out.println("我叫" + name + ",我用" + legs + "條腿跑步!");} }/** this關鍵字的使用* 1.this可以用來修飾:屬性、方法、構造器** 2.this修飾屬性和方法:* ? this理解為當前對象或者當前正在創建的對象** ? 2.1 在類的方法中,我們可以使用"this.屬性"或者"this.方法"的形式,調用當前對象的屬性或者方法。* ? 但是,通常情況下,我們都選擇省略"this."。特殊情況下,如果方法的形參和類的屬性同名時,我們必須* ? 顯式的使用"this.變量"的方式,表明此變量是屬性,而非形參。** 2.2 在類的構造器中,我們可以使用"this.屬性"或者"this.方法"的形式,調用當前正在創建對象的屬性或者方 法。* ? 但是,通常情況下,我們都選擇省略"this."。特殊情況下,如果構造器的形參和類的屬性同名時,我們必須* ? 顯式的使用"this.變量"的方式,表明此變量是屬性,而非形參。* */
-
5. 構造方法
5.1 構造方法概述
-
構造方法:構造函數,構造器,Constructor
-
作用:用于給對象中的成員變量賦值。因為在創建對象的同時,JVM會自動調用構造方法,等對象創建完成的時候,對象中的成員變量就已經有指定的值了。
-
語法結構:
修飾符 方法名稱(參數列表) {方法體 }
-
構造方法說明:
-
構造方法的方法名稱,必須和類名一模一樣,連大小寫都一樣
-
構造方法沒有返回值類型,連void也沒有
-
構造方法沒有return語句,如果一定需要return語句,就寫一個return;return后面不能跟內容,加return沒有實際的意義
-
構造方法不需要手動調用,由JVM在創建對象的時候自動調用
-
對象本身不能調用構造方法
-
構造方法只調用一次
-
-
示例:
public class Person {private String name;private int age;private String gender; ?public Person() {System.out.println("我被執行了");} } .......public class PersonTest {public static void main(String[] args) {Person person = new Person();} } // 在創建對象的同時,會自動調用構造方法
-
注意事項:
-
構造方法可以是有參數的,也可以是沒有參數的。
-
如果是沒有參數的構造方法,外界無需傳入任何的參數值,只能給成員變量賦固定值或者不賦值。
-
如果是有參數的構造方法,外界在調用構造方法的時候,需要傳入實際的參數值,通常用于賦值給成員變量。
-
-
如果在類中沒有定義任何的構造方法,那么系統會自動提供一個空參構造(空實現)。
-
如果在類中手動定義了一個構造方法(無論是空參還是有參),系統都不再會提供任何的構造方法。
-
構造方法的重載:構造方法都在同一個類中,構造方法的方法名稱都和類名一致,參數列表不同,沒有返回值類型,一般在類中,既需要空參構造,也需要有參構造,都手動定義出來。
-
示例:
public class Person {private String name;private int age;private String gender; ?public Person(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;} ?public Person() {} ?public String getName() {return name;} ?public void setName(String name) {this.name = name;} ?public int getAge() {return age;} ?public void setAge(int age) {this.age = age;} ?public String getGender() {return gender;} ?public void setGender(String gender) {this.gender = gender;} ?@Overridepublic String toString() {return "Person{" +"name='" + name + '\'' +", age=" + age +", gender='" + gender + '\'' +'}';} } ? public class PersonTest {public static void main(String[] args) {Person person = new Person("zhangsan", 18, "男");System.out.println(person);} }/*****************************************************/ 我們也可以給set方法進行改造,讓它返回對應的類型,改造方式如下: public Person setName(String name) {this.name = name;return this;} ?public Person setAge(int age) {this.age = age;return this;} ?public Person setGender(String gender) {this.gender = gender;return this;}創建對象時可以使用鏈式編程的方式Person person = new Person().setName("lisi").setAge(20).setGender("男");
-
5.2 構造方法和set方法的比較
-
共同點:構造方法和set方法都是用于給成員變量賦值。不希望外界直接訪問私有成員變量,通過構造方法或者set方法,間接的訪問私有變量。
-
區別:
-
構造方法:構造方法是在創建對象的同時,由JVM自動調用執行,用于給屬性賦值,只能執行一次。
-
set方法:set方法是在創建對象之后,由對象手動調用執行,用于給屬性修改值,可以調用多次。
-
-
使用場景比較:
-
構造方法:只能在創建對象的時候被自動調用一次,代碼更加簡潔。一旦對象創建成功,就不能繼續使用構造方法修改成員變量的值。
-
set方法:一般set方法使用更加靈活,使用更加頻繁。
-
-
總結:屬性賦值的先后順序
-
默認初始化
-
顯示初始化
-
構造器初始化
-
通過"對象.方法"或者"對象.屬性"的方式,賦值
-
最終結果由最后執行的方式決定
-
6. 靜態
6.1 靜態概述
-
靜態:
static
關鍵字,靜態、靜止的。靜態變量不會隨著對象的變化而變化。 -
加載時機:
-
隨著類的加載而加載。
-
靜態變量隨著類的加載進方法區,就直接在靜態區給開辟了存儲靜態變量的內存空間。
-
-
靜態變量優先于對象而存在。
-
靜態變量被所有該類對象所共享。
-
代碼層面:可以使用類名直接調用,不需要使用對象名稱。在不創建對象的前提下,仍然可以使用這個靜態變量。
-
強烈建議使用類名來訪問。
6.2 靜態效果
-
不使用靜態:
-
現象:如果某個類型的所有對象,都具有一個相同的屬性值,比如2個對象的country都是中國; 那么這個屬性值就沒有必要在所有對象中,都存儲一份。
-
缺點:浪費內存空間;維護難度大,一旦需要修改,就得修改所有的對象。
-
示例:
public class StaticDemo {private String username;private String country; ?public String getUsername() {return username;} ?public void setUsername(String username) {this.username = username;} ?public String getCountry() {return country;} ?public void setCountry(String country) {this.country = country;} ?public static void main(String[] args) {StaticDemo st1 = new StaticDemo();st1.setUsername("zs");st1.setCountry("中國");StaticDemo st2 = new StaticDemo();st1.setUsername("lisi");st1.setCountry("中國"); ?st1.setCountry("東三省");st2.setCountry("東三省");} }
-
-
使用靜態:
-
現象:如果某個類型的所有對象,都具有一個相同的屬性值,那么就在這個屬性的定 義上,加一個static靜態關鍵字。讓該變量存儲在方法區字節碼的靜態區中,避免了所有對象都存儲相 同數據的問題,節省了內存空間,將來維護容易(只需要修改一次)。
-
示例:
public class StaticDemo {private String username;private static String country; ?public String getUsername() {return username;} ?public void setUsername(String username) {this.username = username;} ?public static String getCountry() {return country;} ?public static void setCountry(String country) {StaticDemo.country = country;} ?public static void main(String[] args) {StaticDemo st1 = new StaticDemo();st1.setUsername("zs");st1.setCountry("中國");StaticDemo st2 = new StaticDemo();st1.setUsername("lisi");System.out.println(st2.getCountry());st2.setCountry("東三省");System.out.println(st1.getCountry());} }
-
-
注意事項:
-
靜態方法:在方法聲明上,加上了
static
關鍵字的方法,就是靜態方法。 -
靜態方法不能訪問非靜態的變量:靜態方法本身可以在沒有創建對象的時候調用;非靜態的變量只有在對象創建之后才存在。如果靜態方法可以訪問非靜態的變量,那么就相當于在對象創建之前,就訪問了對象創建之后的數據。明顯不合理。
-
靜態方法不能訪問非靜態的方法:靜態方法可以在沒有創建對象的時候調用;非靜態的方法可以訪問非靜態的變量。如果靜態方法可以訪問非靜態的方法,就相當于靜態方法間接的訪問了非靜態的變量,和第2點矛盾。
-
靜態方法中不能存在
this
關鍵字:this
關鍵字表示本類當前對象。靜態方法可以在對象創建之前調用。如果靜態方法可以訪問this
關鍵字,相當于在創建對象之前,就使用了對象本身。矛盾。 -
總結:靜態資源不能訪問非靜態資源
-
6.3 靜態變量和非靜態變量的區別
-
概念上,所屬不同:
-
非靜態變量屬于對象。
-
靜態變量屬于類,類變量。
-
-
內存空間不同,存儲位置不同:
-
非靜態變量屬于對象,所以存儲在堆內存中。
-
靜態變量屬于類,存儲在方法區的靜態區中。
-
-
內存時間不同,生命周期不同:
-
非靜態變量屬于對象,所以生命周期和對象相同,隨著對象的創建而存在,隨著對象的消失而消失。
-
靜態變量屬于類,所以生命周期和類相同,隨著類的加載。
-
-
訪問方式不同:
-
非靜態變量只能使用對象名訪問。
-
靜態變量既可以使用對象訪問,也可以通過類名訪問(強烈建議使用類名訪問):
-
類名.靜態變量名
-
類名.靜態方法名()
-
-
6.4 工具類
-
工具類:在一個類中,沒有維護什么數據,沒有任何的成員變量,相當于是一個工具。類中就都是一些靜態方法,快速的解決一些常見的問題。
-
方法都是靜態的,不需要創建對象;創建對象會浪費系統資源。希望控制不讓創建對象(方式:使用構造方法私有化)。
-
示例:數組工具類
public class ArraysUtils {// ? 構造方法私有化,保證類不會被創建對象private ArraysUtils() {} ?// 1、循環打印數組public static void print(int[] arr) {for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + ",");}} ?// 2、循環打印數組,一行打印指定個數的元素public static void print(int[] arr, int number) {for (int i = 0; i < arr.length; i++) {System.out.print(arr[i] + ",");if ((i + 1) % number == 0) {// 換一行System.out.println();}}} ?// 3、將數組轉成[元素1,元素2...]這種格式的字符串public static String formatPrint(int[] arr) {if (arr == null)return "null";// 如果iMax是-1 意味著數組長度是0int iMax = arr.length - 1;if (iMax == -1)return "數組長度為0";StringBuilder b = new StringBuilder();b.append('[');// 在最前方追加一個[for (int i = 0; ; i++) {b.append(arr[i]);// 滿足條件 就退出if (i == iMax) {return b.append(']').toString();}b.append(", ");}} ?// 4、將數組冒泡\或者其他算法排序(直接將原數組排序)public static void sort(int[] arr) {for (int i = 0; i < arr.length - 1; i++) {for (int j = 0; j < arr.length - 1 - i; j++) {if (arr[j] > arr[j + 1]) {int desk = arr[j];arr[j] = arr[j + 1];arr[j + 1] = desk;}}}} ?// 5、將數組冒泡\或者其他算法排序(不允許排形參的數組,需要直接返回一個排好序的新數組)public static int[] sortNew(int[] arr) {int arrNew[] = new int[arr.length];// 把源數組 內容賦值一份給 arrNew// arrNew = Arrays.copyOf(arr, arr.length);for (int i = 0; i < arrNew.length; i++) {arrNew[i] = arr[i];} ?for (int i = 0; i < arrNew.length - 1; i++) {for (int j = 0; j < arrNew.length - 1 - i; j++) {if (arrNew[j] > arrNew[j + 1]) {int desk = arrNew[j];arrNew[j] = arrNew[j + 1];arrNew[j + 1] = desk;}}}return arrNew;} ?// 6、比較兩個數組的所有元素是否完全一致public static boolean isEquals(int[] arr1, int[] arr2) {// 地址相同 里面的數據肯定相同if (arr1 == arr2)return true;if (arr1 == null || arr2 == null)return false; ?int length = arr1.length;if (arr2.length != length)return false; ?for (int i = 0; i < length; i++)if (arr1[i] != arr2[i])return false; ?return true;} ?// 7、計算數組的平均值public static double avg(int[] arr) {double sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}return sum / arr.length;} ?// 8、計算數組的最大值public static int max(int[] arr) {// 數組第一個 為最大值int maxnumber = arr[0];for (int i = 1; i < arr.length; i++) {if (maxnumber < arr[i]) {maxnumber = arr[i];}}return maxnumber;} ?// 9、計算數組的最小值public static int min(int[] arr) {// 數組第一個 為最小值int minnumber = arr[0];for (int i = 0; i < arr.length; i++) {if (minnumber > arr[i]) {minnumber = arr[i];}}return minnumber;} ?// 10、將一個數組的所有元素都反轉(比如{5,4,8}變成{8,4,5})public static int[] reverse(int[] arr) {int[] arrNew = new int[arr.length];for (int x = 0; x < arr.length; x++) {arrNew[x] = arr[arr.length - 1 - x];}return arrNew;} ?// 11、判斷一個指定的數值在數組中是否存在public static boolean isExits(int[] arr, int number) {boolean isTrue = false;for (int i = 0; i < arr.length; i++) {if (arr[i] == number) {return true;}}// 如果不存在return false;} }
7. 代碼塊
7.1 概述
-
使用大括號包起來的一段代碼。放在不同的位置,有不同的名稱,有不同的作用,有不同的執行時機。
-
分類:
-
局部代碼塊
-
構造代碼塊
-
靜態代碼塊
-
同步代碼塊(多線程中會遇到)
-
7.2 局部代碼塊
-
格式:使用大括號包起來的一段代碼
-
位置:方法中
-
作用:
-
限定變量的生命周期,作用域只是在大括號內部。
-
在局部代碼塊中【聲明】的變量,只能在局部代碼塊的范圍內使用,一旦出了局部代碼塊的大括號,變量就不能繼續使用了。
-
某個變量一旦不能使用了,就會被回收,節省內存空間。
-
-
注意事項:
-
局部代碼塊內聲明的變量,會減少變量的生命周期,局部代碼塊執行完畢后,就無法繼續使用變量。
-
局部代碼塊外聲明的變量,局部代碼塊執行完畢后,仍可以繼續使用變量。
-
-
示例:
public class Demo {public static void main(String[] args) {int a = 123;{int b = 456;System.out.println(a);System.out.println(b);}System.out.println(a);} }
7.3 構造代碼塊
-
格式:使用大括號包起來的一段代碼
-
位置:類中方法外
-
作用:
-
用于給成員變量初始化賦值。
-
在創建對象時執行部分操作。
-
-
構造代碼塊的執行說明:
-
在創建對象的時候執行,由 JVM 默認調用,用于給對象的屬性賦值。
-
在構造方法執行之前執行。
-
任意一個構造方法執行之前,都會執行一次構造代碼塊的內容。
-
如果每個構造方法都會執行的內容,請提取到構造代碼塊中執行。
-
-
示例:
public class Demo {{System.out.println("我是一個構造代碼塊");} ?public static void main(String[] args) {Demo demo = new Demo();} }
7.4 靜態代碼塊
-
格式:
static {靜態代碼塊的內容 }
-
位置:類中方法外
-
作用:
-
用于給靜態的成員變量初始化賦值
-
用于執行那些只需要執行一次的代碼,例如驅動加載等
-
-
執行特點:
-
隨著類的加載而執行
-
類只加載一次,所以靜態代碼塊只執行一次
-
執行的時機最早:早于所有的對象相關內容,比main方法執行的早
-
-
示例:
public class Demo {static {System.out.println("說我是靜態代碼塊");} ?{System.out.println("我是構造代碼塊");} ?public static void main(String[] args) {System.out.println("我是main方法");Demo demo = new Demo();} }