第三章 面向對象上

第三章 面向對象

3.1面向對象的概念

3.3.1理解面向對象

    1.面向對象是相對面向過程而言

    2.面向對象和麪向過程的區別

       面向過程就是分析出解決問題所需要的步驟,然後用函數把這些步驟一步一步實現,使用的時候一個一個依次調用就可以了。

       面向對象是把構成問題事務分解成各個對象,建立對象的目的不是爲了完成一個步驟,而是爲了描敘某個事物在整個解決問題的步驟中的行爲。

3.3.2面向對象的特點

1、是一種符合人們思考習慣的思想

2、可以將複雜的事情簡單化

3、將程序員從執行者轉換成了指揮者

4、完成需求時:

l先要去找具體所需的功能的對象來用

l如果該對象不存在,那麼創建一個具有所需功能的對象

l這樣簡化開發並提高了複用性

3.3.3面向對象開發,設計,特徵

    1、開發的過程:其實就是不斷創建對象,使用對象,指揮對象做事情

    2、設計的過程:其實就是在管理和維護對象之間的關係

    3、面向對象的特徵:

    封裝(encapsulation):封裝是面向對象的核心思想,將對象的屬性和行爲封裝起來,而它的載體是類,類通常對客戶隱藏細節。

    繼承(inheritance):使用已存在的類的定義作爲建立新技術的基礎,新類的定義可以增加新的數據或功能,也可以使用父類的功能。

    多態(polymorphism):動態綁定機制,用來決定會使用被重寫的方法名的那個方法的行爲。

3.2類與對象的關係

3.2.1類與對象的關係

    1、對象——類的實例

    它是實際存在的該類事物的個體。面向對象程序設計思想是以對象來思考問題,首先將現實世界的屍體抽離爲對象,然後考慮對象具備的行爲和屬性。

    2、類:類是同一類事物的統稱,是構造對象時依賴的規範, 

3.2.2類的定義

1、類定義的內容:

⑴、成員變量:也叫成員域,是對象的屬性

                   ①、類變量:被該類全部共享的變量,也稱靜態成員域,常用於保存所有對象共有的常數值。

②、實例變量:也稱非靜態成員域

             ⑵、方法:也叫成員函數,是對象的行爲。

                 ①、類方法:即使該類對象沒有對象存在時,也可以執行類方法。它也用static進行聲明,因此也被稱爲靜態方法

②、實例方法

3.2.3成員變量和局部變量的區別?

    1.作用範圍:成員變量可以被public,protect,private,static等修飾符修飾,局部變量不能被控制修飾符及static修飾;兩者都可以定義成final型

 2.是否有默認值:成員變量有,局部變量木有

 3.生命週期:成員變量隨對象的建立而存在,隨其消失而消失;局部變量隨所屬區域的執行而產生,隨其釋放而釋放

 4.存儲位置:成員變量存儲在堆,局部變量存儲在棧

3.2.4匿名對象

    1、其實就是定義對象的簡寫格式:new 對象名();

    2、使用場景:①、當對象方法僅進行一次調用時,就可以簡化成匿名對象

 ②、可以作爲實際參數進行傳遞

3.2.5參數傳遞——值調用

     1、值調用將實際參數的內容拷貝到被調用方法

 2、基本數據類型:創建時存儲於棧中。在調用時,會將將其copy拷貝到被調用方法的棧中。然後方法method根據傳過來的參數進行方法的執行。

 3、引用數據類型:引用類型的引用存儲於棧中,而對象則是存儲與堆中在調用時,會對象的地址拷貝到被調用方法的棧中。然後方法method根據傳過來的參數進行方法的執行。

3.3 封裝

 1、定義:隱藏對象的屬性和實現細節,對外提供公共的訪問方式

class Person{
//隱藏age這個屬性,一旦有屬性,幾乎都封裝,
private int age;
//提供對外訪問方式,是爲了可控
public void setAge(int a) {
age = a;
}
public int getAge(){
return age;
}

   2、好處

n將變化隔離。

n便於使用

n提高重用性

n提高安全性

原則

l將不需要對外提供的內容都隱藏起來。

l把屬性都隱藏,提供對外訪問方式。

4、private關鍵字

n作用:利用private關鍵字,可以修飾成員,私有的內容只在本類中有效。

n封裝與私有的關係:私有是封裝的子集,私有僅僅是封裝的一種體現而已

n在java中最小的封裝體是函數。

3.4 構造函數

 1、特點:⑴函數名與類名相同

          ⑵不定義返回值類型,沒有具體的返回值

 2、作用:給對象進行初始化,創建對象都必須要通過構造函數初始化

