java學習第五章-java面向對象(僅做個人學習筆記用)

5.1.1 繼承的實現

 面向對象的三大特徵:繼承、封裝、多態

 繼承讓我們更加容易實現類的擴展。 比如,我們定義了人類,再定義Boy類就只需要擴展人類即可。實現了代碼的重用,不用再重新發明輪子(don’t  reinvent  wheels)。

從英文字面意思理解,extends的意思是“擴展”。

 在我們編程中,如果新定義一個Student類,發現已經有Person類包含了我們需要的屬性和方法,那麼Student類只需要繼承Person類即可擁有Person類的屬性和方法。

package cn.nls.oo2;

/**
 * 測試繼承
 * @author 
 *
 */

public class TestExtends {
	public static void main(String[] args) {
		Student stu = new Student();
		stu.name="大哥";
		stu.height=177;
		stu.rest();//休息一會!
		
		Student stu2 = new Student("小弟",222,"高數");
		
		/*測試instanceof*/
		System.out.println(stu2 instanceof Student);//true
		System.out.println(stu2 instanceof Person);//true
		System.out.println(stu2 instanceof Object);//true
		System.out.println(new Person() instanceof Student);//false
	}

}


class Person /*extends Object*/{
	String name;
	int height;
	
	public void rest() {
		System.out.println("休息一會!");
	}
}

class Student extends Person{
	//String name;
	//int height;
	String major;
	
	public void study() {
		System.out.println("學習兩小時!");
	}
	
	//public void rest() {
	//	System.out.println("休息一會!");
	//}
	
	public Student(String name,int height,String major) {
		this.name = name;
		this.height= height;
		this.major = major;
	}
	
	public Student() {
		
	}
}

instanceof是二元運算符,左邊是對象,右邊是類;當對象是右面類或子類所創建對象時,返回true;否則,返回false。 

 5.1.3 繼承使用要點

可以使用ctrl+T方便的查看類的繼承層次結構

1.父類也稱作超類、基類、派生類等。

2.Java中只有單繼承,沒有像C++那樣的多繼承。多繼承會引起混亂,使得繼承鏈過於複雜,系統難於維護。

3.Java中類沒有多繼承,接口有多繼承

4.子類繼承父類,可以得到父類的全部屬性和方法 (除了父類的構造方法),但不見得可以直接訪問(比如,父類私有的屬性和方法)。

5.如果定義一個類時,沒有調用extends,則它的父類是:java.lang.Object

5.1.4 方法的重寫override

子類通過重寫父類的方法,可以用自身的行爲替換父類的行爲。方法的重寫是實現多態的必要條件。

方法的重寫需要符合下面的三個要點:

      1.“==”: 方法名、形參列表相同。

      2.“≤”:返回值類型和聲明異常類型,子類小於等於父類。

      3.“≥”: 訪問權限,子類大於等於父類。

package cn.nls.oo2;


/**
 * 測試重寫(override)/覆蓋
 * @author 
 *
 */
public class TestOverride {
	public static void main(String[] args) {
		Horse h = new Horse();
		h.run();
	}

}

class Vehicle{
	public void run() {
		System.out.println("跑....");
	}
	
	public void stop() {
		System.out.println("停止!");
	}
	
	public Person whoIsPsg() {
		return new Person();
	}
}

class Horse extends Vehicle{
	public void run() {//重寫
		System.out.println("四蹄翻飛,嘚嘚嘚。。。");
	}
	
	public Student whoIsPsg() {//重寫,返回類型student,比Person小,即小於父類類型,可以
		return new Student();
	}
	
}

5.2.1 Object

Object類是所有Java類的根基類,也就意味着所有的Java對象都擁有Object類的屬性和方法。如果在類的聲明中未使用extends關鍵字指明其父類,則默認繼承Object類。

package cn.nls.oo2;

public class TestObject {
	public static void main(String[] args) {
		//Object obj;
		
		TestObject to = new TestObject();
		System.out.println(to.toString());
		
		Person2 p2 = new Person2("狗子",66);
		System.out.println(p2.toString());
	}
	
