java初學 面向物件二 static關鍵字 封裝、繼承和多型
- static關鍵字
1:如果沒有static會怎樣?
1:定義Person類
1:姓名、年齡、國籍,說話行為
2:多個構造,過載形式體現
2:中國人的國籍都是確定的
1:國籍可以進行顯示初始化
class Person { String name; int age; String gender; String country = "CN";
Person() {
}
Person(String name, int age, String gender, String country) { this.name = name; this.age = age; this.gender = gender; this.country = country; }
void speak() { System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender + " 年齡:" + age + " 哈哈!!!"); }
} |
3:new Person 物件
1:分析記憶體
2:每個物件都維護例項變數國籍也是。
public class PersonDemo { public static void main(String[] args) { Person p1 = new Person("jack", 20, "男"); p1.speak();
Person p2 = new Person("rose", 18, "女"); p2.speak(); } }
|
4:記憶體分析
1:棧,堆、共享區
2:Demo.class載入近共享區
1:Demo類的main方法進棧
2:Person p1=new Person();
1:Person.class 載入進方法區
2:堆記憶體開闢空間,例項變數進行預設初始化,顯示初始化。
3:記憶體地址傳給變數p1,棧和堆建立連線
3:person p2=new Person();
1:堆記憶體開闢空間,例項變數進行預設初始化,顯示初始化。
2:記憶體地址傳給變數p2,棧和堆建立連線
4:如果建立多個Person物件發現問題
1:每個物件都維護有國籍。
5:解決問題,記憶體優化
1:為了讓所有Person物件都共享一個country ,可以嘗試將country放入共享區。
2:country變數如何放入共享區?物件如何訪問?
1:使用static
2:static
1:為了實現物件之間重複屬性的資料共享
3:static使用
1:主要用於修飾類的成員
1:成員變數
1:非靜態成員變數:需要建立物件來訪問
2:靜態成員變數:使用類名直接呼叫,也可以通過物件訪問
public static void main(String[] args) {
//訪問靜態成員 //直接通過類名來呼叫 String country=Person.country; System.out.println(country);
//通過物件.成員的形式訪問 Person p1 = new Person("jack", 20, "男"); p1.country="US"; p1.speak();
} class Person { String name; int age; String gender; //static 修飾成員變數 static String country = "CN";
Person() {
}
Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender;
}
void speak() {
System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender + " 年齡:" + age + " 哈哈!!!"); }
} |
2:成員方法
可以使用類名直接呼叫
1:靜態函式:
1:靜態函式中不能訪問非靜態成員變數,只能訪問靜態變數。
2:靜態方法不可以定義this,super關鍵字.
3:因為靜態優先於物件存在.靜態方法中更不可以出現this
2:非靜態函式:非靜態函式中可以訪問靜態成員變數
class Person { String name; int age; String gender; //static 修飾成員變數 static String country = "CN";
Person() {
}
Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender;
} //非靜態方法 void speak() { //非靜態方法可以訪問靜態成員 System.out.println("國籍:" + country );
System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender + " 年齡:" + age + " 哈哈!!!");
} //靜態方法 static void run(){ //靜態方法只能訪問靜態成員變數。 System.out.println("國籍:"+country);
//靜態方法訪問非靜態成員變數,編譯報錯。 System.out.println(" 姓名:" + name);
//靜態方法中不可以出現this,編譯報錯 this.speak(); } } |
2:細節:
1:靜態函式中不能使用非靜態變數
2:非靜態函式可以訪問靜態變數
3:為什麼靜態函式中不能訪問非靜態成員
1:static修飾的成員在共享區中。優先於物件存在
2:驗證
1:使用靜態程式碼塊驗證
1:靜態程式碼塊
static{
靜態程式碼塊執行語句;
}
1:靜態程式碼塊特點
隨著類的載入而載入。只執行一次,優先於主函式。用於給類進行初始化。
public class PersonDemo { public static void main(String[] args) {
// 訪問靜態成員 // 直接通過類名來呼叫 String country = Person.country; System.out.println(country);
// 通過物件.成員的形式訪問 Person p1 = new Person("jack", 20, "男"); p1.country = "US"; p1.speak();
} }
class Person { String name; int age; String gender; // static 修飾成員變數 static String country = "CN"; static { System.out.println("這是靜態程式碼塊"); }
{ System.out.println("這是構造程式碼塊"); }
Person() { System.out.println("無引數構造"); }
Person(String name, int age, String gender) { this.name = name; this.age = age; this.gender = gender; System.out.println(" 有引數構造");
}
// 非靜態方法 void speak() { // 非靜態方法可以訪問靜態成員 System.out.println("國籍:" + country);
System.out.println("國籍:" + country + " 姓名:" + name + " 性別:" + gender + " 年齡:" + age + " 哈哈!!!"); // 非靜態方法可以呼叫靜態方法。 run(); }
// 靜態方法 static void run() { // 靜態方法只能訪問靜態成員變數。 System.out.println("國籍:" + country); } }
|
4:static特點
1 隨著類的載入而載入,靜態會隨著類的載入而載入,隨著類的消失而消失。說明它的生命週期很長。
2 優先於物件存在。-->靜態是先存在,物件是後存在。
3 被所有例項(物件)所共享。
4 可以直接被類名呼叫
5:靜態變數(類變數)和例項變數的區別:
1存放位置
1:類變數隨著類的載入而載入存在於方法區中.
2:例項變數隨著物件的建立而存在於堆記憶體中.
2生命週期
1:類變數生命週期最長,隨著類的消失而消失.
2:例項變數生命週期隨著物件的消失而消失.
6:靜態優缺點
1: 優點:對物件的共享資料進行單獨空間的儲存,節省空間 例如Person 都有
國籍。該資料可以共享可以被類名調
2:缺點:生命週期過長
訪問出現侷限性。(靜態只能訪問靜態)
7: 什麼時候定義靜態變數
1:靜態變數(類變數)當物件中出現共享資料
例如:學生的學校名稱。學校名稱可以共享
物件的資料要定義為非靜態的存放在對記憶體中(學生的姓名,學生的年齡)
8:什麼時候定義靜態函式
如果功能內部沒有訪問到非靜態資料(物件的特有資料。那麼該功能就可以定義為靜態)
9:靜態的應用
自定義陣列工具類
/* 定義陣列工具類 1:定義一個遍歷陣列的函式 2:定義一個求陣列和的功能函式 1. 遍歷 2. 兩兩相加 3:定義一個獲取陣列最大值的功能函式 4:定義一個獲取陣列最大值角標的功能函式 5:定義一個返回指定數在指定陣列中包含的角標的功能函式 6:定義一個可以用於排序int陣列的函式 1:冒泡 2:選擇
定義自己的工具類
*/ class Arrays {
private Arrays() {
}
// 1:定義一個遍歷陣列的函式 public static void print(int[] arr) { for (int x = 0; x < arr.length; x++) { if (x != (arr.length - 1)) { System.out.print(arr[x] + ","); } else { System.out.print(arr[x]); }
} }
// 2:定義一個求陣列和的功能函式 public static int getSum(int[] arr) { int sum = 0; for (int x = 0; x < arr.length; x++) { sum += arr[x]; } return sum; }
// 3:定義一個獲取陣列最大值的功能函式 public static int getMax(int[] arr) { int max = 0; for (int x = 0; x < arr.length; x++) { if (arr[max] < arr[x]) { max = x; } } return arr[max]; }
// 4:定義一個獲取陣列最大值角標的功能函式 public static int getIndexMax(int[] arr) { int max = 0; for (int x = 0; x < arr.length; x++) { if (arr[max] < arr[x]) { max = x; } } return max; }
// 5:定義一個返回 指定數在指定陣列中包含的角標的功能函式 public static int getIndex(int[] arr, int src) { int index = -1; for (int x = 0; x < arr.length; x++) { if (arr[x] == src) { index = x; } } return index; }
// 冒泡 public static void test(int[] arr) { for (int x = 0; x < arr.length - 1; x++) { if (arr[x] > arr[x + 1]) { int temp = arr[x + 1]; arr[x + 1] = arr[x]; arr[x] = temp;
} } }
// 選擇排序 public static void selectSort(int[] arr) { for (int x = 0; x < arr.length - 1; x++) { for (int y = 1 + x; y < arr.length; y++) { if (arr[x] > arr[y]) { int temp = arr[y]; arr[y] = arr[x]; arr[x] = temp; } } } }
// 7:定義一個可以將整數陣列進行反序的功能函式。 public static void reverseSort(int[] arr) { int start = 0; int end = arr.length - 1; for (int x = 0; x < arr.length; x++) { if (start < end) { int tem = arr[start]; arr[start] = arr[end]; arr[end] = tem; } start++; end--; }
}
// 折半查詢 public static int halfSearch(int key, int[] arr) { int min = 0; int max = arr.length - 1; int mid = 0;
while (min < max) { mid = (min + max) / 2; if (key > arr[mid]) { min = mid + 1; } else if (key < arr[mid]) { max = mid - 1; } else { return mid; } } return -1; }
}
class Demo6 {
public static void main(String[] args) { int[] arr = { 3, 4, 5, 2, 3, 7, 4 }; Arrays.print(arr); System.out.println(); Arrays.selectSort(arr); Arrays.print(arr);
} } |
練習:統計建立物件的人數
class Person { public String name; public int age; static public long all_count; public Person(){ all_count++; } public Person( String name , int age ){ all_count++; this.name = name; this.age = age; } // 統計人數的函式 public long getCount(){ return all_count; } // 應該具備找同齡人的功能 public boolean isSameAge( Person p1 ){ return this.age == p1.age; } } class Demo9 { public static void main(String[] args) { Person p1 = new Person( "jame" , 34 ); Person p2 = new Person( "lucy" , 34 );
Person p3 = new Person( "lili" , 34 ); Person p4 = new Person(); System.out.println( p1.getCount() + " " + p2.getCount() + " " + p3.getCount() ); System.out.println( p1.isSameAge( p2 ) ); System.out.println( p1.isSameAge( p3 ) ); } } |
-
- main方法詳解
主函式是靜態的
public static void main(String[] args){
}
主函式是什麼:主函式是一個特殊的函式,作為程式的入口,可以被jvm識別。
主函式的定義:
public :代表該函式的訪問許可權是最大的。
static :代表主函式隨著類的載入,就已經存在了。
void: 主函式沒有具體的返回值
main : 不是關鍵字,是一個特殊的單詞可以被jvm識別。
(String[] args) 函式的引數,引數型別是一個數組,該陣列中的元素是字串。字串型別的陣列。
主函式的格式是固定的:jvm能夠識別
jvm在呼叫函式是,傳入的是new String[0];
可以在dos視窗中執行 java Demo5 hello world 給類Demo5的main方法傳遞2個引數,引數與引數之間通過空格隔開。
class Demo5 {
public static void main(String[] args) {
// 獲取String[] args 陣列長度 System.out.println(args.length);
// 變數args陣列 for (int x = 0; x < args.length; x++) { System.out.println(args[x]); } }
}
class MainTest {
public static void main(String[] args) { // 字串陣列 String[] arr = { "good", "study", "java" };
// 呼叫Demo5類的main方法,傳遞引數。 Demo5.main(arr);
} }
|
- 單例設計模式
一些人總結出來用來解決特定問題的固定的解決方案。
解決一個類在記憶體中只存在一個物件,想要保證物件的唯一。
1 為了避免其他程式過多的建立該類物件。禁止其他程式建立該類物件。
2 為了其他程式可以訪問該類物件,在本類中自定義一個物件。
3 方便其他程式對自定義類的物件的訪問,對外提供一些訪問方式。
程式碼:
1將建構函式私有化
2在類中建立一個私有的本類物件
3提供一個用類名呼叫的公有方法獲取該物件。
class Single {
private static Single s = new Single(); // 惡漢式
private Single() {
}
public static Single getInstance() { return s; } }
class Single2 { private static Single2 s = null; // 懶漢
private Single2() {
}
public static Single2 getInstance() { if (s == null) { s = new Single2(); } return s; } } |
- 繼承
- 類和類之間的常見關係。
1:既然繼承是描述類和類之間的關係,就需要先來了解類和類之間的常見關係
-
-
- 現實生活的整體與部分
-
舉例說明
1:現實生活
1:學生 是人
2:狗 是動物
3:球隊 包含 球員 整體與部分的關係,部分可以刪除和增加
4:筆記本包含 cpu 整體與部分的關係,部分不可以刪除和增加
5:航母編隊 包含(航母 護衛艦 驅逐艦 艦載機 核潛艇)
-
-
- java中的類與類關係
-
java中的類關係
1:is a 關係 (學生是人)
2:has a 整體與部分
class Person{ String name; int age; Address add;
Person(){
} Person(String name,int age,Address add){
this.name=name; this.age=age; this.add=add;
}
void speak(){ System.out.println("姓名:"+name+" 年齡:"+age+" "+add.print()); } } class Address{ String country; String city; String street;
Address(){
} Address(String country,String city,String street){ this.country=country; this.city=city; this.street=street; }
String print(){ return "地址:"+country+" "+"城市:"+city+" 街道;"+street; } } class Demo3{
public static void main(String[] args){
Address add=new Address("中國","廣州","棠東東路"); Person p=new Person("jack",27,add); p.speak();
System.out.println(); } } |
-
- 繼承
1:描述一個學生類
1:姓名年齡學號屬性,學習的方法
2:描述一個工人類
1:姓名年齡工號屬性,工作的方法
3:描述一個人類
1:姓名年齡屬性,說話的方法。
4:發現學生類和人類天生有著聯絡,學生和工人都是人。所以人有的屬性和行為學生和工人都會有。出現類程式碼重複
class Person { String name; int age;
// 靜態變數(類變數)物件和物件之間的程式碼重複使用靜態變數 static String country = "CN";
Person() {
}
void speak() { System.out.println(name + ":哈哈,我是人!!!"); }
}
// 讓學生類和人類產生關係,發現學生is a 人,就可以使用繼承 class Student {
String name; int age;
Student() {
}
void study() { System.out.println("姓名:" + name + "年紀:" + age + ":好好學習"); } }
class Worker { String name; int age;
void work() { System.out.println(name + ":好好工作,好好掙錢。"); }
}
class Demo1 {
public static void main(String[] args) { Student s = new Student(); s.name = "jack"; s.age = 20; s.study();
Worker w = new Worker(); w.name = "rose"; |