Java正式上路之物件導向二

小小測試蝦皮糖發表於2020-12-31

1 static關鍵字

1:如果沒有static會怎樣?
	1:定義Person類
		1:姓名、年齡、國籍,說話行為
		2:多個構造,過載形式體現
	2:中國人的國籍都是確定的
		國籍可以進行顯示初始化
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  為了實現物件之間重複屬性的資料共享
	3:static使用
		主要用於修飾類的成員
			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 成員方法

2.1 訪問方式

可以使用類名直接呼叫
	1:靜態函式:
		1:靜態函式中不能訪問非靜態成員變數,只能訪問靜態變數。
		2:靜態方法不可以定義this,super關鍵字.
		3:因為靜態優先於物件存在.靜態方法中更不可以出現this
	2:非靜態函式:非靜態函式中可以訪問靜態成員變數
		1:靜態函式中不能使用非靜態變數
		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.2 為什麼靜態函式中不能訪問非靜態成員

1:static修飾的成員在共享區中。優先於物件存在
2:驗證:使用靜態程式碼塊驗證
	靜態程式碼塊
		static{
			靜態程式碼塊執行語句;
		}
3:靜態程式碼塊特點
	隨著類的載入而載入。只執行一次,優先於主函式。用於給類進行初始化。
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);
	}
}

2.3 static特點

  1. 隨著類的載入而載入,靜態會隨著類的載入而載入,隨著類的消失而消失。說明它的生命週期很長。
  2. 優先於物件存在。–>靜態是先存在,物件是後存在。
  3. 被所有例項(物件)所共享。
  4. 可以直接被類名呼叫

2.4 靜態變數(類變數)和例項變數的區別:

  1. 存放位置
    1:類變數隨著類的載入而載入存在於方法區中.
    2:例項變數隨著物件的建立而存在於堆記憶體中.
  2. 生命週期
    1:類變數生命週期最長,隨著類的消失而消失.
    2:例項變數生命週期隨著物件的消失而消失.

2.5 靜態優缺點

  1. 優點:對物件的共享資料進行單獨空間的儲存,節省空間 例如Person 都有
    國籍。該資料可以共享可以被類名調
  2. 缺點:生命週期過長
    訪問出現侷限性。(靜態只能訪問靜態)

2.6 什麼時候定義靜態變數

靜態變數(類變數)當物件中出現共享資料
例如:學生的學校名稱。學校名稱可以共享
物件的資料要定義為非靜態的存放在對記憶體中(學生的姓名,學生的年齡)

2.7 什麼時候定義靜態函式

如果功能內部沒有訪問到非靜態資料(物件的特有資料。那麼該功能就可以定義為靜態)

2.8 靜態的應用

自定義陣列工具類

