本文是複習筆記,初學者若是不理解面向對象的概念能夠看看個人另外一篇博客:http://www.javashuo.com/article/p-zjxmduaw-ht.htmlhtml
變量定義在棧中,而具體的對象數據則在堆區java
構造函數,構造器python
語法要求設計模式
1.函數名稱與類名一致 2.不容許有返回值類型 3.不容許使用return語句返回數據
特色:安全
new 對象時會自動執行 1.能夠重載多個構造方法 2.當咱們沒有定義任何構造方法時,會自動生成無參的空構造方法 3.一旦咱們定義類構造方法,系統將不會自動生成
構造方法只能經過兩種方式來調用:ide
1.在構造方法中可經過this去調用其餘的構造方法 2.經過new 關鍵字 //在普通方法中也不能去掉用構造方法 public class Constructer { public Constructer(){ } public Constructer(String name){ this(); //調用空參數構造方法 } }
1.只能經過規定的接口(方法)訪問內部數據函數
2.隱藏了內部實現細節,爲了隔離複雜度,和提升安全性,提升了類內部的維護性性能
修改方法或屬性的權限爲private 私有化測試
爲私有的屬性提供對外開放(public)的setter 和getter方法;this
public class Test { private String name;//該屬性被私有化 此時該屬性盡在該類內部能夠訪問 public Test(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
包的本質是一個文件夾
當一個項目中出現大量的類是,維護性會下降,咱們能夠採起分包的方式來管理 ,將相關的類放到同一個包中,方便管理維護代碼,
採用域名倒敘,+模塊名稱+功能名稱
全小寫
import用於導入某個類
語法:
1.導入某個包下的某個類 import com.yh.package1.Cat;
2.導入某個包下的全部類 import com.yh.package2.*;
import com.yh.package1.Cat
com.yh.package1.Cat c1 = new com.yh.package1.Cat(); c1.show();
static修飾的成員稱之爲靜態成員
特色:
1.可使用類名直接調用(固然對象也能夠)
2.而且static修飾的成員屬於類名稱空間中,也就是說全部該類對象,共享該資源,相反的若是非static修飾的成員是每一個對象獨有的,例如每一個人的name屬性不一樣;
3.靜態成員的生命週期跟隨的類,類加載時被加載,虛擬機結束時被銷燬;
4.在靜態方法中不可使用this關鍵字,由於static修飾的成員比對象先被加載
5.靜態方法中只能訪問靜態成員
使用一對大括號產生一個代碼塊,固然了方法也是代碼塊
咱們還能夠在類中直接使用{}來定義出一個構造代碼快 像下面這樣
class Person(){ { //構造代碼塊,會在建立類的時候先於構造函數執行,沒建立一個對象就執行一次 } }
class Person{ void show(){ //方法體 { // 普通代碼塊 } //方法體 } }
在類中使用static來修飾的代碼塊就是靜態代碼塊,其執行時機是在類被加載時,執行一次,後續不在執行,
何時使用?
當咱們須要在使用類以前作一些初始化操做時
問題?
1.代碼塊是不是局部做用域 ? 是的每一個代碼塊都是局部的
2.靜態代碼塊中是否能夠存在方法? 不能夠局部代碼塊建立方法沒有意義
靜態代碼塊 -> 構造代碼塊 -> 構造方法
一個類和另外一個類之間的關係,是一種什麼是什麼的關係(A is aB)
如豬是動物,
好處:子類繼承父類能夠直接使用父類開放(非private)的已存在成員
extends關鍵字創建繼承關係,一個類只能有一個父類
class Animal{ String name; } class Person extends Animal{ public void show(){ System.out.println(this.name);//直接訪問父類成員 } }
override
當子類出現了與父類徹底一致(相同返回值類型,相同名稱,相同參數列表)的方法時將產生覆蓋
當父類的方法 沒法直接知足需求時子類能夠覆蓋父類已有方法
也就是說若是子類想定義新的方法要麼名稱不一樣,要麼參數列表不一樣
修飾符 | 本類 | 同包 | 子類 | 其餘包 |
---|---|---|---|---|
public | yes | yes | yes | yes |
protected | yes | yes | yes | no |
default | yes | yes | no | no |
private | yes | no | no | no |
當子類覆蓋了父類的方法時,按照順序將優先執行子類中的方法,當咱們須要執行父類方法時
能夠在子類中使用super關鍵字來調用父類的方法
class A{ public A(){ } public show(){ System.out.println("hello java!"); } } class B extends B{ public B(){ super().show(); } }
1.加載類(僅發生一次)
2.加載父類靜態資源
3.加載子類靜態資源
4.執行父類構造代碼塊
5.執行父類構造函數
6.執行子類構造代碼塊
7.執行子類構造函數
8.完成
this:
本類的,屬性,方法,構造器
super:
父類的,屬性,方法,構造器
注意:this和super不能同時出如今構造函數中
翻譯爲最終,能夠修飾類,變量,方法
1.在繼承關係中,被final修飾的方法沒法被覆蓋
2.final修飾變量時,就變成了常量,一旦初始化值不容許修改
3.final修飾類時,表示該類不能被繼承
JDK1.5 推出
用於對方法或變量進行說明
源碼註解盡在編譯完成時自動去除,用於對元素進行標記,方便編譯器識別,例如@override
編譯時註解指的是編譯成class後依然存在的註解
運行時註解指的是,會對程序邏輯產生影響的註解,例如autowrite,transaction等..
常見23中設計模式,及其分類;
某個類有且僅有一個實例,那ta就是單例類
1.將構造函數私有化 以禁止外界本身初始化
2.利用static僅加載一次的特性,建立一個靜態的對象做爲類的私有屬性
3.提供訪問這個靜態對象的方法
1.餓漢式: 直接在聲明static屬性時建立對象 這種方法是線程安全
class SingleInstance{ private static SingleInstance obj = new SingleInstance(); private SingleInstance(){ //私有化的構造函數 } public SingleInstance getInstance(){ return obj; } }
2.懶漢式:在獲取對象是若是發現對象爲空才建立 這種方法是非線程安全
public class Emperor { //定義私有構造方法 private Emperor(){ System.out.println("create instance!"); } //定義私有靜態類對象 private static Emperor obj = null; //定義公有靜態方法返回類內的私有靜態對象 public static Emperor get_instance(){ if(obj == null){ obj = new Emperor(); } return obj; } }
優勢:
節省空間,提升性能
缺點:
擴展困難
當對象長期不使用,困難會被回收致使異常
使用場景:
當程序須要共享同一份對象的數據時
當每一個對象數據都相同時,則沒有必要建立對個對象
當須要保證某些數據的一致性時,例如: 要生成惟一的id,若是每一個對象都有一份本身的生成方式則可能形成數據錯誤
多個不一樣對象能夠響應同一個方法產生各自不一樣的行爲
指的是在編譯階段就能識別具體要執行的方法是哪個,一般是方法重載,經過參數不一樣決定調用哪一個方法
只有在運行時才能肯定到底調用哪一個方法
注意下面的內容都是針對運行時多態,是任何OOP語言的共同特性
1.必須具有繼承關係
2.父類指針指向子類對象
ps:在python中沒有這兩個限制,python是動態類型,編譯期間不會檢查對象具體類型,更加靈活,可是也增長了風險
指的是用父類指針引用子類實例,會自動將子類轉換爲父類,轉換後將隱藏子類特有的成員,只能使用父類中定義的方法和屬性,
當明確某個對象就是某個子類對象時能夠強制轉換爲子類,如此就能夠從新訪問子類中獨有的成員
當不能明確對象是不是某個類型時可使用 instanceof
if(obj instanceof Objcet){ System.out.println("obj is ObjectClass instance"); }else{ System.out.println("obj not ObjectClass instance"); }
抽象類指的是類中包含抽象方法的類,
抽象方法指的是沒有任何方法體的方法
使用abstract關鍵字類表示抽象方法 或抽象類
當父類須要規定子類應該具有某些方法,但父類自己不清楚方法具體如何實現時使用抽象類,
用於提早告訴子類,你應該具有哪些方法
存在抽象方法的類沒法直接實例化產生對象,必須由子類繼承並實現全部抽象方法才能實例化子類
如子類沒有實現全部抽象方法,那麼子類也只能做爲抽象類
實例:
abstract class Person{ abstract public void show(); } class Student extends Person{ @Override public void show(){ System.out.println("show"); } }
1.若是設計子類的人清楚的知道本身應該作的事情時(方法),能夠不用抽象類,抽象類本質就是限制子類必須怎麼怎麼滴
2.須要注意final 不能與 abstract 同時出現
接口是一組功能(方法)的定義
定義一組協議方法,讓子類遵循協議中的要求去實現具體的操做,對於使用者而言,只須要掌握接口中定義的方法的使用便可,無需關心,具體是哪個類實現的,更不用關心是如何實現的, 這將類的設計者和類的使用者之間的耦合度大大的下降了,
interface Name { }
接口本質是一個類,可是與普通類有着衆多區別
1.接口中的方法默認都是抽象的不能有方法體
2.接口中定義的變量默認都是靜態常量
3.接口中的成員必然是public修飾的,即時沒有明確聲明
4.接口沒法直接實例化
5.接口能夠繼承一個或多個其餘接口
6,一個類能夠同時實現多個接口
某些狀況下,接口中聲明瞭不少抽象方法,然而子類不須要實現所有,而是想僅實現部分須要的,這種狀況在1.8以前是不容許的,除非把這個子類變成抽象的,這不夠靈活;
案例:
package com.yh.src; interface HDMI { static int a = 0; // 上述代碼等價於public static final int a = 0; //抽象方法 void generalMethod(); //上述代碼等價於public void test(); //默認方法 子類可選重寫 default void defaultMethod(){ System.out.println("默認的方法體"); } //靜態方法 子類不可重寫 static void staticMethod(){ System.out.println("靜態方法體"); } } class AA implements HDMI { @Override public void generalMethod() { System.out.println("AA Implements generalMethod!"); HDMI.staticMethod();//靜態方法只能有接口名稱調用 } @Override public void defaultMethod() { //super.test1();//沒法經過super調用接口中的默認方法 HDMI.super.defaultMethod();//須要使用接口名稱.super來調用 } } public class InterfaceRunner { public static void main(String[] args) { AA a = new AA(); a.generalMethod(); a.defaultMethod();//調用未被重寫的默認方法 //a.staticMethod();//沒法直接調用接口中的靜態方法 HDMI.staticMethod();//靜態方法只能由接口名稱調用 } }
接口名稱.super.方法名稱
如HDMI.super.defaultMethod();
PS:其實取消抽象方法和接口同樣能夠實現設計-使用鬆耦合,直接使用普通類做爲父類,子類本身實現該實現的方法,固然了java爲何佔領企業開發也正是由於其嚴謹,標準規範,
你會發現,爲了提升靈活性接口好像變得和抽象類很是類似,.......乾脆像python同樣別整這麼多約束,,,
與普通類不一樣的是一個類能夠同時實現多個接口,增長了子類的擴展性
可是也帶來了訪問不肯定性,
interface IA{ default void test(){ System.out.println("IA test!"); } } interface IB{ default void test(){ System.out.println("IB test!"); } } //實現類直接編譯失敗, class IMA implements IA,IB{ }
//在子類中重寫衝突的方法,便可 當須要調用默認方法時,使用`接口名稱.super.xx`來調用 class IMA implements IA,IB{ @Override public void test() { IA.super.test(); IB.super.test(); } }
interface IA{ default void test(){ System.out.println("IA test!"); } } interface IB{ default void test(){ System.out.println("IB test!"); } } class P{ public void test(){ System.out.println("IB test!"); } } class IMA extends P implements IA,IB{ }
這種狀況下不會出現問題,將直接調用父類中的方法
interface IA{ int a =10; int b =100; } interface IB{ int a =20; } class P{ int a = 20000; } class IMA extends P implements IA,IB{ public void func(){ System.out.println(a);//編譯錯誤 System.out.println(IA.a);//使用接口名稱來明確 System.out.println(super.a);//使super來指定訪問父類 System.out.println(b);//不存在重複的時直接能夠訪問 } }
此時子類沒法明確選擇一個要訪問的常量,必須使用接口名稱來明確
要訪問父類時使用super來明確
子類對象能夠直接訪問接口中沒有衝突的靜態變量,可是沒法直接訪問靜態方法須要使用接口名稱調用
當一個類定義在一個類的範圍中,則這個類稱之爲內部類,與之對應的是包含這個內部類的外部類
實例:
class A{//外部類 class B{ //內部類 } }
public class InnerClass { public static void main(String[] args) { //實例化內部類方法1 A.B obj; //定義 obj = new A().new B(); //實例化內部類方法2 A aobj = new A(); obj = aobj.getInner(); //實例化內部類方法3 obj = aobj.new B(); } } class A{ public B getInner() { return new B(); } class B{ } }
public class InnerClass { public static void main(String[] args) { //實例化內部類方法1 A.B obj; //定義 obj = new A().new B();//實例化 obj.test();//調用方法訪問外部類的成員 } } class A{ int inta = 100; int intb = 200; public B getInner() { return new B(); } class B{ int intb = 300; public void test(){ System.out.println(inta);//100 能夠直接訪問外部類成員 System.out.println(intb);//300 衝突時優先訪問內部 System.out.println(A.this.intb);//200 衝突時指定訪問外部 } } }
class A{ int inta = 100; int intb = 200; public void accessInner() { B b = new B();//實例化 b.test();//訪問 } class B{ int intb = 300; public void test(){ System.out.println(inta); System.out.println(intb); System.out.println(A.this.intb); } } }
外部類訪問內部類成員時須要先實例化內部類的對象,經過對象訪問便可
注意:普通內部類中不能包含任何static修飾的成員
能夠將內部類使用static修飾,此時他就是靜態內部類
與普通內部類的不一樣之處,與static修飾的其餘成員有着相同的特徵:
在類被加載時就一塊兒加載,因此,能夠直接實例化,不須要先實例化外部類;
靜態內部類中的能夠包含靜態成員而且也能夠直接調用(外部類.內部類.屬性
);普通類中不能夠有靜態成員;
實例:
public class InnerClass2 { public static void main(String[] args) { System.out.println(OUT.IN.a);//直接訪問靜態內部類的靜態成員 OUT.IN.test();//訪問靜態內部類方法 } } class OUT{ static int a = 10; String name = "jack"; static class IN{ static int a = 100; static public void test(){ System.out.println(a);//優先訪問內部類 System.out.println(OUT.a);//指定訪問外部類 System.out.println(new OUT().name);//訪問外部非靜態成員 } } }
定義在方法中的類稱爲局部內部類
意義不大..沒啥用..略過了
class A{ public void test(){ class B{ //局部內部類 } } }
特色:不容許使用static修飾局部內部類,和其中的任何成員,要使用該類必須做爲返回值return出去
字面意思就是沒有名字的類
經過new 實例化接口或是抽象類,同時提供相應的方法實現
實例:
interface USB{ void open(); } class PC { public void working(){ //此處須要一個實現了USB接口的對象來完成操做 //咱們能夠定義一個類實現USB接口先下面的A類同樣 //而後實例化A對象來完成OPEN操做 new A().open(); //咱們也可使用匿名內部類的方式來簡化操做 new USB(){ public void open(){ System.out.println("OPEN......"); } }.open; } } class A implements USB{ public void open(){ System.out.println("OPEN......"); } }
在上面的例子中咱們能夠看出匿名內部類有如下優勢:
代碼更加緊湊
使用更便捷
固然匿名內部類的缺點也很明顯:
1.臨時須要某個接口或是抽象類的獨享完成某個功能
2.當整個任務的部分代碼已經完成,可是剩下一部分關鍵代碼須要由使用這個功能的人來完成
案例:
PC類的working方法須要傳入一個USB接口對象才能完成整個任務
interface USB{ void open(); } public class PC { public static void main(String[] args) { new PC().working(new AP());//之前的方式:定義類實現方法而後實例化 new PC().working(new USB() {//匿名內部類的方式:在當前位置完成上述所有操做 @Override public void open() { System.out.println("open on NonNameClass"); } }); } public void working(USB usb){ usb.open(); } } class AP implements USB{ public void open(){ System.out.println("OPEN......on AP"); } }
PS:我的以爲匿名內部類+匿名對象其實 與OC中的block,python中的函數對象要完成的事情是同樣的,即方法的使用者實現部分代碼,而後做爲參數傳給某個方法(本質就是回調機制
),可是JAVA中定義方法必須藉助類,因此纔有了匿名內部類這麼一說,歸根結底是由於JAVA強制面向對象致使的;
補充:匿名內部類中可使用構造代碼塊