天天看點

黑馬程式員_Java基礎_面向對象,封裝,繼承,單例設計模式,構造函數,構造代碼塊

一,面向對象

1,基本了解

面向對象其實是一種思想,現實生活中我們所看到的東西,包括想到的一個概念都可以看做是一個對象。

如果有人問到你對面向對象的了解,可以舉一個例子說明,比如:我們去餐館就餐,首先我們需要叫來服務員點菜,因為服務員具備點菜的功能,點完餐後,服務員會将菜單給廚師,廚師具有做飯的功能,會根據你的選擇做出你想吃的東西,然後服務員給你上菜,你就可以開始吃了。這其中的面向對象包括你調用服務員的點菜方法,服務員又調用廚師做菜的方法,你又調用服務員傳菜的方法,這一切都是面向對象,而你不用去管服務員是如何做的,更不用去管廚師是怎麼做的,你隻需要調用服務員的相應功能得到飯即可。

2,其實開發過程中實際就是找對象,調用對象的某些功能實作我們的需求。

如果沒有對象,我們隻需要造出一個對象,然後在對象中寫出實作我們需求的功能局可以了。

3,java中對對象的描述:是通過類的形式描述的。對事物的描述通常隻需要關注事物的屬性和行為兩個方面。

4,java中類與對象的關系:

類:對現實生活中事物的描述。

對象:就是這類事物,實實在在存在個體。

5,對事物描述的舉例:

需求:對小汽車的描述。

分析:屬性--輪胎數。行為--運作。

定義類其實就是定義類中的成員,成員包括成員變量(屬性)和成員方法(行為)。

成員變量特點:(1)定義在類中,整個類都可以通路。(2)存在于對記憶體的對象中,并且随着對象的

建立而存在,随着對象的消失而消失。(3)成員變量都有預設的初始值。

局部變量:(1)定義在函數,語句,局部代碼塊中,隻有所屬的區域有效。(2)存在于棧記憶體中,随

着所屬區域的執行而存在,結束而釋放。(3)局部變量沒有預設初始化值。

class Car
{
	//描述顔色
	String color = "紅色";
	//描述輪胎數
	int num = 4;

	//運作行為。
	void run()
	{

		System.out.println(color+".."+num);
	}
	
}
class  CarDemo
{
	public static void main(String[] args) 
	{
		//建立car對象,調用run方法
		Car car = new Car();
		c.run();
		c.color = "白色";
		c.run();
	}
}
           

6,匿名對象的使用

匿名對象使用方式一:當對對象的方法隻調用一次時,可以用匿名對象來完成,這樣寫比較簡化。

如果對一個對象進行多個成員調用,必須給這個對象起個名字。

匿名對象使用方式二:可以将匿名對象作為實際參數進行傳遞。

class Car
{
	//描述顔色
	String color = "紅色";
	//描述輪胎數
	int num = 4;

	//運作行為。
	void run()
	{

		System.out.println(color+".."+num);
	}
	
}
class  CarDemo
{
	public static void main(String[] args) 
	{
		//建立car對象,調用run方法
		Car car = new Car();
		c.run();
		c.color = "白色";
		c.run();

		//使用匿名内部類調用run方法
		new Car().run();
	}
}
           

二,面向對象的特性之封裝

1,封裝:是指隐藏對象的屬性和實作細節,僅對外提供公共通路方式。

2,封裝的好處:将變化隔離,便于使用,提高重用性,提高安全性。

3,封裝的原則:将不需要對外提供的内容都隐藏起來。

把屬性都隐藏,提供公共方法對其通路。

4,private通路修飾符隻是用于修飾類中的成員(成員變量,成員函數),并且隻在本類中有效。

使用private将成員變量設定為私有通路權限,通過get和set方法提供擷取和設定成員變量的方法,set方法的傳回類型是void,get方法傳回類型是成員變量的類型。

私有僅僅是封裝的一種表現形式,不可将私有了解成是封裝。

