java面向對象的三大特性是:封裝、繼承與多態,是面向對象編程的核心。java
簡單說封裝就是將同一類事物的特性與功能包裝在一塊兒,對外暴露調用的接口。面試
封裝:封裝也稱信息隱藏,是指利用抽象數據類型把數據和基於數據的操做封裝起來,使其成爲一個不可分割的總體,數據隱藏在抽象數據內部,儘量的隱藏數據細節,只保留一些接口使其與外界發生聯繫。也就是說用戶無需知道內部的數據和方法的具體實現細節,只需根據留在外部的接口進行操做就行。編程
封裝的好處:ide
1) 實現了專業的分工測試
2) 良好的封裝可以減小耦合this
3) 類內部的結構可以自由修改spa
4) 能夠對成員進行更精確的控制3d
5) 隱藏信息,實現細節調試
定義一個學生類,在類中定義學生身高。code
Student類:
package com.zhangguo.c41; /**學生類*/ public class Student { /**身高*/ public int height; /**展現*/ public void show(){ System.out.println("身高:"+this.height+"cm"); } }
School類型:
package com.zhangguo.c41; public class School { public static void main(String[] args) { Student tom=new Student(); tom.height=189; tom.show(); Student rose=new Student(); rose.height=-398; rose.show(); } }
運行結果:
從示例中能夠看出rose這個學生的對象的身高達-398cm這明顯不科學,將屬性封裝起來,對外提供訪問接口。
若是要保護height這個屬性,能夠將它的訪問修飾符修改成私有的,以下所示:
/**身高*/ private int height;
報錯了:
由於是私有的,只有本類能夠正常訪問,外部訪問不了,能夠定義屬性達到訪問控制與封裝的功能,以下所示:
Student類
package com.zhangguo.c41; /** 學生類 */ public class Student { /** 身高 */ private int height; /** 返回身高屬性 */ public int getHeight() { return this.height; } /** * 設置身高屬性 * * @throws Exception */ public void setHeight(int height) { // 若是參數height大於260或小於0 if (height < 0 || height > 260) { // 輸出錯誤信息 System.out.println("身高只能是0-260之間"); } else { this.height = height; } } /** 展現 */ public void show() { System.out.println("身高:" + this.height + "cm"); } }
學生類:
package com.zhangguo.c41; public class School { public static void main(String[] args) { Student tom=new Student(); tom.setHeight(189); tom.show(); Student rose=new Student(); rose.setHeight(-398); rose.show(); } }
運行結果:
getXXX()得到,setXX(參數)設置
能夠調試查看。
若是在一個類中定義了很是多的屬性,手動封裝是很麻煩的,1個屬性對應2個方法,1個get,1個set。Eclipse中有自動封裝屬性的功能,以下所示:
將鼠標懸停在屬性上,點擊「create getter and setter for xxx」
生成的結果:
package com.zhangguo.c41; /**狗*/ public class Dog { /**名稱*/ private String name; /**價格*/ private float price; /**顏色*/ private String color; //可讀可寫 public float getPrice() { return price; } public void setPrice(float price) { this.price = price; } //只讀 public String getName() { return name; } //只寫 public void setColor(String color) { this.color = color; } }
Java繼承是面向對象的最顯著的一個特徵。繼承是從已有的類中派生出新的類,新的類能吸取已有類的數據屬性和行爲,並能擴展新的能力。JAVA不支持多繼承,單繼承使JAVA的繼承關係很簡單,一個類只能有一個父類,易於管理程序,父類是子類的通常化,子類是父類的特殊化(具體化)
父類(基類):人 子類(派生):學生
學生繼承人,人派生出學生
繼承所表達的就是一種對象類之間的相交關係,它使得某類對象能夠繼承另一類對象的數據成員和成員方法。若類B繼承類A,則屬於B的對象便具備類A的所有或部分性質(數據屬性)和功能(操做),咱們稱被繼承的類A爲基類、父類或超類,而稱繼承類B爲A的派生類或子類。
繼承避免了對通常類和特殊類之間共同特徵進行的重複描述。同時,經過繼承能夠清晰地表達每一項共同特徵所適應的概念範圍——在通常類中定義的屬性和操做適應於這個類自己以及它如下的每一層特殊類的所有對象。運用繼承原則使得系統模型比較簡練也比較清晰。
java使用extends關鍵字標識繼承。
Dog狗
package com.zhangguo.c42; /**狗*/ public class Dog { /**名稱*/ public String name; /**顏色*/ public String color; /**價格*/ public double price; /**顯示信息*/ public void show(){ System.out.println("名稱:"+name+",顏色:"+color); } }
Cat貓
package com.zhangguo.c42; /**貓*/ public class Cat { /**名稱*/ public String name; /**顏色*/ public String color; /**重量*/ public double weight; /**顯示信息*/ public void show(){ System.out.println("名稱:"+name+",顏色:"+color); } }
Zoo動物園
package com.zhangguo.c42; /**動物園*/ public class Zoo { public static void main(String[] args) { Dog dog=new Dog(); dog.name="吉娃娃狗"; dog.color="綠色"; dog.price=19800.7; dog.show(); Cat cat=new Cat(); cat.name="波斯貓"; cat.color="紅色"; cat.weight=18.5; cat.show(); } }
運行結果:
上面的代碼實現了基本功能,但有問題,主要是:name,color,show重複,若是系統中的動物類再增長將不停的重複,重複就會帶來不便修改,不便維護的問題。
要解決上面的問題可使用繼承,達到代碼複用的目的。
Animal動物:
package com.zhangguo.c43; /**動物*/ public class Animal { /**名稱*/ public String name; /**顏色*/ public String color; /**顯示信息*/ public void show(){ System.out.println("名稱:"+name+",顏色:"+color); } }
Dog狗:
package com.zhangguo.c43; /**狗繼承自動物,子類 is a 父類*/ public class Dog extends Animal { /**價格*/ public double price; }
Cat貓:
package com.zhangguo.c43; /**貓*/ public class Cat extends Animal { /**重量*/ public double weight; }
Zoo動物園:
package com.zhangguo.c43; /**動物園*/ public class Zoo { public static void main(String[] args) { Dog dog=new Dog(); dog.name="吉娃娃狗"; dog.color="綠色"; dog.price=19800.7; dog.show(); Cat cat=new Cat(); cat.name="波斯貓"; cat.color="紅色"; cat.weight=18.5; cat.show(); } }
運行結果:
從示例中可見dog並無定義color屬性,但在使用中能夠調用,是由於dog繼承了父類Animal,父類的非私有成員將被子類繼承。若是再定義其它的動物類則無須再反覆定義name,color與show方法。
若類C繼承類B,類B繼承類A(多繼承),則類C既有從類B那裏繼承下來的屬性與方法,也有從類A那裏繼承下來的屬性與方法,還能夠有本身新定義的屬性和方法。繼承來的屬性和方法儘管是隱式的,但還是類C的屬性和方法。
若類B繼承類A,那麼創建類B時只須要再描述與基類(類A)不一樣的少許特徵(數據成員和成員方法)便可。這種作法能減少代碼和數據的冗餘度,大大增長程序的重用性。
一、使用super關鍵字調用父類成員
二、子類默認會先調用父類的無參構造方法,若是父沒有則報錯,能夠手動指定,但必須在第一行
動物:
package com.zhangguo.c43; /**動物*/ public class Animal { /**名稱*/ public String name; /**顏色*/ public String color; public Animal() { System.out.println("這是動物類的空構造方法"); } public Animal(String name, String color) { this.name = name; this.color = color; } /**顯示信息*/ public void show(){ System.out.println("名稱:"+name+",顏色:"+color); } }
狗:
package com.zhangguo.c43; /**狗繼承自動物,子類 is a 父類*/ public class Dog extends Animal { public Dog(String name, String color,double price) { super(name,color); //調用父類構造方法 this.price=price; //調用當前對象的成員 } /**價格*/ public double price; /**重寫父類方法*/ public void show(){ /**子類調用父類成員*/ super.show(); System.out.println("價格:"+this.price); } }
貓:
package com.zhangguo.c43; /**貓*/ public class Cat extends Animal { /**重量*/ public double weight; }
動物園:
package com.zhangguo.c43; public class Zoo { public static void main(String[] args) { Dog dog = new Dog("中華田園犬","藍色",123.56); dog.show(); Cat cat = new Cat(); cat.name = "波斯貓"; cat.color = "紅色"; cat.weight = 18.5; cat.show(); A a = new A(); a.y = 100; B b = new B(); b.y = 200; // com.nf.c401.Hello h=new com.nf.c401.Hello(); C c = new C(); c.y = 200; c.z = 200; } } class A { /** * private 私有的,只容許本類訪問 * public 公有的,容許全部類訪問 * protected 授權保護的,只容許子類訪問,同包訪問 * default 容許同一個包訪問 package,不寫訪問修飾符 **/ private int x; protected int y; } class B extends A { public int z; } class C extends B { } //class D extends A,B,C{} 單根性,只能繼承一個父類,可實現多個接口
運行結果:
a)、構造方法是建立對象時調用的方法,(實例化,new),析構方法
b)、構造方法名與類名相同(如Book類的構造方法名稱必定Book)
c)、構造方法沒有返回類型() public Book(){}
d)、一個類若是不定義構造方法會默認有一個無參構造方法,若是用戶自定義了構造方法則再也不默認定義無參構造方法
package com.zhangguo.c44; /** 車 */ public class Car { /**車速*/ private int speed; //構造方法 public Car() { System.out.println("安裝輪胎"); System.out.println("安裝方向盤"); this.speed=230; } }
測試
package com.zhangguo.c44; public class CarClient { public static void main(String[] args) { Car c1=new Car(); Car c2=new Car(); } }
結果:
a)、構造方法的參數與普通方法相同
b)、構造方法容許重載(同名方法不一樣參數個數或類型)
c)、在建立子類時會默認調用父類的構造方法,通常是無參構造
d)、使用super能夠調用父類指定的構造方法,子類中調用父類的構造方法時必須在第一行
e)、使用super能夠調用父類中的任意公開成員
package com.zhangguo.c44; /** 車 */ public class Car { /**車速*/ public int speed; //構造方法 public Car(int _speed) { this.speed=_speed; } //無參構造方法 public Car(){ this.speed=100; } /**啓動*/ public void start() { System.out.println("車速:"+this.speed); } }
測試:
package com.zhangguo.c44; public class CarClient { public static void main(String[] args) { Car c1=new Car(99); c1.speed=100; c1.start(); Car c2=new Car(350); c2.start(); Car c3=new Car(); c3.speed=198; c3.start(); } }
結果:
package com.zhangguo.c44; class A{ public A() { System.out.println("A"); } } class B extends A{ public B() { System.out.println("B"); } } public class Student { public static void main(String[] args) { B b=new B(); } }
運行結果:
A
B
動物:
package com.zhangguo.c47; /**動物*/ public class Animal { public Animal() { } public Animal(String name){ setName(name); } /**名稱屬性*/ private String name; /** * 得到名稱 */ public String getName() { return name; } /** * 設置名稱 */ public void setName(String name) { this.name = name; } /**展現*/ public void show(){ System.out.println("這是"+this.name); } }
狗:
package com.zhangguo.c47; /**狗*/ public class Dog extends Animal { public Dog() { } public Dog(String name,String color) { super(name); setColor(color); } /**顏色*/ private String color; public String getColor() { return color; } public void setColor(String color) { this.color = color; } /**重寫父類的show方法,由於父類中也有同樣的show方法*/ public void show(){ super.show(); System.out.println(" 顏色:"+color); } //註解 @Override public String toString() { return "名稱:"+getName()+",顏色:"+getColor(); } }
動物園:
package com.zhangguo.c47; public class Zoo { public static void main(String[] args) { Dog dog1=new Dog("吉娃娃","紅色"); System.out.println(dog1.toString()); Dog dog2=new Dog("大娃娃","藍色"); System.out.println(dog2.toString()); } }
結果:
面向對象的多態性主要體如今:重寫與重載兩方面,前面的課程中已經詳細講解太重載。
同名方法,不一樣參數(類型或個數),與返回值無關,適用全部方法(構造,靜態,實例)。
構造方法重載:
package com.nf.c401; /** 學生 類 */ public class Student { /** 構造方法 */ public Student(int height, String name, String hobby) { // super(); /**調用父類構造方法,寫在第一行,默認就調用*/ this.height = height; this.name = name; this.hobby = hobby; } public Student(int height, String name) { this.height = height; this.name = name; } public Student(String name) { this.name = name; } public Student() { } /** 身高 字段,成員變量,全部成員變量都有默認值 */ private int height; /** 姓名 */ private String name; /** 愛好 */ private String hobby; /** 身高屬性,寫 */ public void setHeight(int height) { if (height > 0 && height < 300) { this.height = height; } else { System.out.println("身高不正確"); } } /** 身高屬性 讀 */ public int getHeight() { return this.height; } /** 顯示 方法 */ public void show() { System.out.println("身高:" + height + ",姓名:" + this.name + ",愛好:" + hobby); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } }
測試類:
package com.nf.c401; public class School { public static void main(String[] args) { Student tom=new Student(171,"張果","代碼"); tom.show(); Student rose=new Student(); rose.show(); Student mark=new Student("馬克"); mark.setHeight(158); mark.setHobby("籃球"); mark.show(); } }
結果:
自動封裝:
普通方法重載:
系統重載方法:
/**java內置的方法,有不少重載*/ System.out.println("重載"); System.out.println(98.5); System.out.println(true);
自定義重載方法:
package com.nf.c401; public class Math { public void add(int a,int b){ System.out.println(a+"+"+b+"="+(a+b)); } /**參數個數不一樣*/ public int add(int a,int b,int c){ System.out.println(a+"+"+b+"+"+c+"="+(a+b+c)); return a+b; } /**參數類型不一樣*/ public void add(double a,double b){ System.out.println(a+"+"+b+"="+(a+b)); } }
測試:
package com.nf.c401; public class MathTest { public static void main(String[] args) { Math math=new Math(); math.add(10, 15); math.add(1.0, 1.5); math.add(100, 200,10); } }
輸出結果:
LSP全稱Liskov Substitution Principle,中文名意思是里氏代換原則。LSP講的是基類和子類的關係。只有當這種關係存在時,里氏代換關係才存在。
子類必定能夠替換父類。
子類的信息量必定大於父類的。老鼠的兒子會打洞,老鼠的兒子必定能夠替代老鼠的父親
package com.zhangguo.c45; class A{ } class B extends A{ } public class Student { public static void main(String[] args) { A a1=new B(); Object a2=new A(); task(new B()); } public static void task(A a){ } }
在代碼中須要父類對象的地方均可以使用子類對象替換。
在Java中,子類可繼承父類中的方法,而不須要從新編寫相同的方法。但有時子類並不想原封不動地繼承父類的方法,而是想做必定的修改,這就須要採用方法的重寫。方法重寫又稱方法覆蓋。
package com.zhangguo.c46; class Car{ public void start() { System.out.println("車在跑"); } } class SuperCar extends Car{ public void start() { System.out.println("車在飛"); } } public class Student { public static void main(String[] args) { Car car=new SuperCar(); car.start(); } }
運行結果:
車在飛
同一個類的不一樣子類對象對同一個方法的調用產生不一樣的結果叫多態。
演員
廚師
理髮師
他都是Person人的子類,但當聽到Cut(切)時他們的表現不同。
package com.zhangguo.c47; /**人*/ public class Person { public void cut(){ } public static void main(String[] args) { Person player=new Player(); Person cooker=new Cooker(); Person cuter=new Cuter(); player.cut(); cooker.cut(); cuter.cut(); } } /**演員*/ class Player extends Person { /**重寫*/ public void cut(){ System.out.println("中止演戲"); } } /**廚師*/ class Cooker extends Person { /**重寫*/ public void cut(){ System.out.println("開始切菜"); } } /**廚師*/ class Cuter extends Person { /**重寫*/ public void cut(){ System.out.println("開始剪頭髮"); } }
運行結果:
程序中定義的引用變量所指向的具體類型和經過該引用變量發出的方法調用在編程時並不肯定,而是在程序運行期間才肯定,即一個引用變量倒底會指向哪一個類的實例對象,該引用變量發出的方法調用究竟是哪一個類中實現的方法,必須在由程序運行期間才能決定。由於在程序運行時才肯定具體的類,這樣,不用修改源程序代碼,就可讓引用變量綁定到各類不一樣的類實現上,從而致使該引用調用的具體方法隨之改變,即不修改程序代碼就能夠改變程序運行時所綁定的具體代碼,讓程序能夠選擇多個運行狀態,這就是多態性。多態性加強了軟件的靈活性和擴展性。小李喜歡聽小鳥唱歌{麻雀,杜鵑,鸚鵡}
小李:窗外的鳥兒,給我唱首歌。
1.(鳥 bird = new 麻雀 )?
2.(鳥 bird = new 杜鵑 )?
3.(鳥 bird = new 鸚鵡 )?
鳥兒:bird.sing()~~~~~
小李:鳥兒唱的不錯,你是哪一種鳥?
鳥兒: bird.shape()
小李:(---若是上面藍字定義的是3,是鸚鵡)哈哈!原來你是鸚鵡!
因此,多態的過程實質是一個抽象指令,讓一組具備相同行爲單具備不一樣內容的個體協同工做的這樣的一個過程。
方法的重寫、重載與動態鏈接構成多態性;
Java之因此引入多態的概念,緣由之一是它在類的繼承問題上和C++不一樣,後者容許多繼承,這確實給其帶來的很是強大的功能,可是複雜的繼承關係也給C++開發者帶來了更大的麻煩,爲了規避風險,Java只容許單繼承,派生類與基類間有IS-A的關係(即「貓」is a 「動物」)。這樣作雖然保證了繼承關係的簡單明瞭,可是勢必在功能上有很大的限制,因此,Java引入了多態性的概念以彌補這點的不足,此外,抽象類和接口也是解決單繼承規定限制的重要手段。同時,多態也是面向對象編程的精髓所在。
要理解多態性,首先要知道什麼是「向上轉型」。
我定義了一個子類Cat,它繼承了Animal類,那麼後者就是前者的父類。我能夠經過
Cat c = new Cat(); 例化一個Cat的對象,這個不難理解。
但當我這樣定義時: Animal a = new Cat();
這表明什麼意思呢?
很簡單,它表示我定義了一個Animal類型的引用,指向新建的Cat類型的對象。因爲Cat是繼承自它的父類Animal,因此Animal類型的引用是能夠指向Cat類型的對象的。那麼這樣作有什麼意義呢?由於子類是對父類的一個改進和擴充,因此通常子類在功能上較父類更強大,屬性較父類更獨特,定義一個父類類型的引用指向一個子類的對象既可使用子類強大的功能,又能夠抽取父類的共性。因此,
父類引用只能調用父類中存在的方法和屬性,不能調用子類的擴展部分;由於父類引用指向的是堆中子類對象繼承的父類;(可是若是強制把超類轉換成子類的話,就能夠調用子類中新添加而超類沒有的方法了。)
同時,父類中的一個方法只有在父類中定義而在子類中沒有重寫的狀況下,才能夠被父類類型的引用調用;
對於父類中定義的方法,若是子類中重寫了該方法,那麼父類類型的引用將會調用子類中的這個方法,這就是動態鏈接。
一、定義包使用什麼關鍵字?
package com.zhangguo.projectA
二、導入包使用什麼關鍵字?
import com.zhangguo.projectA.類 import com.zhangguo.projectA.*
三、若是想導入com.zhangguo.project下的全部類應該怎樣聲明?
import com.zhangguo.project.*
四、靜態方法是否能夠直接調用同一個類中其它非靜態方法?
不行,經過對象調用
五、非靜態方法是否能夠直接調用同一個類中的其它靜態方法?
同一個類:直接調用
不一樣的類:使用類名調用,如類名.成員名
package com.gdnf.java.d3; public class Student { public static void main(String[] args) { //靜態的直接調用靜態的 int i=add(1,2); System.out.println(add(add(i,100),7)); //靜態的實例調用非靜態的 *** Student stu=new Student(); System.out.println(stu.calc(1,2,add(9,91))); } public int calc(int i,int j,int k){ //非靜態的直接調用靜態的 return add(add(i,j),k); } /** * 加法操做 * @param x 第一個參數 * @param y 第二個參數 * @return 相加的結果 */ public static int add(int x,int y){ return x+y; } }
運行結果:
六、請定義一個類車(Car),在車中定義屬性車速(Speed)與車名(Name),封裝Speed與Name,要求車速在50-300之間;定義Start方法輸出車名與車速。測試定義好的類TestCar;
七、請定義父類人(Person),屬性姓名(Name)與性別(Sex),方法Hello方法輸出姓名與性別;子類學生Student與老師Teacher分別繼承人,
Student擁有屬性班級(ClassNO),老師擁有屬性教齡(TeachLen);測試定義好的類TestSchool;
八、java面向對象的三大特性是:封裝、繼承與多態
九、有一個類的定義是這樣的:public class Cat extends Animal,其中Cat是貓,Animal是動物,請問基類是、子類是、基類又稱爲何?子類又稱爲何?
基類Animal、子類Cat 、基類又稱爲父類,子類又稱爲派生類
十、已知以下類(Phone:Product,Book:Product),請完成另外一個類(Book,添加屬性Author)的繼承,請實現對Price的封裝
Product.java
package com.zhangguo.c44; /** 產品 */ public class Product { /** 價格 */ private double price; /** 得到價格 */ public double getPrice() { return price; } /** 設置價格 */ public void setPrice(double price) { if (price >= 0) { this.price = price; } else { System.out.println("價格必須>=0"); } } /** 展現 */ public void show() { System.out.println("商品的價格是:" + price); } }
Book.java
package com.zhangguo.c44; /** 圖書 繼承 產品 */ public class Book extends Product { /** 做者 屬性 */ private String author; public String getAuthor() { return author; } public void setAuthor(String author) { this.author = author; } }
Phone.java
package com.zhangguo.c44; /**電話*/ public class Phone extends Product { /**品牌*/ public String brand; } class Vivo extends Phone { }
Store.java
package com.zhangguo.c44; public class Store { public static void main(String[] args) { //請定義圖書對象,設置價格爲-100,顯示價格 Book book = new Book(); book.setPrice(-100); book.show(); Vivo vivo=new Vivo(); } }