/*
	定義陣列工具類
	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 ) );
	}
}

3 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);
	}
}

4 單例設計模式

一些人總結出來用來解決特定問題的固定的解決方案。解決一個類在記憶體中只存在一個物件,想要保證物件的唯一。

  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;
	}
}

5 繼承

5.1 類和類之間的常見關係

既然繼承是描述類和類之間的關係,就需要先來了解類和類之間的常見關係

5.1.1 現實生活的整體與部分

舉例說明

現實生活中
1:學生   是人  
2:狗     是動物
3:球隊 包含 球員 整體與部分的關係,部分可以刪除和增加
4:筆記本包含 cpu 整體與部分的關係,部分不可以刪除和增加
5:航母編隊 包含(航母 護衛艦 驅逐艦 艦載機 核潛艇)

5.1.2 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:描述一個學生類
		 姓名年齡學號屬性,學習的方法
	2:描述一個工人類
		 姓名年齡工號屬性,工作的方法
	3:描述一個人類
		 姓名年齡屬性,說話的方法。
	4:發現學生類和人類天生有著聯絡,學生和工人都是人。所以人有的屬性和行為學生和工人都會有。出現類程式碼重複
	5:問題:
		1:如果沒有繼承,出現類和類的關係無法描述
		2:如果沒有繼承,類和類之間有關係會出現類和類的描述程式碼的重複。
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";
		w.work();
	}
}

5.2 繼承特點

1:描述類和類之間的關係
2:降低類和類之間的重複程式碼
	1:降低物件和物件之間的程式碼重複使用靜態變數
	2:降低類和類之間的程式碼重複使用就繼承

5.3 extends關鍵字

繼承使用extends關鍵字實現
1:發現學生是人,工人是人。顯然屬於is a 的關係,is a就是繼承。
2:誰繼承誰?
學生繼承人,發現學生裡的成員變數,姓名和年齡,人裡邊也都進行了定義。有重 復程式碼將學生類的重複程式碼註釋掉,建立學生類物件,仍然可以獲取到註釋的成員。這就是因為繼承的關係,學生類(子類)繼承了人類(父類)的部分

class Person {
	String name;
	int age;
	// 靜態變數(類變數)物件和物件之間的程式碼重複使用靜態變數
	static String country = "CN";
	Person() {
	}
	void speak() {
		System.out.println(name + ":哈哈,我是人!!!");
	}
}

// 讓學生類和人類產生關係,發現學生is a 人,就可以使用繼承
class Student extends Person {
	Student() {
	}
	void study() {
		System.out.println("姓名:" + name + "年紀:" + age + ":好好學習");
	}
}

class Worker extends Person {
	void work() {
		System.out.println(name + ":好好工作,好好掙錢。");
	}
}

class Demo1 {
	public static void main(String[] args) {
		Student stu = new Student();
		stu.name = "jack";
		stu.age = 20;
		stu.study();
		stu.speak();
		System.out.println(stu.country);
		System.out.println(Student.country);

		Worker worker = new Worker();
		worker.name = "rose";
		System.out.println(worker.country);
		worker.work();
		worker.speak();

		System.out.println();
	}
}
  • 類名的設定,被繼承的類稱之為父類(基類),繼承的類稱之為子類
  • 子類並不能繼承父類中所有的成員
    • 父類定義完整的成員 靜態成員,非靜態,構造方法。靜態變數和靜態方法都可以通過子類名.父類靜態成員的形式呼叫成功。
    • 所有的私有成員不能繼承,private修飾的成員。
    • 建構函式不能被繼承

5.4 如何使用繼承

不要為了使用繼承而繼承。工人和學生都有共性的成員,不要為了節省程式碼,讓工人繼承學生。

/*
如何使用繼承:驗證是否有 is  a 的關係
 例如:學生是人, 小狗是動物
 注意:不要為了使用某些功能而繼承,java只支援單繼承
 */
class DK {
	void Ip4S() {
		System.out.println("好玩");
	}
}

class BGir extends DK {
}

class Demo {
	public static void main(String[] args) {
		new BGir().Ip4S();
	}
}

5.5 super關鍵字

1:定義Father(父類)類
	1:成員變數int x=1;
	2:構造方法無參的和有參的,有輸出語句
2:定義Son類extends Father類
	1:成員變數int y=1;
	2:構造方法無參和有參的。有輸出語句
	1:this.y=y+x;
3:建立Son類物件
	Son son=new Son(3);
	System.out.println(son.y); //4
class Father {
	int x = 1;
	Father() {
		System.out.println("這是父類無參構造");
	}
	Father(int x) {
		this.x = x;
		System.out.println("這是父類有參構造");
	}
	void speak() {
		System.out.println("我是父親");
	}                  
}

class Son extends Father {
	int y = 1;
	Son() {
		System.out.println("這是子類的無參構造");
	}
	Son(int y) {
		this.y = y + x;
		System.out.println("這是子類的有參構造");
	}
	void run() {
		super.speak(); // 訪問父類的函式
		System.out.println("我是兒子");
	}
}

class Demo6 {
	public static void main(String[] args) {
		Son s = new Son(3);
		System.out.println(s.y);// 4
	}
}
4:子類物件為什麼可以訪問父類的成員。
	1:this.y=y+x;有一個隱式的super super.x

5:super關鍵字作用
	1:主要存在於子類方法中,用於指向子類物件中父類物件。
	2:訪問父類的屬性
	3:訪問父類的函式
	4:訪問父類的建構函式