class Person
{
	private int age;
	public void setAge(int a)
	{
		if(a>0 && a<130)
		{
			age = a;
			speak();
		}
		else
			System.out.println("年齡錯誤");
	}

	public int getAge()
	{
		return age;
	}
	private void speak()
	{
		System.out.println("age="+age);
	}
}

class Test1
{
	public static void  main(String[] args)
	{
		Person p = new Person();

		//p.age = -20;
		p.setAge(-40);
		//p.speak();
	}
}
           

三,構造函數以及構造代碼塊的使用

1,構造函數:建立對象時調用的函數。

作用:對對象進行初始化。

一個類中如果沒有定義構造函數,那麼該類中會有一個預設的無參數的構造函數。

如果類中定義了指定的構造函數,則預設的構造函數則不存在了。

2,構造函數與一般的函數的差別:

(1)構造函數在對象建立時就會調用與之對應的構造函數,對對象進行初始化。

而一般函數在對象建立後,需要函數功能時才調用。

(2)構造函數在對象建立時,隻調用一次,并且隻會調用一次,而一般函數在對象建立後可以被

多次調用。

3,什麼時候定義構造函數?

在描述事物時,該事物已存在就具備了一些内容,這些内容都定義在構造函數中,構造函數可以有

多個,對于不同的對象進行針對性的初始化。多個構造函數在類中是以重載的形式展現的。

4,需要注意的是:一般函數是不能調用構造函數的,如果構造函數前面加了傳回值類型,就變成了

一般的函數。構造函數中是有return語句的。

5,構造代碼塊的使用;

作用:給對象進行初始化。

對象一建立就運作,而且優先于構造函數執行。

和構造函數的差別:

構造代碼塊是給所有對象進行統一初始化,

而構造函數是給對應的對象初始化。

構造代碼快中定義的是不同對象共性的初始化内容。

class Person
{
	private String name;
	private int age;
	//構造代碼塊:該代碼塊會在每次建立對象的時候先執行一次,然後構造函數才執行
	{
		cry();
	}

	Person()
	{
		System.out.println("A: name="+name+",age="+age);
		
	}

	Person(String n)
	{
		name = n;
		System.out.println("B: name="+name+",age="+age);
	}

	Person(String n,int a)
	{
		name = n;
		age = a;
		System.out.println("C: name="+name+",age="+age);
	}

	public void cry()
	{
		
		System.out.println("cry......");
	}
}

class  Test
{
	public static void main(String[] args) 
	{
		Person p1 = new Person();
		Person p2 = new Person("lisi");	
	}
}
           

四,面向對象之單例設計模式

1,java中一共有23中設計模式。所謂的設計模式就是解決一類問題的行之有效的方法。

2,單例設計模式是23中設計模式中的一種,它是用來解決記憶體中隻存在某一個對象。

3,保證記憶體中對象的唯一的方式:

(1)為了避免其他的程式過多的建立該類的對象,先禁止其它程式建立該類對象。方法是将構造函數私有化。

(2)為了讓其他程式可以通路到到該類對象,隻好在自己的類中建立一個該類對象。方法是自定義一個類。

(3)為了讓其他程式對自定義的對象的通路,可以對外提供通路該類的方式。提供一個方法可以擷取該對象。

示例代碼:

public class SingleDemo {

	public static void main(String[] args) {
		
		Single s = Single.getInstance();
		s.setNum(10000);
		System.out.println(s.getNum());
	}

}

class Single {
	private Single() {
	}
	
	static Single single = new Single();
	
	public static Single getInstance() {
		return single;
	}
	
	private int num;
	public void setNum(int num) {
		this.num = num;
	}
	public int getNum() {
		return num;
	}	
}
           

使用單例設計模式的時候要注意,程式該怎麼編寫就怎麼編寫,隻需要加上保證記憶體唯一的那一部分代碼即可,是以這三步可以作為一個模闆。

4,單例設計模式——餓漢式,餓漢式是指,在類一加載就已經建立好了對象。

class Single {
	private Single() {
	}
	