 3、默認構造函數:一個類中如果沒有定義過構造函數,那麼該類會有一個默認的空參構造函數,如果定義了,類中就沒有默認的啦。

 4、與一般函數的區別:⑴構造函數:對象創建時,就會調用與之對應的構造函數,對對象進行初始化,一般函數:對象創建後,需要函數功能時才調用。

⑵構造函數在對象創建時會調用,而且只調用一次;一般函數在對象創建後,可調用多次。

 5、重載:

       什麼時候使用構造函數?在描述事物的時候,該事物一創建,就具備的一些內容,這些內容定義在構造函數中。

 如果構造函數有多個,用於對不同對象進行針對性的初始化,多個函數在類中是以重載的形式來體現的。

 6、注意:⑴、方法的名稱、形式參數的類型及其順序形成了方法的簽名,簽名是唯一

   ⑵、在構造函數前,不能加返回類型。

   ⑶、一般函數不可以調用構造函數,原因是構造函數是對對象初始化函數,不能被調用,非得調用就得用:new 構造函數();但這是廢話、

   ⑷、構造函數中也有return語句。

3.5 this關鍵字

    1、使用場景

      ⑴、當定義類中功能時,該類函數內部要用到調用該函數的對象時,這是用this來表示這個對象,即本類功能內部用到本類對象的時候,用this。 

        ①、區分同名的局部變量與成員變量,this代表本類的對象,到底代表哪一個?this代表它所在函數所屬對象的引用。簡單說:哪個對象在調用this所在的函數,this就代表哪個對象

        ②、在本類方法中使用對象,用this。

        ③、凡是被對象調用的方法,在內存中都有this所屬

     ⑵用於構造函數間的相互調用

  2、注意:this只能放在構造函數中第一個,因爲初始化動作要先執行

    3、代碼示例

class Person{
private int age;
private String name;
/*public Person(int age) {
this.age = age;
}*/
Person(String name){
this.name = name;//將局部的賦給對象的變量
}
Person(String name, int age){
//Person(name);這是一般函數間的調用
this(name);//這是構造函數間的互相調用,在這裏,this(name)相當於p(name),也就是new Person(name);
this.age = age;
}
public void shout(){
System.out.println("My age is "+age+"\nMy name is "+name);
}
/*
* 需求:給人定義一個用於比較年齡是否相同的功能
*
public boolean compare(Person p){
return this.age == p.age;
}*/
}
public class AboutThisKey {
public static void main(String[] args) {
/*Person p1 = new Person(20);
Person p2 = new Person(25);
boolean b = p1.compare(p2);
System.out.println(b);
*/
Person p = new Person("lisi",30);
// Person p1 = new Person("zhangsan");
p.shout();
// p1.shout();
//爲什麼p1不打印My age is 0 My name is lisi,而p不打印My age is 0 My name is zhangsan
//在一個類裏面,成員之間互相調用時都是對象完成的,所以shout放完的是某一個對象中的name和age,即name和age之前省略了this
}
}

3.6 static關鍵字

1、共享數據:static用於修飾成員(成員函數,成員變量),這些成員都是被對象共享的成員。

2、特點

       ①、隨類的加載而加載,消失而消失。

       ②、優先於對象而存在

       ③、被所有對象所共享

       ④、可以直接被類名所調用

       代碼示例

class Chinese
{
static String country = "中國";//共享數據
String name;
int age;
void singOurCountry(){
System.out.println("啊,親愛的"+country);
}
}
public class AboutStaticKey {
public static void main(String[] args) {
System.out.println(Chinese.country);
//當成員被靜態修飾後,除了可以被對象調用之外,還可以被類名調用
Chinese ch = new Chinese();
System.out.println("Chinese country is " + ch.country);
ch.singOurCountry();
}
}

    3、實例變量與類變量的區別

       ①、存儲位置:前者隨對象的建立而存在於堆內存中;後者隨着類的加載而存在於方法區中

       ②、生命週期;前者隨着對象的消失而消失;後者隨着類的的消失而消失

       ③、調用方式:前者可以被對象及類名調用,但建議用類名調用;後者只能被對象調用

   4、靜態的使用注意事項:

      ①、靜態的方法只能訪問靜態成員

      ②、靜態方法中不可以使用this或super關鍵字

      ③、靜態省略的是類名,成員變量省略的是this

      ④、主函數是靜態的

        public static void main(String[] args)