super注意點

  1. this和super很像,this指向的是當前物件的呼叫,super指向的是當前呼叫物件的父類。Demo類被載入,執行main方法,Son.class載入,發現有父類Father類,於是Father類也載入進記憶體。類載入完畢,建立物件,父類的構造方法會被呼叫(預設自動無參),然後執行子類相應構造建立了一個子類物件,該子類物件還包含了一個父類物件。該父類物件在子類物件內部。this super只能在有物件的前提下使用,不能在靜態上下文使用。
  2. 子類的建構函式預設第一行會預設呼叫父類無參的建構函式,隱式語句super();
    父類無參建構函式不存在,編譯報錯。
Son(int y) {
	//super();隱式語句
	this.y = y + x;
	System.out.println("這是子類的有參構造");
}
  1. 子類顯式呼叫父類建構函式
    在子類建構函式第一行通過super關鍵字呼叫父類任何建構函式。如果顯式呼叫父類建構函式,編譯器自動新增的呼叫父類無引數的構造就消失。建構函式間的呼叫只能放在第一行,只能呼叫一次。super() 和this()不能同時存在建構函式第一行。
Son(int y) {
	super(y);// 子類顯式呼叫父類建構函式
	this.y = y + x;
	System.out.println("這是子類的有參構造");
}

Son(int y) {
	this();  //不能同時存在建構函式第一行  
	super(y);
	this.y = y + x;
	System.out.println("這是子類的有參構造");
}
  1. super思考
    如果開發者自定義了一個類,沒有顯示的進行類的繼承,那麼該類中成員函式是否可以使用super關健健字?可以使用,繼承了Object類,Object類是所有類的父類。
class Demo7 {
	public  void print(){
		System.out.println(super.toString());
	}
	public static void main(String[] args){
		new Demo7().print();
		System.out.println();
   	}
}

6. 重寫(Override)

1:定義Father類
	1:姓名,吃飯方法,吃窩窩頭。
	2:定義Son類,繼承Father
		1:Son類中不定義任何成員,子類建立物件,仍然可以呼叫吃飯的方法。
		2:父類的吃飯的方法,Son不願吃。Son自己定義了吃飯的方法。
2:此時父類中有一個吃飯的方法,子類中有2個吃飯的方法,一模一樣,只是方法體不一樣。一個類中兩個函式一模一樣,是不允許的。
	1:編譯執行,執行了子類的方法。
	2:使用父類的方法,在子類方法中,使用super.父類方法名。
class Father {
	String name;
	void eat() {
		System.out.println("吃窩窩");
	}
}

class Son extends Father {
	public void eat() { // 繼承可以使得子類增強父類的方法
		System.out.println("來倆小菜");
		System.out.println("來兩杯");
		System.out.println("吃香喝辣");
		System.out.println("來一根");
	}
}

class Demo8 {
	public static void main(String[] args) {
		Son s = new Son();
        //執行子類的方法
		s.eat();
	}
}
3:該現象就叫做重寫(覆蓋 override)
	1:在繼承中,子類可以定義和父類相同的名稱且引數列表一致的函式,將這種函式稱之為函式的重寫.
4:前提:必須要有繼承關係
5:特點:
	1:當子類重寫了父類的函式,那麼子類的物件如果呼叫該函式,一定呼叫的是重寫過後的函式。
   可以通過super關鍵字進行父類的重寫函式的呼叫。
	2:繼承可以使得子類增強父類的方法
6:細節
	1:函式名必須相同
	2:引數列表必須相同
	3:子類重寫父類的函式的時候,函式的訪問許可權必須大於等於父類的函式的訪問許可權否則編譯報錯
	4:子類重寫父類的函式的時候,返回值型別必須是父類函式的返回值型別或該返回值型別的子類。不能返回比父類更大的資料型別: 如子類函式返回值型別是Object
		1:定義 A B  C 類 B extends A  
		2:Father類中定義A getA();
		3:Son 類中重寫getA(); 方法,嘗試將返回值修改為B,C ,Object
			1:B編譯通過
			2:C 編譯失敗,沒有繼承關係
			3:Object編譯失敗,比父類的返回值型別更大
class A {
}

class B extends A {
}

class C {
}

class Father {
	String name;
	void eat() {
		System.out.println("吃窩窩");
	}
	// 定義一個函式,獲取A類的物件,
	A getA() {
		return new A();
	}
}