	private static Single single = new Single();
	
	public static Single getInstance() {
		return single;
	}
	...
}
           

5,單例設計模式——懶漢式,懶漢式是指在類加載到記憶體時,對象還沒有被建立,而是調用擷取對象的方法時才建立對象。也叫做對象的延遲加載。

class Single {
	private Single() {
	}
	
	private static Single single = null;
	
	public static Single getInstance() {
		if(single == null) {
			synchronized (Single.class) {
				if(single == null)
					single = new Single();
			}
		}
		return single;
	}
	...
}
           

單例設計模式原則:在使用單例設計模式的時候建議使用餓漢式。

五,面向對象之繼承

1,java中的繼承隻有單繼承,可以通過人這個例子來了解,因為每個人隻能有一個父親。但是java是支援多重繼承的,也就是一個類可以被多個類繼承,這樣所有的字類就擁有了父類的方法。

之是以不支援多繼承原因是:當繼承多個父類時,如果多個父類中有多個相同的方法,那麼子類就不知道到底使用父類的哪個方法,但是一個父親可以擁有多個孩子。但是java中支援多實作。也就是後面将要講到的接口。

2,繼承的好處是:提高了代碼的複用性,并且讓類與類之間産生了關系,也就有了後面的多态。

3,在使用繼承的時候一定要注意,不要為了擷取其他類的功能,簡化代碼而使用繼承。類與類之間必須要有所屬關系時才使用繼承。

4,繼承中的成員變量的特點

繼承中如果子類出現非私有的和父類相同的成員變量子類要通路本類的成員變量時,使用this關鍵字,要通路父類的成員變量的時候,用super關鍵字。super關鍵字和this關鍵字的用法幾乎一樣,this指的是本類對象的引用,super指的是父類對象的引用。

5,繼承中函數的特點

當子類中出現和父類一模一樣的函數時,當子類對象調用該函數的時候,會運作子類的函數的内容。這種情況叫做重寫。當子類繼承了父類的,沿襲了父類的功能,到了子類中子類具備該功能,但是功能的内容卻和父類不一樣,這時沒有必要重新定義該功能,可以使用重寫父類的該功能。子類覆寫父類的方法時要注意:子類方法的權限要大于父類的方法。靜态隻能覆寫靜态。

6,繼承中構造函數的特點

在對子類進行初始化的時候,父類的構造方法也會運作,因為子類的構造方法的第一句預設調用父類的空參數的構造方法。子類的所有構造函數的第一句預設的都是super()。

為什麼子類中一定要通路父類的構造方法呢?是因為子類可以直接擷取父類中的資料,是以子類在建立對象的時候,要先檢視父類是如何對這些資料進行初始化的。所有的子類的在建立對象的時候要先通路一下父類的構造函數,如果沒有可以手動通過super關鍵字定義。如果父類中沒有空參數的構造函數,子類構造函數中一定要手動super關鍵字通路父類帶參數的構造函數,而且super關鍵字要放在子類構造函數的第一行。

示例:定義一個Person類,有設定姓名和年齡,父類中定義sayHello方法,子類中重寫該方法,通過子類對象調用。

class Person {
	public String name;
	public int age;
	int num = 12;
	Person(String name,int age) {
		this.name = name;
		this.age = age;
	}


	/*public void setName(String name) {
		this.name = name;
	}


	public void setAge(int age) {
		this.age = age;
	}*/


	public void sayHello() {
		System.out.println(name + ":" + age);
	}
}


class Student extends Person {
	int num = 13;
	Student(String name,int age) {
		super(name,age);
	}
	// 重寫父類中的sayHello方法
	public void sayHello() {
		System.out.println("我叫:" + name + ",今年" + age + "歲了");
		System.out.println(super.num + "::" + this.num);//預設的this,可以省略
	}
}


class Demo {
	public static void main(String[] args) {
		Student s = new Student("zhangsan",25);
		/*s.setName("zhangsan");
		s.setAge(25);*/
		s.sayHello();
	}
}