	public String toString() {//toString的重寫
		return "測試Object對象";
	}

}

class Person2{
	String name;
	int age;
	
	public String toString() {
		return name+",年齡:"+age;
	}
	
	public Person2(String name,int age) {
		this.name = name;
		this.age = age;
	}
}

5.2.3 ==和equals方法

==”代表比較雙方是否相同。如果是基本類型則表示相等,如果是引用類型則表示地址相等即是同一個對象

Object類中定義有:public boolean equals(Object obj)方法,提供定義“對象內容相等”的邏輯。比如,我們在公安系統中認爲id相同的人就是同一個人、學籍系統中認爲學號相同的人就是同一個人。

Object 的 equals 方法默認就是比較兩個對象的hashcode,是同一個對象的引用時返回 true 否則返回 false。但是,我們可以根據我們自己的要求重寫equals方法。

package cn.nls.oo2;

public class TestEquals {
	public static void main(String[] args) {
		Object obj;
		String str;
		
		User u1 = new User(1999,"高琪","123456");
		User u2 = new User(1999,"高息","123456");
		
		System.out.println(u1==u2);//false,false
		System.out.println(u1.equals(u2));//false,重寫後true
		
		String str1 = new String("sxt");
		String str2 = new String("sxt");
		System.out.println(str1==str2);//false
		System.out.println(str1.equals(str2));//true
	}

}


class User{
	int id;
	String name;
	String pwd;

	public User(int id, String name, String pwd) {
		super();
		this.id = id;
		this.name = name;
		this.pwd = pwd;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		User other = (User) obj;
		if (id != other.id)
			return false;
		return true;
	}
	
	
}

  JDK提供的一些類,如String、Date、包裝類等,重寫了Object的equals方法,調用這些類的equals方法, x.equals (y) ,當x和y所引用的對象是同一類對象且屬性內容相等時(並不一定是相同對象),返回 true 否則返回 false。

5.3 super關鍵字

 super是直接父類對象的引用。可以通過super來訪問父類中被子類覆蓋的方法或屬性。

 使用super調用普通方法,語句沒有位置限制,可以在子類中隨便調用。

若是構造方法的第一行代碼沒有顯式的調用super(...)或者this(...);那麼Java默認都會調用super(),含義是調用父類的無參數構造方法。這裏的super()可以省略。

package cn.nls.oo2;

public class TestSuper01 {
	public static void main(String[] args) {
		new ChildClass().f();
	}

}

class FatherClass {
	public int value;
	public void f() {
		value = 100;
		System.out.println("FatherClass.value="+value);//FatherClass.value=100
	}
}

class ChildClass extends FatherClass{
	public int value;
	public void f() {
		super.f();//調用父類對象的普通方法
		value = 200;
		System.out.println("ChildClass.value="+value);//ChildClass.value=200
		System.out.println(value);//200
		System.out.println(super.value);//100,調用父類對象的成員變量
	}
}

 

構造方法調用順序:

      構造方法第一句總是:super(…)來調用父類對應的構造方法。所以,流程就是:先向上追溯到Object,然後再依次向下執行類的初始化塊和構造方法,直到當前子類爲止。

      注:靜態初始化塊調用順序,與構造方法調用順序一樣,不再重複。

package cn.nls.oo2;

public class TestSuper02 {
	public static void main(String[] args) {
	System.out.println("開始創建一個ChildClass對象....");
	new ChildClass02();
	}

}

class FatherClass02{
	public FatherClass02() {
		System.out.println("創建FatherClass02");
	}
}

class ChildClass02 extends FatherClass02{
	public ChildClass02() {
		//super();
		System.out.println("創建ChildClass02");
	}
}

5.4封裝 

我們程序設計要追求“高內聚,低耦合”。 高內聚就是類的內部數據操作細節自己完成,不允許外部干涉;低耦合是僅暴露少量的方法給外部使用,儘量方便外部調用。

編程中封裝的具體優點:

     1. 提高代碼的安全性。

     2. 提高代碼的複用性。

     3. “高內聚”:封裝細節,便於修改內部代碼,提高可維護性。

     4. “低耦合”:簡化外部調用,便於調用者使用,便於擴展和協作。