class Son extends Father {
	public void eat() { // 繼承可以使得子類增強父類的方法
		System.out.println("來兩杯");
		System.out.println("來倆小菜");
		super.eat();
		System.out.println("來一根");
	}
	// B類是A類的子類
	B getA() {
		return new B();
	}
}

class Demo8 {
	public static void main(String[] args) {
		Son s = new Son();
		s.eat();
	}
}
7:子類物件查詢屬性或方法時的順序:
	1:原則:就近原則。
		如果子類的物件呼叫方法,預設先使用this進行查詢,如果當前物件沒有找到屬性或方法,找當前物件中維護的super關鍵字指向的物件,如果還沒有找到編譯報錯,找到直接呼叫。
8:過載和重寫的不同
	1:過載(overload):  
		1:前提: 所有的過載函式必須在同一個類中 
    	2:特點: 
	       函式名相同,引數列表不同,與其他的無關(訪問控制符、返回值型別)
		3:不同:個數不同 、 順序不同、 型別不同 
	2:重寫(override):
     	1:前提: 繼承
		2:特點:
	      函式名必須相同、引數列表必須相同。
		  子類的返回值型別要等於或者小於父類的返回值

重寫練習

描述不同的動物不同的叫法
	1:定義動物類
		有名字,有吃和叫的方法
	2:定義狗繼承動物重寫父類吃和叫的方法
	3:定義貓繼承動物重寫父類吃和叫的方法
class Animal{
	int x=1;
	String name;
	void eat(){
		System.out.println("吃東西");
	}
	void shout(){
		System.out.println("我是動物");
	}
}

class Dog extends Animal{
	void eat(){
		System.out.println("啃骨頭");
	}
	void shout(){
		System.out.println("旺旺");
	}
	void eat(String food){
		System.out.println("吃:"+food);
	}
}
class Cat extends Animal{
	void eat(){
		System.out.println("吃老鼠");
	}
	void shout(){
		System.out.println("喵喵");
	}
}

class Demo9{
	public static void main(String[] args){
		Dog d=new Dog();
		d.shout();
		d.eat();
		
		Cat c=new Cat();
		c.shout();
		c.eat();
		System.out.println();
     	}
}

7 instanceof 關鍵字

1:快速演示instanceof

Person p=new Person();
System.out.println( p instanceof Person);

2:instanceof是什麼?

  • 屬於比較運算子
  • instanceof關鍵字:該關鍵字用來判斷一個物件是否是指定類的物件。
  • 用法: 物件 instanceof 類;
    該表示式是一個比較運算子,返回的結果是boolea型別 true|false
    注意:使用instanceof關鍵字做判斷時,兩個類之間必須有關係。

3:案例

定義一個功能表函式,根據傳遞進來的物件的做不同的事情,如果是狗讓其看家,如果是貓讓其抓老鼠
	1:定義動物類
	2:定義狗類繼承動物類
	3:定義貓類繼承動物類
	4:定義功能根據傳入的動物,執行具體的功能
	5:instanceof好處   可以判斷物件是否是某一個類的例項	
package oop01;
/*
 instanceof
 比較運算子
 檢查是否是類的物件
 可以判斷物件是否是某一個類的例項
 用法: 物件  instanceof 類; 
 	
案例:
定義一個功能函式,根據傳遞進來的物件的做不同的事情
	如果是狗讓其看家,如果是貓讓其抓老鼠
1:定義動物類
2:定義狗類繼承動物類
3:定義貓類繼承動物類
4:定義功能根據傳入的動物,執行具體的功能
 */

class Animal {
	String name;
	void eat() {
		System.out.println("吃東西");
	}
	void shout() {
		System.out.println("我是動物");
	}
}

class Dog extends Animal {
	void eat() {
		System.out.println("啃骨頭");
	}
	void shout() {
		System.out.println("旺旺");
	}
}

class Cat extends Animal {
	void eat() {
		System.out.println("吃老鼠");
	}
	void shout() {
		System.out.println("喵喵");
	}
}

class Demo11 {
	public static void main(String[] args) {
		Demo11 d = new Demo11();
		// 物件 instanceof 類;
		System.out.println(d instanceof Demo11);
		d.doSomething(new Dog());
		d.doSomething(new Cat());
	}