        1)、public:代表着該函數的權限最大

        2)、static:代表主函數歲類的加載而加載就已經存在

        3)、void:主函數沒有返回值

        4)、main:不是關鍵字,是一個特殊的單詞,可以被jvm識別。

        5)、String[] args:函數的參數,參數類型是一個數組,該數組中的元素師字符串,字符串類型的數組。

    5 、靜態的利弊

       ①、利:對對象的共享數據進行單獨空間的存儲,節省空間,可以被類名直接調用。

       ②、弊:生命週期過長,而且訪問有侷限性

    6、什麼時候使用靜態?

       ①、靜態變量:如果對象中出現共享數據時,該數據被靜態修飾,對象中的特有數據定義在堆內存中

       ②、靜態函數:函數是否用靜態修飾,就看該函數功能是否需要訪問對象中的特有數據,需要,該功能爲非靜態;不需要,就定義成靜態

   7、靜態代碼塊

      ①、格式:static{

                   code

               }

      ②、特點:隨類的加載而執行,且只執行一次,並優先於主函數而執行

      ③、作用:給類進行初始化

   8、面試題

class StaticCode {
StaticCode(){
//因爲沒有創建過與之相關的對象,從而沒有被執行過,所以不打印b
System.out.println("b");
}
static{//靜態代碼塊給類初始化
System.out.println("a");
}
{//構造代碼塊給對象初始化,其優先級比構造函數高,因爲構造函數有針對性,而構造代碼塊可以初始化所有對象
System.out.println("c");
}
StaticCode(int x){//構造函數給對應的對象初始化
System.out.println("d");
}
public static void show(){
System.out.println("show run");
}
}
class StaticCodeDemo {
public static void main(String[] args) {
new StaticCode(4);
}
}
問打印結果是?爲什麼?
結果:a c d,

3.7 單例設計模式

    1、設計模式:解決一類問題最行之有效的方法

    2、單例設計模式:保證內存中只有一個對象

    3、原因:以配置文件爲例,

    4、如何保證對象的唯一性?

       1)、不允許其他程序用new建立該類對象

       2)、爲了讓其他程序可以訪問到該類對象,在本類中,定義一個對象

       3)、爲了讓其他程序對自定義對象可以訪問,可以對外提供一些訪問方式

    5、以上3部怎麼用代碼體現?

       1)、將構造函數私有化

       2)、在類中創建一個本類對象

       3)、提供一個方法可以獲得該對象

 6、模式:

①餓漢式:定義單例時,建議使用餓漢式

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

 ②懶漢式:對象的延時加載,懶漢式在面試的時候考的最多

class Singleton{
private int num;
public int getNum() {
return num;
}
public void setNum(int num) {
this.num = num;
}
private Singleton(){}
private static Singleton s = null;
public static  Singleton getInstance(){
if(s==null){
synchronized(Singleton.class){
if(s==null)
s = new Singleton();
}
}
return s;
}
}
public class SingletonPattern {
public static void main(String[] args) {
Singleton s1 = Singleton.getInstance();
Singleton s2 = Singleton.getInstance();
s1.setNum(30);
System.out.println(s2.getNum());
}
}

3.8 繼承

3.8.1繼承的概述

 1、繼承:Java繼承是使用已存在的類的定義作爲基礎建立新類的技術,新類的定義可以增加新的數據或新的功能,也可以用父類的功能,但不能選擇性地繼承父類。

 2、繼承的優點

        ①、提高了代碼的複用性

        ②、讓類與類之間產生了關係,有了這關係,纔有了多態的特性

       注意:千萬別因爲要獲取其他類 的功能,簡化代碼而繼承,必須是類與類之間有所屬關係纔可以繼承。

 3、父類,也稱爲基類,或超類

 4、 聚集關係:關聯的一種形式,代表兩個類之間的整體 / 局部關係。聚集暗示着整體在概念上處於比局部更高的一個級別,而關聯暗示兩個類在概念上位於相同的級別。

    有兩種特殊聚集:共享聚集和組合聚集。

l共享聚集:它的“部分”對象可以是多個任意“整體”對象的一部分

l組合聚集:整體擁有各部分,部分與整體共存。

