Java中面向對象核心
面向對象核心
在學習Java中我們會經常會被問到,面向對象的核心是什麽?
面向對象的核心即封裝,繼承,多態。
封裝:在面向對象程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現細節部份包裝、隱藏起來的方法。封裝可以被認為是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問。通俗點說:封裝就是要訪問該類的代碼和數據,必須通過嚴格的接口控制,加強了程式碼的安全性。
封裝的優點(簡單來說,共四點):
1. 良好的封裝能夠減少耦合。
2. 類內部的結構可以自由修改。
3. 可以對成員變量進行更精確的控制。
4. 隱藏信息,實現細節。
封裝的示例:
1 package com.company; 2 3 class Test{ 4 private String name; 5 private int age; 6 private String Phone; 7 8 public String getName() { 9 return name; 10 } 11 12 public void setName(String name) { 13 this.name = name;View Code14 } 15 16 public int getAge() { 17 return age; 18 } 19 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 public String getPhone() { 25 return Phone; 26 } 27 28 public void setPhone(String phone) { 29 Phone = phone; 30 } 31 } 32 33 34 public class get_set_ { 35 public static void main(String[] args) { 36 Test t = new Test(); 37 t.setName("小花"); 38 t.setAge(20); 39 t.setPhone("789789789789789"); 40 System.out.println("name:"+t.getName()); 41 System.out.println("age:"+t.getAge()); 42 System.out.println("Phone"+t.getPhone()); 43 44 45 } 46 }
繼承(extends):
繼承是java面向對象編程技術的一塊基石,因為它允許創建分等級層次的類。繼承就是子類繼承父類的特征和行為,使得子類對象(實例)具有父類的實例域和方法,或子類從父類繼承方法,使得子類具有父類相同的行為。
Java中的繼承是單繼承,但是也可以實現多繼承,需要關鍵字(implements),
語法為: class A extends B implements .....{}
說到繼承,其實生活中也有很多繼承的示例,如下面這張圖:
使用繼承的根本原因是,減少代碼的臃腫特點,提高代碼的維護性。
示例 :
使用繼承之後:
1 package com.company; 2 3 4 class person{ 5 private int id; 6 private String name; 7 8 public person(int id, String name) { 9 this.id = id; 10 this.name = name; 11 } 12 13 public void Eat(){ 14 System.out.println("吃飯"); 15 } 16 17 public void Sleep(){ 18 System.out.println("睡覺"); 19 } 20 21 public void introduction() { 22 System.out.println("大家好!我是" + id + "號" + name + "."); 23 } 24 } 25 26 class Boss extends person{ 27 public Boss(int MyId,String MyName){ 28 super(MyId,MyName); 29 } 30 } 31 32 class Teacher extends person{ 33 public Teacher (int MyId,String MyName){ 34 super(MyId,MyName); 35 } 36 } 37 38 public class jicehng { 39 public static void main(String[] args) { 40 Boss b = new Boss(123,"小強"); 41 b.Eat(); 42 b.Sleep(); 43 b.introduction(); 44 System.out.println("-----------------------------"); 45 Teacher t=new Teacher(456,"小明"); 46 t.Eat(); 47 t.Sleep(); 48 t.introduction(); 49 } 50 }View Code
關於Java中繼承與構造方法的關系、成員方法的關系,詳見:https://blog.csdn.net/LOL_toulan/article/details/89318617
多態:
說到繼承就不得不說到多態,繼承與多態是相輔相成的,多態中會用到繼承。
多態:簡單點說就是同一事物在不同時刻展現不同狀態。
多態的前提:
1.要有繼承關系。
2.要有方法重寫。
其實沒有也是可以的,但如果沒有這個就沒有意義。
animal d = new cat();
d.show();
animal d = new dog();
d.show();
3.要有父類引用指向子類對象。
父 f = new 子();
多態中的成員訪問特點:
1.成員變量
編譯看左邊,運行看左邊
2.構造方法
創建子類對象的時候,訪問父類構造方法,對父類對象進行初始化。
3.成員方法
編譯看左邊,運行看右邊。
4.靜態方法
編譯看左邊,運行看左邊
(靜態和類有關,所以算不上重寫,所以訪問還是左邊的)
由於成員方法存在重寫,所以運行看右邊。
1 2 3 class Fu{ 4 public int num=100; 5 public void show(){ 6 System.out.println("show fu"); 7 } 8 9 public static void function(){ 10 System.out.println("function Fu"); 11 } 12 13 } 14 15 class zi extends Fu{ 16 public int num=200; 17 public void show() { 18 System.out.println("show zi"); 19 } 20 public void method(){ 21 System.out.println("method zi"); 22 } 23 24 public static void function(){ 25 System.out.println("function zi"); 26 } 27 } 28 29 public class duotai { 30 public static void main(String[] args) { 31 Fu F = new zi(); 32 33 F.show(); 34 //成員變量 35 System.out.println(F.num); 36 //靜態方法 37 F.function(); 38 } 39 }View Code
運行結果:
多態的好處:
1.提高了代碼的維護性
2.提高了代碼的擴展性
1 2 3 class Animal{ 4 public void eat(){ 5 System.out.println("eat"); 6 } 7 public void sleep(){ 8 System.out.println("sleep"); 9 } 10 } 11 12 class dog extends Animal{ 13 public void eat(){ 14 System.out.println("dog eat"); 15 } 16 public void sleep(){ 17 System.out.println("dog sleep"); 18 } 19 } 20 21 class cat extends Animal{ 22 public void eat(){ 23 System.out.println("cat eat"); 24 } 25 public void sleep(){ 26 System.out.println("cat sleep"); 27 } 28 } 29 30 class pig extends Animal{ 31 public void eat(){ 32 System.out.println("pig eat"); 33 } 34 public void sleep(){ 35 System.out.println("pig sleep"); 36 } 37 } 38 39 class AnimalTool{ 40 private AnimalTool(){} 41 // public static void userCat(cat c){ 42 // c.sleep(); 43 // c.eat(); 44 // } 45 // 46 // public static void userDog(dog d){ 47 // d.sleep(); 48 // d.eat(); 49 // } 50 // 51 // public static void userPig(pig p){ 52 // p.sleep(); 53 // p.eat(); 54 // } 55 public static void userAnimal(Animal a){ 56 a.eat(); 57 a.sleep(); 58 } 59 60 } 61 62 public class duotai { 63 public static void main(String[] args) { 64 Animal a = new dog(); 65 // cat c = new cat(); 66 //dog d = new dog(); 67 // pig p=new pig(); 68 Animal a2=new pig(); 69 Animal a1=new cat();//多態 70 AnimalTool.userAnimal(a1); 71 System.out.println("--------------"); 72 // AnimalTool.userCat(c); 73 AnimalTool.userAnimal(a); 74 //System.out.println("--------------"); 75 //AnimalTool.userDog(d); 76 //AnimalTool.userAnimal(a1); 77 System.out.println("--------------"); 78 AnimalTool.userAnimal(a2);// 79 //AnimalTool.userPig(p); 80 // System.out.println("調用貓的方法----------"); 81 // c.eat(); 82 // c.sleep(); 83 // System.out.println("調用狗的方法-----------"); 84 // d.eat(); 85 // d.sleep(); 86 } 87 }View Code
方法重寫的好處:重寫的好處在於子類可以根據需要,定義特定於自己的行為。 也就是說子類能夠根據需要實現父類的方法。
抽象類(abstract)
基本概念:普通類是一個完善的功能類,可以直接產生實例化對象,並且在普通類中可以包含有構造方法、普通方法、static方法、常量和變量等內容。而抽象類是指在普通類的結構裏面增加抽象方法的組成部分。那麽什麽叫抽象方法呢?在所有的普通方法上面都會有一個“{}”,這個表示方法體,有方法體的方法一定可以被對象直接使用。而抽象方法,是指沒有方法體的方法,同時抽象方法還必須使用關鍵字abstract做修飾。而擁有抽象方法的類就是抽象類,抽象類要使用abstract關鍵字聲明。
抽象類的特點:
抽象類必須用abstract關鍵系修飾。
抽象類中不一定有抽象方法,但有抽象方法的類必須定義為抽象方法,(有抽象方法的類一定是抽象類)。
抽象類不能實例化,即無法構造對象( 如果Animal是抽象類的話,Animal a = new Animal();)。
規則:
含有抽象方法的類,一定是抽象類;
抽象類中可以聲明成員變量、常量、成員方法、抽象方法,抽象類中不一定要有抽象方法;
抽象類不能被實例化;
抽象類可以被繼承;
可以通過兩種方式獲得抽象類對象:父類引用指向子類對象、匿名內部類;
子類必須重寫抽象父類的所有抽象方法,或者是把子類也定義為抽象類;
如果一個類繼承的抽象父類還有上級抽象父類,那麽子類中需要要重寫所有抽象父類的所有抽象方法;
抽象類也可以繼承非抽象類,同時繼承了父類的所有非私有的屬性和方法;
例如:
示例一(錯誤示範):
1 abstract class Employee{ 2 private String name; 3 private String id; 4 private int salary; 5 6 public Employee(){} 7 8 public Employee(String name, String id, int salary) { 9 this.name = name; 10 this.id = id; 11 this.salary = salary; 12 } 13 14 public String getName() { 15 return name; 16 } 17 18 public void setName(String name) { 19 this.name = name; 20 } 21 22 public String getId() { 23 return id; 24 } 25 26 public void setId(String id) { 27 this.id = id; 28 } 29 30 public int getSalary() { 31 return salary; 32 } 33 34 public void setSalary(int salary) { 35 this.salary = salary; 36 } 37 38 public abstract void work(); 39 40 41 } 42 43 class Programmer extends Employee{ 44 45 public Programmer(){} 46 47 public Programmer (String name,String id , int salary){ 48 super(name, id, salary); 49 } 50 51 @Override 52 public void work() { 53 System.out.println("碼代碼"); 54 } 55 } 56 57 class Manager extends Employee{ 58 59 private int Money; //bonus 獎金 60 61 public int getMoney() { 62 return Money; 63 } 64 65 public void setMoney(int money) { 66 Money = money; 67 } 68 69 public Manager(){} 70 71 public Manager (String name,String id , int salary){ 72 super(name, id, salary); 73 this.Money=Money; 74 } 75 76 @Override 77 public void work() { 78 System.out.println("跟客戶談需求"); 79 } 80 81 } 82 83 public class chouxiang { 84 public static void main(String[] args) { 85 Employee emp = new Employee(); 86 87 88 // Employee emp = new Programmer(); 89 // emp.setId("123"); 90 // emp.setName("狗蛋兒"); 91 // emp.setSalary(123123); 92 // System.out.println(emp.getName()+"--"+emp.getId()+"--"+emp.getSalary()); 93 // System.out.println("------------------------------------"); 94 // Employee emp2 = new Manager(); 95 // emp2.setId("13"); 96 // emp2.setName("狗兒"); 97 // emp2.setSalary(12323); 98 // ((Manager) emp2).setMoney(798789); 99 // 100 // System.out.println(emp2.getName()+"--"+emp2.getId()+"--"+emp2.getSalary()+"--"+((Manager) emp2).getMoney()); 101 } 102 }View Code
報錯信息:
示例二(正確案例):
1 package com.company; 2 3 abstract class Employee{ 4 private String name; 5 private String id; 6 private int salary; 7 8 public Employee(){} 9 10 public Employee(String name, String id, int salary) { 11 this.name = name; 12 this.id = id; 13 this.salary = salary; 14 } 15 16 public String getName() { 17 return name; 18 } 19 20 public void setName(String name) { 21 this.name = name; 22 } 23 24 public String getId() { 25 return id; 26 } 27 28 public void setId(String id) { 29 this.id = id; 30 } 31 32 public int getSalary() { 33 return salary; 34 } 35 36 public void setSalary(int salary) { 37 this.salary = salary; 38 } 39 40 public abstract void work(); 41 42 43 } 44 45 class Programmer extends Employee{ 46 47 public Programmer(){} 48 49 public Programmer (String name,String id , int salary){ 50 super(name, id, salary); 51 } 52 53 @Override 54 public void work() { 55 System.out.println("碼代碼"); 56 } 57 } 58 59 class Manager extends Employee{ 60 61 private int Money; //bonus 獎金 62 63 public int getMoney() { 64 return Money; 65 } 66 67 public void setMoney(int money) { 68 Money = money; 69 } 70 71 public Manager(){} 72 73 public Manager (String name,String id , int salary){ 74 super(name, id, salary); 75 this.Money=Money; 76 } 77 78 @Override 79 public void work() { 80 System.out.println("跟客戶談需求"); 81 } 82 83 } 84 85 public class chouxiang { 86 public static void main(String[] args) { 87 88 89 Employee emp = new Programmer(); 90 emp.setId("123"); 91 emp.setName("狗蛋兒"); 92 emp.setSalary(123123); 93 System.out.println(emp.getName()+"--"+emp.getId()+"--"+emp.getSalary()); 94 System.out.println("------------------------------------"); 95 Employee emp2 = new Manager(); 96 emp2.setId("13"); 97 emp2.setName("狗兒"); 98 emp2.setSalary(12323); 99 ((Manager) emp2).setMoney(798789); 100 101 System.out.println(emp2.getName()+"--"+emp2.getId()+"--"+emp2.getSalary()+"--"+((Manager) emp2).getMoney()); 102 } 103 }View Code
運行結果:
接口(interface)
在JAVA編程語言中是一個抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個類通過繼承接口的方式,從而來繼承接口的抽象方法。接口並不是類,編寫接口的方式和類很相似,但是它們屬於不同的概念。類描述對象的屬性和方法。接口則包含類要實現的方法。除非實現接口的類是抽象類,否則該類要定義接口中的所有方法。接口無法被實例化,但是可以被實現。一個實現接口的類,必須實現接口內所描述的所有方法,否則就必須聲明為抽象類。另外,在 Java 中,接口類型可用來聲明一個變量,他們可以成為一個空指針,或是被綁定在一個以此接口實現的對象。
初學者通常在接口這裏有很大的困擾,通過一個例子來介紹一下:
接口就是個招牌。
比如說你今年放假出去杭州旅遊,玩了一上午,你也有點餓了,突然看到前面有個店子,上面掛著KFC,然後你就知道今天中飯有著落了。
KFC就是接口,我們看到了這個接口,就知道這個店會賣炸雞腿(實現接口)。
那麽為神馬我們要去定義一個接口涅,這個店可以直接賣炸雞腿啊(直接寫實現方法),是的,這個店可以直接賣炸雞腿,但沒有掛KFC的招牌,我們就不能直接簡單粗暴的沖進去叫服務員給兩個炸雞腿了。
要麽,我們就要進去問,你這裏賣不賣炸雞腿啊,賣不賣漢堡啊,賣不賣聖代啊(這就是反射)。很顯然,這樣一家家的問實在是非常麻煩(反射性能很差)。要麽,我們就要記住,中山路108號賣炸雞,黃山路45號賣炸雞(硬編碼),很顯然這樣我們要記住的很多很多東西(代碼量劇增),而且,如果有新的店賣炸雞腿,我們也不可能知道(不利於擴展)。 詳情請見博客:https://www.cnblogs.com/LOL-toulan/p/10753862.html ,裏面有大量的源代碼和講解。
Java中面向對象核心