5.4.2 封裝的實現-使用訪問控制符

Java是使用“訪問控制符”來控制哪些細節需要封裝,哪些細節需要暴露的。 Java中4種“訪問控制符”分別爲private、default、protected、public,它們說明了面向對象的封裝性,所以我們要利用它們儘可能的讓訪問權限降到最低,從而提高安全性。

下面詳細講述它們的訪問權限問題。其訪問權限範圍如表5-1所示。

表5-1 訪問權限修飾符

圖1.png

1. private 表示私有,只有自己類能訪問

2. default表示沒有修飾符修飾,只有同一個包的類能訪問

3. protected表示可以被同一個包的類以及其他包中的子類訪問

4. public表示可以被該項目的所有包中的所有類訪問

代碼1:

package cn.nls.oo2;

/**
 * 測試封裝
 * @author 
 *
 */

public class TestEncapsulation {
	public static void main(String[] args) {
		Human h = new Human();
		//h.age=10;//age不可見
		h.name = "高琪";
		h.Height = 8;
		
	}

}
/*
class Human{
	private int age;
	String name;
	
	void sayAge() {
		System.out.println(age);
	}
}*/

class Boy extends Human{
	void sayHello() {
		//System.out.println(age);//報錯,子類無法使用父類的私有屬性和方法
	}
}

代碼2:

package cn.nls.oo;

import cn.nls.oo2.Human;

public class TestEncapsulation2 {
	public static void main(String[] args) {
		Human h = new Human();
		//h.age=10;//age不可見
		//h.name = "高琪"; //name爲default屬性,不能被不同包的類訪問
		//h.Height = 8;//protected屬性,同包可見,不同包不可見
		h.sayAge();
	}

}

class Girl extends Human{
	void sayGood() {
		System.out.println(Height);
	}
}

代碼3:

package cn.nls.oo2;

public class Human {
	private int age;
	String name;  //,默認default,可以被本包下面的類訪問
	protected int Height;
	
	public void sayAge() {
		System.out.println(age);
	}

}

 5.4.3 封裝的使用細節

 

類的屬性的處理:

      1. 一般使用private訪問權限。

      2.  提供相應的get/set方法來訪問相關屬性,這些方法通常是public修飾的,以提供對屬性的賦值與讀取操作(注意:boolean變量的get方法是is開頭!)。

      3. 一些只用於本類的輔助性方法可以用private修飾,希望其他類調用的方法用public修飾。

javaBean封裝實例

package cn.nls.oo2;

/**
 * 仍然測試測試封裝
 * @author 
 *
 */
public class Person4 {
	private int id;
	private String name;
	private int age;
	private boolean man;
	
	public void setName(String name) {
		this.name = name;
	}
	public String getName() {
		return this.name;
	}
	
	public void setAge(int age) {
		if(age>=1&&age<=130) {
			this.age = age;
		}else {
			System.out.println("請輸入正常的年齡!");
		}
	}
	public int getAge() {
		return this.age;
	}
	
	public int getId() {
		return id;
	}
	public void setId(int id) {
		this.id = id;
	}
	public boolean isMan() {
		return man;
	}
	public void setMan(boolean man) {
		this.man = man;
	}

	
}

5.5 多態 (polymorphism)

多態指的是同一個方法調用,由於對象不同可能會有不同的行爲。

多態的要點:

      1. 多態是方法的多態,不是屬性的多態(多態與屬性無關)。

      2. 多態的存在要有3個必要條件:繼承,方法重寫,父類引用指向子類對象。

      3. 父類引用指向子類對象後,用該父類引用調用子類重寫的方法,此時多態就出現了。

package cn.nls.oo2;
/**
 * 測試多態
 * @author 
 *
 */
public class TestPolym {
	public static void main(String[] args) {
		Animal a = new Animal();
		animalCry(a);//叫了一聲!
		Dog d = new Dog();
		animalCry(d);//旺旺旺
	}
	
	static void animalCry(Animal a) {
		a.shout();
	}

}

