概述
面向?qū)ο蟮娜筇卣?/h5>
- 封裝 (Encapsulation)
- 繼承 (Inheritance)
- 多態(tài) (Polymorphism)
面向?qū)ο蟮乃枷敫攀?/h5>
類(Class)和對象(Object)是面向?qū)ο蟮暮诵母拍睢?/p>
- 類是對一類事物的描述,是抽象的嗦明、概念上的定義
- 對象是實際存在的該類事物的每個個體笼沥,因而也稱為實例(instance)
可以理解為:類 = 抽象概念的人;對象 = 實實在在的某個人
面向?qū)ο蟪绦蛟O(shè)計的重點是類的設(shè)計;而類的設(shè)計敬拓,其實就是類的成員的設(shè)計邻薯。
java類
類的語法格式
修飾符 class 類名 {
屬性聲明;
方法聲明;
}
類的成員構(gòu)成
- 屬性
- 構(gòu)造器
- 方法
- 代碼塊
- 內(nèi)部類
對象創(chuàng)建和使用
要想創(chuàng)建一個對象并且使用,首先要進行類的創(chuàng)建:
// 類的創(chuàng)建
class Person{
// 屬性
String name;
int age;
// 方法
public void grown(){
age++;
}
public void greeting(){
System.out.println("Domo, my name is "+ name +", nice to meet you!");
}
}
有了類之后乘凸,便可以通過類名創(chuàng)建對象厕诡,并且通過" . "的方式來訪問對象中的屬性和方法:
public static void main(String[] args) {
// 創(chuàng)建對象
Person p1 = new Person();
// 調(diào)用屬性
p1.name = "Kana";
p1.age = 14;
System.out.println(p1.name);
System.out.println(p1.age);
// 調(diào)用方法
p1.greeting(); // Domo, my name is Kana, nice to meet you!
p1.grown();
System.out.println(p1.age); // 15
}
完成一個對象創(chuàng)建后,系統(tǒng)會給對象的屬性賦予默認的初始值营勤;同時灵嫌,對象之間的直接復制,本質(zhì)上是將兩個對象指向了同一個地址值葛作。這點跟數(shù)組的情況非常類似:
// 對象內(nèi)屬性的默認初始化值
Person p2 = new Person();
System.out.println(p2.name); // null
System.out.println(p2.age); // 0
// 對象復制(類似數(shù)組)
Person p3 = new Person();
p3 = p1;
p3.name = "Yuki";
System.out.println(p1.name); // Yuki
以上代碼的內(nèi)存解析圖如下:
匿名對象
可以不定義對象的句柄寿羞,而直接調(diào)用這個對象的方法。這樣的對象叫做匿名對象赂蠢。
new Person().shout();
使用情況:
- 如果對一個對象只需要進行一次方法調(diào)用绪穆,那么就可以使用匿名對象。
- 匿名對象可作為實參傳遞給一個方法進行調(diào)用虱岂。
比如玖院,先聲明一個Phone的類:
class Phone{
// 屬性
double price;
// 方法
public void sendEmail(){
System.out.println("Send E-mail...");
}
public void playGame(){
System.out.println("Game Start!");
}
public void showPrice(){
System.out.println(price);
}
}
通過匿名對象的形式第岖,調(diào)用其方法:
// 匿名對象
// 每一個匿名對象难菌,都會是一個單獨的實例
new Phone().playGame();
new Phone().price = 1999;
new Phone().showPrice(); // 0.0
這里需要注意,每一個匿名對象蔑滓,都是一個單獨的實例郊酒;即便上述代碼通過調(diào)用匿名對象方法對其price屬性進行賦值,但是通過調(diào)用匿名對象方法打印出來的price值依舊是0.0键袱,這說明兩次調(diào)用方法的不是同一個實例燎窘。
接著,再聲明PhoneMall的類杠纵,它沒有屬性值荠耽,僅有一個通過Phone創(chuàng)建的實例作為參數(shù)钩骇、調(diào)用其方法的方法:
class PhoneMall{
public void showPhone(Phone phone,double price){
phone.price = price;
System.out.println(phone.price);
phone.sendEmail();
phone.playGame();
}
}
Phone的匿名對象作為實參比藻,傳遞給方法進行調(diào)用。以下例子是通過這樣的操作完成對匿名對象的price屬性進行修改:
// 匿名對象的使用
PhoneMall mall = new PhoneMall();
mall.showPhone(new Phone(),2999); // 作為形參進行值傳遞倘屹,調(diào)用方法或者更改屬性
類的屬性
屬性是類的成員之一银亲,同時作為類的變量存在
當一個對象被創(chuàng)建時,會對其中各種類型的成員變量自動進行初始化賦值纽匙,這點與數(shù)組十分類似:
變量(補充)
變量分為局部變量和全局變量(成員變量)务蝠,類的屬性就屬于全局變量的一種;它們之間詳細的分類和區(qū)別如下:
結(jié)合之前類的屬性烛缔、以及方法的形參進行比較馏段,局部變量和全局變量的區(qū)別如下:
類的方法
- 方法是類或?qū)ο笮袨樘卣鞯某橄笮Γ脕硗瓿赡硞€功能操作。在某些語言中也稱為函數(shù)或過程院喜。
- 將功能封裝為方法的目的是:可以實現(xiàn)代碼重用亡蓉,簡化代碼。
- Java里的方法不能獨立存在喷舀,所有的方法必須定義在類里砍濒。
class Customer{
// 屬性
String name;
int age;
// 方法
public void intro(){ // 無形參、無返回值
System.out.println("Hello, nice to meet you");
}
public void years(int year){ // 有形參硫麻、無返回值
age += year;
return; // 可省略爸邢,表示結(jié)束此方法
}
public String getName(){ // 無形參、有返回值
return name;
}
public String getNation(String nation, String district){ // 有形參(形參列表)拿愧、有返回值
return nation + "," +district;
}
}
方法的定義形式跟其返回值類型和參數(shù)有直接關(guān)系杠河,在通過對象調(diào)用方法時,也需要根據(jù)返回值類型和參數(shù)注意其格式:
// 創(chuàng)建實例
Customer cus1 = new Customer();
cus1.name = "Tom";
cus1.age = 24;
cus1.intro();
cus1.years(10);
System.out.println(cus1.age); // 34
System.out.println(cus1.getName());
System.out.println("I am coming from " + cus1.getNation("China","Chongqing"));
注意:
- 方法被調(diào)用一次浇辜,就會執(zhí)行一次感猛。
- 沒有具體返回值的情況,返回值類型用關(guān)鍵字void表示奢赂,那么方法體中可以不必使用return語句陪白。如果使用,僅用來結(jié)束方法膳灶。
- 定義方法時咱士,方法的結(jié)果應(yīng)該返回給調(diào)用者,交由調(diào)用者處理轧钓。
- 方法中只能調(diào)用方法或?qū)傩孕蚶鳎豢梢栽诜椒▋?nèi)部定義方法。
- 方法結(jié)束后毕箍,方法中定義的局部變量會被釋放掉弛房。
方法重載
- 在同一個類中,允許存在一個以上的同名方法而柑,只要它們的參數(shù)個數(shù)或者參數(shù)類型不同即可文捶。
- 與返回值類型無關(guān),只看參數(shù)列表媒咳,且參數(shù)列表必須不同粹排。(參數(shù)個數(shù)或參數(shù)類型)。調(diào)用時涩澡,根據(jù)方法參數(shù)列表的不同來區(qū)別顽耳。
以下三個方法彼此之間構(gòu)成重載:
public int getSum(int i,int j){
return (i + j);
}
public double getSum(double i,double j){
return (i + j);
}
public String getSum(String i,String j){
return (i + j);
}
// public int getSum(int i,int j){ // 報錯
// return 0;
// }
可變個數(shù)的形參
JavaSE 5.0 中提供了Varargs(variable number of arguments)機制,允許直接定義能和多個實參相匹配的形參。從而射富,可以用一種更簡單的方式膝迎,來傳遞個數(shù)可變的實參。
public void show(int i){
System.out.println(i);
}
public void show(String i){
System.out.println(i);
}
public void show(String ...strings){ // 未指定參數(shù)數(shù)量
String str = "";
for(int i = 0; i < strings.length; i++){
str += strings[i];
}
System.out.println(str);
}
// public void show(String[] strings){ // 本質(zhì)上是數(shù)組形式
// }
可變形參方法與其他同名方法之間構(gòu)成重載胰耗。
值傳遞機制
- 若參數(shù)是基本數(shù)據(jù)類型弄抬,實參賦給形參的是實參真實存儲的數(shù)據(jù)值
- 若參數(shù)是引用數(shù)據(jù)類型,實參賦給形參的是實參存儲數(shù)據(jù)的地址值
比如以下類中宪郊,第一個方法的形參為基本數(shù)據(jù)類型掂恕,第二個方法的形參為引用數(shù)據(jù)類型,它們同樣是執(zhí)行交換數(shù)據(jù)的功能:
class Object{
// 屬性
int m;
int n;
// 方法
public void swap(int m ,int n){
int temp = m;
m = n;
n = temp;
}
public void swap(Object obj){
int temp = obj.m;
obj.m = obj.n;
obj.n = temp;
}
}
// 若參數(shù)是基本數(shù)據(jù)類型弛槐,實參賦給形參的是實參真實存儲的數(shù)據(jù)值
int m = 10;
int n = 20;
Object obj = new Object();
obj.swap(m,n);
System.out.println("m = "+ m +";n = " + n); // m = 10;n = 20
// 若參數(shù)是引用數(shù)據(jù)類型懊亡,實參賦給形參的是實參存儲數(shù)據(jù)的地址值
obj.m = 10;
obj.n = 20;
obj.swap(obj);
System.out.println("obj.m = "+ obj.m +";obj.n = " + obj.n); // obj.m = 20; obj.n = 10
然而兩個方法的執(zhí)行結(jié)果卻大相徑庭,采用基本數(shù)據(jù)類型作為形參的方法乎串,其實參傳遞給形參后進行交換店枣,完全不會影響到對象內(nèi)的屬性值;而采用引用數(shù)據(jù)類型作為形參的方法叹誉,因為直接交換的地址值鸯两,所以其指向的對象也會發(fā)生實質(zhì)性的交換。
遞歸方法
遞歸方法:一個方法體內(nèi)調(diào)用它自身
- 1长豁、方法遞歸包含了一種隱式的循環(huán)钧唐,它會重復執(zhí)行某段代碼,但這種重復執(zhí)行無須循環(huán)控制匠襟。
- 2钝侠、遞歸一定要向已知方向遞歸,否則這種遞歸就變成了無窮遞歸酸舍,類似于死循環(huán)帅韧。
比如:
// 利用遞歸累積求和
public int getSum(int n){
if(n == 1){
return 1;
}else{
return n + getSum(n-1);
}
}
當調(diào)用getSum(100)時,因為內(nèi)部存在遞歸方法啃勉,就會調(diào)用 getSum(99) 忽舟;同理,當調(diào)用 getSum(99) 時淮阐,就會調(diào)用 getSum(98) ... ... 以此類推叮阅,最終總會調(diào)用 getSum(1) = 1 這個已知的條件,從而按原來相反的順序返回 getSum(100) 的值枝嘶。
封裝與隱藏
隱藏對象內(nèi)部的復雜性帘饶,只對外公開簡單的接口哑诊,便于外界調(diào)用群扶,從而提高系統(tǒng)的可擴展性、可維護性。通俗的說竞阐,把該隱藏的隱藏起來缴饭,該暴露的暴露出來。這就是封裝性的設(shè)計思想
比如骆莹,聲明一個Animal類颗搂,并使其legs屬性為私有的,如需通過對象對該屬性使用幕垦,則需要在類中聲明訪問私有屬性的方法 getXxx() 和 setXxx() 丢氢。
class Animal{
// 屬性
String name;
int age;
private int legs; // 腿的個數(shù)
// 方法
// 屬性的設(shè)置與獲取
public void setLegs(int l){
if(l >= 0 && l % 2 ==0){
legs = l;
}else{
legs = 0;
}
}
public int getLegs(){
return legs;
}
// 其它函數(shù)
public void eat(){
System.out.println("eating...");
}
public void show(){
System.out.println("name:"+ name +" age:"+ age +" legs:"+ legs);
}
}
創(chuàng)建Animal類的實例后,無法再用 “.” 的方式訪問其私有屬性先改。而應(yīng)該使用事先聲明好的 getXxx() 和 setXxx() 方法:
Animal a = new Animal();
a.name = "dog";
a.age = 2;
// a.legs = 4; // 屬性不可見/隱藏疚察,不可直接調(diào)用
a.setLegs(4);
System.out.println(a.getLegs());
a.show();
權(quán)限修飾符
Java權(quán)限修飾符public、protected仇奶、(缺省)貌嫡、private置于類的成員定義前,用來限定對象對該類成員的訪問權(quán)限该溯。
類的構(gòu)造器
類的構(gòu)造器用來創(chuàng)建對象岛抄;并給對象進行初始化。
比如聲明一個Student類:
class Student{
// 屬性
private String name;
private int age;
// 構(gòu)造器
public Student(){ // 系統(tǒng)提供的默認構(gòu)造器
}
public Student(String n){
name = n;
}
public Student(String n, int a){
name = n;
age = a;
}
// 方法
public void show(){
System.out.println("Name:"+ name +" Age:" + age);
}
}
- 如沒有事先顯示定義構(gòu)造器狈茉,則系統(tǒng)默認提供一個空參數(shù)的夠造器
- 一旦顯示定義了構(gòu)造器夫椭,系統(tǒng)就不會提供默認構(gòu)造器
- 一個類中可以定義多個構(gòu)造器,彼此構(gòu)成重載
Student stu = new Student();
stu.show();
Student stu1 = new Student("Kana", 16);
stu1.show();
構(gòu)造器特征
- 它具有與類相同的名稱
- 它不聲明返回值類型氯庆。(與聲明為void不同)
- 不能被static益楼、final、synchronized点晴、abstract感凤、native修飾,不能有return語句返回值
關(guān)鍵字(this粒督、package陪竿、import)
this
當this在方法內(nèi)部使用,即這個方法所屬對象的引用屠橄;
當this在構(gòu)造器內(nèi)部使用族跛,表示該構(gòu)造器正在初始化的對象。
當在方法內(nèi)需要用到調(diào)用該方法的對象時锐墙,就用this礁哄。
具體的:我們可以用this來區(qū)分屬性和局部變量。
比如:this.name = name;
class Person{
// 屬性
private String name;
private int age;
// 方法
public void setName(String name){
this.name = name;
}
public void setAge(int age){
this.age = age;
}
public String getName(){
return this.name;
}
public int getAge(){
return this.age;
}
public void show(){
System.out.println("Name:"+this.getName()+" Age:"+this.getAge());
}
}
this修飾構(gòu)造器:
// 構(gòu)造器
// this修飾/調(diào)用構(gòu)造器
public Person(){
// 假設(shè)對象初始化溪北,必須輸出以下字段
System.out.println("this is an important sentence桐绒!");
}
public Person(String name){
this();
this.name = name;
}
public Person(int age){
this();
this.age = age;
}
public Person(String name,int age){
this(age); // 通過this(field)來調(diào)用其他指定的構(gòu)造器
this.name = name;
}
package
package語句作為Java源文件的第一條語句夺脾,指明該文件中定義的類所在的包。(若缺省該語句茉继,則指定為無名包)咧叭。
package project.java;
系統(tǒng)文件夾會創(chuàng)建對應(yīng)的路徑:
import
為使用定義在不同包中的Java類,需用import語句來引入指定包層次下所需要的類或全部類(.*)烁竭。import語句告訴編譯器到哪里去尋找類菲茬。
package practice.java;
import project.java.*;
public class Test {
public static void main(String[] args) {
CustomerView cs = new CustomerView();
cs.enterMainMenu();
}
}
通過import,在當前包(practice)中導入另一個包(project)的項目工程派撕。