面向對象,無論什麼編程語言,都有三個特點:封裝,繼承,多態。
首先,封裝:
舉個例子,比如電腦,電腦就是一個類,外面有些usb插口,你知道,把打印機插上就可以打印,把音響插上可以放音樂,但是你並不知道電腦內部是怎麼實現的,你只是知道這個接口確實有這些功能,你就可以用了,這樣,對普通用戶,他們不瞭解電腦,也能用,不至於去破壞電腦內部的東西。而開發人員就是預留這些接口,保護電腦不會被不專業的人搞壞了。
封裝就是做這個事情,類就是黑盒子,預留幾個接口讓別人用,怎麼實現的那個使用的人不需要知道。
例如,有一個電腦類,屬性:品牌,型號兩個,讓外面可以通過接口訪問這兩個屬性,但是又不能直接對屬性訪問。代碼如下:
/** *@author LeiGao *@data 2016.11.19 */ class Computer{ //將兩個屬性私有化,外面就不可以訪問了。 private String brand; private String type; //實現兩個屬性訪問的接口,就是用方法來作爲接口,如下: public String getBrand(){ return brand; } public void setBrand(String brand){ this.brand=brand; } public String getType(){ return type; } public void setType(String type){ this.type=type; } } //指定程序入口: class ComputerMain{ public static void main(String[] args){ Computer computer = new Computer(); //下面兩個語句會報錯: //computer.brand="lenovo"; //computer.type="thinkpad" //通過接口設置屬性和訪問屬性 //設置屬性 computer.setBrand("lenovo"); computer.setType("thinkpad"); //訪問屬性 String brand = computer.getBrand(); String type = computer.getType(); System.out.println("品牌:"+brand+"\n類型:"+type); } }
注:java權限修飾符,在成員變量與成員方法前,也就是類的屬性和功能前。主要限制外來人員的訪問,以保證其安全性。具體權限,如下圖:
從上圖可以看出,作爲接口或者功能的成員方法,本來就是爲了讓其他模塊或者其他人使用,因此除了特殊情況,基本都用public修飾,作爲類的屬性的成員變量,爲了保護,基本都用private修飾,其他關鍵字很少使用。
其次,繼承:
所謂繼承,就是子繼承父,既然繼承父親了,那麼父親會的,孩子都會,父親不會的,孩子也可以會,要不然怎麼有進步呢?當然private修飾的孩子沒有,但是public修飾的有,因此,被private修飾的屬性的接口,setter和getter方法,依然有用。
uml類圖如下:
根據上圖,實現的代碼如下:
/** * @author LeiGao24 * @data 2016.11.19 */ class Person{ private String name; private String sex; private Integer age; public void sleep(){ System.out.println("person sleep ..."); } public void eat(){ System.out.println("person eat ..."); } //成員變量的接口 //name接口 public void setName(String name){ this.name=name; } public String getName(){ return name; } //sex接口 public void setSex(String sex){ this.sex=sex; } public String getSex(){ return sex; } //age接口 public void setAge(Integer age){ this.age=age; } public Integer getAge(){ return age; } } class Teacher extends Person{ //teacher所屬學校 private String school; //成員方法 public void teach(){ System.out.println("Teacher 的 teach 方法..."); } //school接口 public void setSchool(String school){ this.school=school; } public String getSchool(){ return school; } } class Student extends Person{ //學生所屬班級,因爲class爲關鍵字,所以寫爲cls private String cls; //成員方法 public void study(){ System.out.println("Student 的 study 方法..."); } //school接口 public void setCls(String cls){ this.cls=cls; } public String getCls(){ return cls; } } //程序入口 class personMain{ public static void main(String[] args){ //創建: //人:張三,男,21歲 //老師:李四,男,30歲,清華附中 //學生:王語嫣,女,18,高三二班 System.out.println("******人**********"); Person person = new Person(); person.setName("張三"); person.setSex("男"); person.setAge(21); System.out.println("姓名:"+person.getName()+"\n性別:"+ person.getSex()+"\n年齡:"+person.getAge()); System.out.println("*******老師*******"); Teacher teacher = new Teacher(); teacher.setName("李四"); teacher.setSex("男"); teacher.setAge(30); teacher.setSchool("清華附中"); System.out.println("姓名:"+teacher.getName()+"\n性別:"+ teacher.getSex()+"\n年齡:"+teacher.getAge()+ "\n所屬學校:"+teacher.getSchool()); System.out.println("*******學生********"); Student student= new Student(); student.setName("王語嫣"); student.setSex("女"); student.setAge(18); student.setCls("高三二班"); System.out.println("姓名:"+student.getName()+"\n性別:"+ student.getSex()+"\n年齡:"+student.getAge()+ "\n所屬班級:"+student.getCls()); } }
運行結果:
最後,多態:
多態就是同一種東西但是有多個形態,或者說類型比較多,但是本質上是一個東西,比如冰箱,這就是一種東西,但是又分很多類,比如,海爾,美的,等很多品牌。本質上就是一個東西,這就是多態了。
多態分爲兩種:一種是運行時多態,一種是編譯時多態。
運行時多態,就是上面舉的冰箱的例子,冰箱是一個類,海爾是一個類,裏面都有製冷的方法,只是海爾冰箱會重寫製冷的方法。這種多個類,類間重寫的方式,就是運行時多態。
編譯時多態,比如,吃火鍋的時候,放進去菜,煮熟的就是菜,放進去肉煮熟的就是肉,並沒有肉一個鍋,菜一個鍋,而是在一個鍋裏,你放進去什麼,他就是按照你放的東西進行處理,這種在一個類裏面,有多個重名的方法,只是方法的參數不一樣的實現方式,就叫做重載,也就是編譯時多態。
多態的實現方式有三種:
第一種,實現接口
第二種,繼承
第三種,實現抽象類
所謂接口,就是擴展類的一種方式,類似電腦上的usb接口。比如,手機類繼承關係。如下圖:
從上圖我們看出,三星,蘋果,諾基亞都是手機,所以是繼承關係(用“is-a”表示這種關係),但是我們會發現三星和蘋果手機還有打遊戲和看電影的功能,既然都有,爲了減少代碼量,我們可以把他們提取出來,但是提取出來以後又不能重新定義一個類,因爲打遊戲和看電影只有兩個方法,沒有什麼類這個樣子,【注意:不要提取出來就寫一個類,一定是真正的類,現實中真能那樣分類,不要爲了繼承而寫類】,既然不能成立一個類,而打遊戲和看電影這兩個功能實際上是三星和蘋果一類智能手機的擴展功能,所以我們可以直接提取出來寫一個接口。UML圖如下:
第二種方式,繼承,我們已經接觸過多次了。
第三種方式,實現抽象類,既有繼承,又有接口的特性
比如,下面代碼爲一個抽象類,abstract修飾,只要含有一個抽象方法,這個類就是抽象類,使用的時候用繼承關鍵字extends,接口一旦實現必須實現接口中的所有方法,抽象類則不必。下面代碼演示:
/** *@author LeiGao24 *@data 2016.11.19 */ //定義一個手機類 class Phone{ private String brand; private String size; //屬性的setter和getter方法 public void setBrand(String brand){ this.brand = brand; } public String getBrand(){ return brand; } public void setSize(String size){ this.size=size; } public String getSize(){ return size; } } //定義一個接口 //接口中只定義擴展功能,也就是方法,並且方法 //沒有方法體,也就是沒有大括號那部分 interface Func{ public void playGame(); public void Movies(); } //定義一個抽象類: //抽象類和普通類一樣,裏面可以有屬性和方法, //方法可以有方法體,也可以沒有,而接口一定 //沒有方法體 abstract class FuncCls{ public abstract void playGame(); public void Movies(){ System.out.println("打遊戲..."); } } //定義一個三星類,繼承手機類,實現接口 class Sanxing extends Phone implements Func{ //實現接口中所有的方法,如果有一個方法沒實現, //就會報錯 public void playGame(){ System.out.println("三星打遊戲!"); } public void Movies(){ System.out.println("三星看電影。。。"); } } //定義一個蘋果類,繼承抽象方法,因爲java是單繼承的 //所以只能繼承一個類,但是java是多實現的,也就是說 //接口的實現可以是多個 class Apple extends FuncCls{ private String brand; private String size; //實現抽象類中的抽象方法,如果不實現其中的 //抽象方法,那麼需要把類上標識abstract,表示 //本類有抽象方法,是一個抽象類。 public void playGame(){ System.out.println("蘋果玩遊戲..."); } //屬性的setter和getter方法 public void setBrand(String brand){ this.brand = brand; } public String getBrand(){ return brand; } public void setSize(String size){ this.size=size; } public String getSize(){ return size; } } //程序入口: class Main{ public static void main(String[] args){ Sanxing sanxing = new Sanxing(); sanxing.playGame(); sanxing.Movies(); Apple apple = new Apple(); apple.playGame(); apple.Movies(); } }
結果:
總結:抽象類是提取具體類的公因式,而接口是爲了將一些不相關的類“雜湊”成一個共同的羣體。通常我們平時養成良好的習慣就是多用接口,畢竟Java是單繼承的,只有在實現接口的時候纔是多實現的。