class Animal{
	public void shout() {
		System.out.println("叫了一聲!");
	}
}

class Dog extends Animal{
	public void shout() {
		System.out.println("旺旺旺");
	}
}

class Cat extends Animal{
	public void shout() {
		System.out.println("喵喵喵!");
	}
}

展示了多態最爲多見的一種用法,即父類引用做方法的形參,實參可以是任意的子類對象,可以通過不同的子類對象實現不同的行爲方式。

由此,我們可以看出多態的主要優勢是提高了代碼的可擴展性,符合開閉原則。但是多態也有弊端,就是無法調用子類特有的功能,比如,我不能使用父類的引用變量調用Dog類特有的seeDoor()方法。

 5.6 對象的轉型(casting)

 

父類引用指向子類對象,我們稱這個過程爲向上轉型,屬於自動類型轉換。

      向上轉型後的父類引用變量只能調用它編譯類型的方法,不能調用它運行時類型的方法。這時,我們就需要進行類型的強制轉換,我們稱之爲向下轉型!

在向下轉型過程中,必須將引用變量轉成真實的子類類型(運行時類型)否則會出現類型轉換異常ClassCastException。

package cn.nls.oo2;
/**
 * 測試多態
 * @author
 *
 */
public class TestPolym {
	public static void main(String[] args) {
		Animal a = new Animal();
		animalCry(a);//叫了一聲!
		Dog d = new Dog();
		animalCry(d);//旺旺旺
		
		Animal dd = new Dog();//自動向上轉型
		animalCry(dd);
		
		Dog dd2 = (Dog)dd;//強制向下轉型
		//dd.seeDoor();//報錯
		dd2.seeDoor();//
		
		//Animal c = new Cat();
		//Dog dd3 = (Dog)c;//類型轉化錯誤
		//dd3.seeDoor();//報錯
	}
	
	static void animalCry(Animal a) {
		a.shout();
	}

}

class Animal{
	public void shout() {
		System.out.println("叫了一聲!");
	}
}

class Dog extends Animal{
	public void shout() {
		System.out.println("旺旺旺");
	}
	
	public void seeDoor() {
		System.out.println("看門!!");
	}
}

class Cat extends Animal{
	public void shout() {
		System.out.println("喵喵喵!");
	}
}

5.7 final關鍵字

final關鍵字的作用:

      1. 修飾變量: 被他修飾的變量不可改變。一旦賦了初值,就不能被重新賦值。

1

final  int   MAX_SPEED = 120;

      2. 修飾方法:該方法不可被子類重寫。但是可以被重載!

1

final  void  study(){}

      3. 修飾類: 修飾的類不能被繼承。比如:Math、String等。

1

final   class  A {}

5.8 抽象方法和抽象類

 

抽象方法

      使用abstract修飾的方法,沒有方法體,只有聲明。定義的是一種“規範”,就是告訴子類必須要給抽象方法提供具體的實現。

·抽象類

      包含抽象方法的類就是抽象類。通過abstract方法定義規範,然後要求子類必須定義具體實現。通過抽象類,我們就可以做到嚴格限制子類的設計,使子類之間更加通用。

抽象類的使用要點:

     1. 有抽象方法的類只能定義成抽象類

     2. 抽象類不能實例化,即不能用new來實例化抽象類。

     3. 抽象類可以包含屬性、方法、構造方法。但是構造方法不能用來new實例,只能用來被子類調用。

     4. 抽象類只能用來被繼承。

     5. 抽象方法必須被子類實現

package cn.nls.oop;
/**
 * 抽象類的意義就在於:爲子類提供統一的、規範的模板。子類必須實現相關的抽象方法
 * @author 
 *
 */
public abstract class Animal {
	//第一:沒有實現。第二:子類必須實現
	abstract public void shout();
	
	public void run() {
		System.out.println("跑跑");
	} 
	
	public static void main(String[] args) {
		Animal a = new Dog();
	}

}

class Dog extends Animal{

	@Override
	public void shout() {
		System.out.println("汪汪汪");
		
	}

	
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章