3.8.2繼承的特點

 1、java語言:只支持單繼承,不支持多繼承,因爲多繼承容易帶來安全隱患:當多個父類中定義相同功能,而功能的內容不同,子類不確定要運行哪一個但是java保留了這種機制,並以另一種體現形式來完成表示,多實現

 2、java支持多層繼承,也就是一個繼承體系。如何使用一個繼承體系中的功能?想要使用體系,先查閱體系父類的描述,因爲父類定義了該體系的共性功能,通過了解共性功能,就可以知道該體系的基本功能。在具體調用時,要創建最子類對象,其原因是父類有可能創建不了對象,另外創建子類可以使用更多的功能。

 3、子父類出現,類成員的特點:

        ⑴、變量:如果子父類中出現非私有的同名成員變量時,子類要訪問本類中的變量時用this,子類要訪問父類中的變量時用super。他們倆的用法幾乎一致,只是倆代表的引用不同

        ⑵、函數:當子類出現和父類一模一樣的函數時,子類對象調用該函數會運行子類函數的內容,如同父類的函數被覆蓋了一樣,也叫重寫或覆蓋。

    當子類繼承了父類,沿襲了父類的功能,到子類中,但是子類雖具備該功能,但是功能的內容和父類不一致,這時,只需覆蓋父類功能,保留父類的功能定義,並重寫功能內容。

    通過函數的複寫可以提高擴展性

    覆蓋注意事項:

      1)、子類的權限必須大於等於父類的權限,纔可以覆蓋。

      2)、靜態只能覆蓋靜態

      3)、重載只看同名函數的參數列表,而重寫的子父類方法必須一模一樣

    ⑶、構造函數:

子父類的構造函數是不可能一樣的,因爲構造函數的函數名與類名一致。在對子類對象進行初始化時,父類的構造函數也會運行。其原因是在子類構造函數默認的第一行有一條隱式的語句super(注意當第一行是this(),就沒有super()),super會訪問父類中空參數的構造函數。

    爲什麼子類一定要訪問父類的構造函數?因爲父類中的數據子類可以直接獲取,所以子類對象在建立時,需要先查看父類是如何對這些數據進行初始化的的,所以子類在對象初始化時,要先訪問父類的構造函數。如果要訪問父類中指定構造函數,可以通過手動定義super語句來。

3.8.3 super關鍵字

    1、應用

          ⑴、在子類的構造方法內部引用父類的構造方法,如果要引用super的話,必須把super放在函數的首位.

class Base {
Base() {
System.out.println("Base");
}
}
public class Checket extends Base {
Checket() {
super();//調用父類的構造方法,一定要放在方法的首個語句
System.out.println("Checket");
}
public static void main(String argv[]) {
Checket c = new Checket();
}
}

          ⑵、在子類中調用父類中的成員方法或成員變量

class Country {
String name;
void value() {
name = "China";
}
}
class City extends Country {
String name;
void value() {
name = "Hufei";
super.value();//不調用此方法時,super.name返回的是父類的成員變量的值null
System.out.println(name);
System.out.println(super.name);
}
public static void main(String[] args) {
City c=new City();
c.value();
}
}

          ⑶、用super直接傳遞參數

class Fu{
int num;
Fu(int num){
System.out.println("fu run"+"  "+num);
}
void show(){
System.out.println("fu show");
}
}
class Zi extends Fu{
Zi(){
//super();
super(4);// 傳遞參數
System.out.println("zi run");
}
void show(){
System.out.println("zi show");
}
}

        2、注意:

         ⑴、super語句必須放在子類構造函數的第一行

⑵、super和this都只能定義在第一行,所以只能定義一個。

⑶、通過super初始化父類內容時,子類的成員變量並未顯示初始化,等super()父類完畢後,才進行成員變量顯示初始化

3.8.4實例化過程

1、子類的實例化過程:

子類的所有的構造函數,默認都會訪問父類中的空參數的構造函數。因爲子類每一個構造函數的第一行都有一句隱式的super();當父類中沒有空參數的構造函數時,子類必須手動通過super語句形式來指定要訪問的父類中的構造函數。當然,子類的構造函數第一行也可以手動指定this語句來訪問本類中的構造函數,子類中至少會有一個構造函數會訪問父類中的構造函數

2、對象實例化過程——以Person p = new Person();爲例

lJvm會讀取指定路徑下的Person.class文件,並加載進內存,並會先加載Person的父類

l在堆內存中開闢空間,分配地址。

l在對象空間中,對對象中的屬性進行默認初始化

l調用對應的構造函數進行初始化

l在構造函數中,第一行會先到調用父類中構造函數進行初始化

l父類初始化完畢後,再對子類的屬性進行顯示初始化

l在進行子類構造函數的特定初始化

l完畢後,將地址值賦給引用變量

3.8.6 final關鍵字

     1、final修飾的類不可以繼承

     2、final修飾的方法不可以覆蓋

     3、final修飾的變量是一個常量,只能賦值一次,且只固定顯示化賦值

     4、注意:類變量只有在final的修飾下,值纔會固定,否則可以修改,static只能說明該值被共享,但不規定是固定的。

 

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