	// 定義一個功能函式,根據傳遞進來的物件的做不同的事情
	// 如果是狗讓其看家,如果是貓讓其抓老鼠
	// 物件 instanceof 類;
	void doSomething(Animal a) {
		if (a instanceof Dog) {
			a.eat();
			a.shout();
			System.out.println("小狗看家");
		} else if (a instanceof Cat) {
			a.eat();
			a.shout();
			System.out.println("抓老鼠");
		}
	}
}

練習:

byte[] bs = new byte[] { 1, 2, 3 };
int[] is = new int[] { 1, 2, 3 };
String[] ss = new String[] { "jack", "lucy", "lili" };
System.out.println(bs instanceof byte[]); // true
System.out.println(is instanceof int[]); // true
System.out.println(ss instanceof String[]); // true
// System.out.println(bs instanceof int[]); // 不可轉換的型別

8 final關鍵字

1:定義靜態方法求圓的面積
2:定義靜態方法求圓的周長
3:發現方法中有重複的程式碼,就是PI,圓周率。
如果需要提高計算精度,就需要修改每個方法中圓周率。
4:描述一個變數
方法都是靜態的,靜態只能訪問靜態,所以變數也定義為靜態的。
public static double PI=3.14;

  1. 如果定義為public後,新的問題,類名.PI=300; 改變了PI的值。
  2. 修改為private,修改為private後進行了封裝,需要getset公共訪問方法。
  3. 現有的知識不能解決這樣的問題了。可以使用final
class Demo12 {
	public static final double PI = 3.14; // 靜態常量
	public static double getArea(double r) {
		return PI * r * r;
	}
	public static double getLength(double r) {
		return PI * r * 2;
	}
	public static void main(String[] args) {
		// Demo12.PI=300; 無法為最終變數 PI 指定值
		System.out.println(Demo12.PI);
	}
}
  1. final關鍵字主要用於修飾類、類成員、方法、以及方法的形參。
  2. final修飾成員屬性:說明該成員屬性是常量,不能被修改。
public static final double PI=3.14;
	1:public :訪問許可權最大
	2:static :記憶體中只有一份
	3:final  :是一個常量
	4:常量名大寫
	5:必須初賦值。

使用類名.成員。修改該成員的值,報錯。–常量不能被修改
1:基本資料型別,final使值不變
2:物件引用,final使其引用恆定不變,無法讓其指向一個新的物件,但是物件自身卻可以被修改。
3:該關鍵字一般和static關鍵字結合使用,常量可以優先載入,不必等到建立物件的時候再初始化。
4:final和static可以互換位置
5:常量一般被修飾為final

  1. fianl修飾類:
    1:該類是最終類,不能被繼承。將父類加final修飾,子類繼承,就會報錯。
    2:檢視api文件發現String類是final的。Integer類也是final的
  • 為了防止程式碼功能被重寫
  • 該類沒有必要進行擴充套件
  1. final修飾方法:
  • 該方法是最終方法,不能被重寫
  • 當一個類被繼承,那麼所有的非私有函式都將被繼承,如果函式不想被子類繼承並重寫可以將該函式final修飾
  • 當一個類中的函式都被修飾為final時,可以將類定義為final的。
class Father2{
	final void eat(){
		System.out.println("eating....");
	}
}
class Son2 extends Father2{
	//該方法是最終方法,不能被重寫
	void eat(){
		System.out.println("eating....");
	}
}
class Demo12 {
	public static void main(String[] args) {
		// Demo12.PI=300; 無法為最終變數 PI 指定值
		System.out.println(Demo12.PI);
		Son2 s=new Son2();
		s.eat();
	}
}
  1. final關鍵字修飾形參
  • 當形參被修飾為final,那麼該形參所屬的方法中不能被篡改。
  • 專案中主要用於一些只用來遍歷未知資料的函式。將未知變數宣告為final的。增強資料的安全性。
class Demo14 {
	public static void main(String[] args) {
		System.out.println();
		String[] arr = { "think in java", "java就業教程", "java核心技術" };
		print(arr);
	}

	// 該方法,列印書名。
	public static void print(final String[] arr) {
		//arr = null; ,無法重新賦值
		for (int x = 0; x < arr.length; x++) {
			System.out.println(arr[x]);
		}
	}
}

相關文章