java面向物件培訓筆記
雜記
封裝:物件,容器都是封裝;封裝的目的是高內聚低耦合。
標頭檔案中初始化和建構函式中初始化的區別? 在標頭檔案中初始化就相當於該例項/變數是一直存在的,會導致效能浪費。 在建構函式中初始化則是用的時候再建立,符合面向變化和節約效能的需求。
不要在建立屬性時直接例項化,例如:
public class Game { ... private IUserinfoSerice us = new IUserinfoSerice(); //wrong! 因為IUserinfoSerice作為介面時,後面例項化的可能是派生類,而不是IUserinfoSerice,如下面初始化為UserinfoSerice1() //此時相當於把專案許可權寫死了,後期面臨變化時會很崩潰。因此在建構函式中來初始化屬性。 private IUserinfoSerice us; public Game() { us=UserinfoSerice1(); //Right! } ... }
值型別和引用型別的區別: 值型別傳遞時傳遞的是數值,引用型別傳遞時傳遞的是地址。
記憶體和硬碟的區別: 硬碟的資料是不能被刪除的,只能被複寫,當使用刪除時,通過一定手段是可以恢復的,但複寫後就不能被恢復了。 記憶體和硬碟差不多,只要記憶體存在,資料就一直存在。但是記憶體與硬碟不同的地方是,記憶體只有上電的時候才會被開闢,才會工作。 因此,只要new之後的記憶體只要沒有被回收,就一直存在。
繼承的目的:重用和改寫,即覆寫。
當你不想重用和改寫時,只是用原來的方法,那麼繼承沒有意義,直接包含就可以了。
那麼如何來改寫?
在java中使用@override
來輔助檢查重寫方法,super(父類),this(自己)。
super的用法?
當覆寫父類方法後,預設呼叫的是覆寫後的方法,當不想用覆寫的方法,只想用原來的方法,就需要使用super.method()來呼叫父類方法。
舉個例子,手機都有拍照功能,小米和華為。。。。
java只能單繼承,不能多重繼承。當需要多重繼承時,可以使用傳遞繼承代替。
使用子類建構函式的時候,必須先使用super例項化父類建構函式。
java包,就是資料夾的概念。 包的命名方式。 1.com或org,com(公司),org(組織),組織就是各方勢力融合; 2.公司名; 3.專案名; 4.模組名。
匯入包:import
- java.lang java語言包,任何程式中,該包都會被自動匯入;
- java.awt 圖形使用者介面包;
- java.awt.event 圖形使用者介面事件處理包;
- java.swing 跨平臺輕量級元件包;
- java.sql 資料庫訪問包;
- java.io 輸入輸出
- java.util 該包提供了許多工具如:lists,calendar,date等所需要的類和介面;
- java.net TCP/IP網路程式設計,逐漸被websocket所代替。
封裝是為了加許可權,訪問許可權其實就是鎖。
java訪問許可權
訪問許可權 | 本類 | 本包的類 | 子類 | 非子類的外包類 |
---|---|---|---|---|
public | 是 | 是 | 是 | 是 |
protected | 是 | 是 | 是 | 否 |
default | 是 | 是 | 否 | 否 |
private | 是 | 否 | 否 | 否 |
什麼都不寫時是default訪問許可權。 方法覆寫時許可權不能小於父類中方法的許可權,否則無法呼叫父類方法。
引用資料型別的轉換 向上轉換--子類轉換為父類,損失了子類新擴充套件的屬性和方法,僅可以使用從父類中繼承的屬性和方法。 向下轉換--父類轉換為子類,曾經向上轉換過的物件,才能向下轉換,。物件不允許不經過向上轉換而直接向下轉換。 使用instanceof運算子來判斷向上轉換後的物件是哪一個子類。
當我要改寫專案中一個業務的時候,不要盲目直接否定改寫該業務,而是新建一個重寫。當實現一個方法時,客戶覺得不好,但是不要去改這個方法,而是繼承原來的方法重新實現該方法,因為即使客戶不喜歡,但是也許客戶的領導喜歡,因此不是改寫而是繼承。
介面只提供虛方法,可以多重繼承,是架構師來實現的,他關注的是程式有什麼;實現是我們來做的,我們關注的是怎麼去實現。
final關鍵字: final修飾的
- 類:不能被繼承;
- 變數:不能被重新賦值;在宣告時賦值,或在建構函式中賦值;系統不會對final屬性預設的賦初始值。
- 方法:不能在子類中被覆蓋,即不能被修改。
1.final空白
public final int a;//final空白
//這種情況下,就必須在建構函式中用引數列表初始化。
2.final引數 final引數不能被改變。
public class Test{
public method(final int i)
{
i++;//
}
}
在程式中經常使用的一些常量,如圓周率,沒必要在程式中頻繁的修改它,那麼我們可以:
- 首先把他設定為靜態static,多個例項共享該常量,沒有必要每個物件儲存一份;
- 其次,設定為final型別,賦值以後不你們再改變;
- 最後注意遵守常量的命名會犯,所有字母大寫,單詞之間用下劃線。
多型的第一步,抽象類。 有抽象方法的一定是抽象類。
抽象類的規則:
- 抽象類不能被例項化;
- 其包含的抽象方法必須在其子類中被實現,否則該子類只能宣告為abstract;
- 抽象方法不能為static。
在下列情況下,一個類必須宣告為抽象類:
- 當一個類的一個或多個方法是抽象方法時;
- 當類是一個抽象類的子類,並且沒有實現父類的所有抽象方法,即只實現部分;
- 當換一個類實現一個介面,並且不能為全部抽象方法都提供實現時;
介面(interface)
- 介面中的所有方法均為抽象方法(不用寫關鍵字);
- 介面中只包含常量和抽象方法,而沒有變數和方法的實現;
- 介面使用關鍵字interface來建立;
- 子類必須實現介面的所有方法,除非是抽象類。
- 介面中的方法必須是public。
- 在介面中預設就是public,而不是default。
- 介面不能有非抽象方法,但抽象類可以有非抽象方法。
- 介面也可以繼承介面。
工廠模式與抽象類。 工廠模式有簡單工廠模式,工廠方法模式和抽象工廠模式。
public class SendFactory{
//簡單工廠模式,傳遞的是字串
public static Sender produce1(String type){
Sender s=null;
if("wechat".equals(type)){
s=new WechatSender();
}else if("sms".equals(type)){
s=new SmsSender();
}
return s;
}
//工廠方法模式,直接呼叫構造方法,工廠可以有很多個產品,產品是抽象的。
public static Sender ProduceWechat(){
return new WechatSender();
}
public static Sender ProduceSms(){
return new SmsSender();
}
}
//以下是抽象工廠模式。抽象工廠模式是在簡單工廠模式和工廠方法模式之上再次抽象了工廠類,將工廠類統一化了。
//如上邊的是SendFactory工廠類,以後還可能有FruitFactory工廠類,因此這些工廠類可以統一化為Provider抽象類。
//抽象為抽象工廠類的目的是為了擴充套件,在不修改原來程式碼的情況下還能新增功能。
//工廠介面
public interface Provider{
public Sender Produce();
}
//現在一個工廠和一個產品對應了。
public class WechatFactory implements Provider{
@override
public Sender Produce(){
return new WechatSender();
}
}
//使用方法如下:
Provider factory=new WechatFactory(); //當我不需要這個工廠時,只需要換一個工廠即可,其他都不需要改變。
Sender sender=factory.produce();
sender.send();
使用介面這種方式,可以通過繼承來實現升級,避免了拋棄舊版本的內容。
多型
多型:就是將做什麼和怎麼做分離;分別對應了介面和實現的分離來完成;通過多型來消除型別之間的耦合關係;多型也叫動態繫結。 批註:這個定義蠻好的,分別解釋了什麼是?怎麼做?為什麼?多型舉例,如計算機的視訊介面可以接很多型別的顯示器。
多型的三個條件:
- 要有繼承或者實現;
- 要有重寫;
- 父類引用指向子類物件。(子類的物件賦予父類物件的引用)
static關鍵字
static可修飾的元素:
- 屬性
- 方法
- 程式碼塊
- 不能修飾區域性變數
static特點:
- 靜態的,全域性的
- 被static修飾的成員變數和成員方法獨立於該類的任何物件。不依賴於特定的例項,被類共享。只要這個類被載入(注意不是物件被載入),java的JVM就能根據類名在執行時資料區的方法內找到他們。
- 由於被static修飾的方法或變數只存在一個,那麼就衍生了一個特殊的使用,單例模式。
靜態方法的作用:
- 簡化方法的使用;
- 便於訪問靜態屬性;
注意事項:
- 靜態方法裡只能直接訪問靜態成員,而不能直接訪問類中的非靜態成員。
- 靜態方法中不能使用this,super關鍵字。
- 靜態方法不能被非靜態方法覆蓋,靜態方法不能修飾構造器。
靜態程式碼塊:
- 一個類中由static關鍵字修飾的,不包含在任何方法體中的程式碼塊;
- 當類被載入時,靜態程式碼塊被執行,且只被執行一次;
- 靜態塊經常用來進行類屬性的初始化。
單例模式
單例模式(singleton):保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
public class Singleton{
//私有靜態例項,仿製被直接引用。
//賦值null,目的就是實現延遲載入。不是引用類時就建立例項,而是在呼叫例項時再建立例項。
private static Singleton instance=null;
private Singleton(){
}
public static Singleton getInstance(){
if(instance==null)
{
instance=new Singleton();
}
return instance;
}
public Object readResolve(){
return instance;
}
}
當在多執行緒中使用的都應該是同一個物件。不管這個物件在哪使用,這個物件都應該是唯一的。
單例模式使用情況舉例:
- 工作管理員。
- Spring ioc Bean預設都是單例的。
單例模式要點:
- 某個類只能有一個例項;
- 他必須自行建立這個例項;
- 必須自行向整個系統提供這個例項。
內部類
內部類:定義在一個類中的另一個類,也叫巢狀類。 外部類:包含內部類的類。
作用:
- 提供了更好的封裝,可以把內部類隱藏在外部類之內。
- 內部類的成員可以直接訪問外部類的私有成員。
- 匿名內部類適合用於建立僅需要一次使用的類。
普通類的訪問許可權修飾符
- default
- public
內部類的訪問許可權修飾符
- default
- public
- protected
- private
靜態內部類 使用static來修飾的內部類,這個內部類不屬於任何類的物件,只屬於類的本身。 靜態內部類無法訪問外部類的例項。 批註:靜態成員其實就是作用域內共享的一塊記憶體,作用域可以使類/函式/檔案。靜態成員和全域性變數一起被存放在靜態區,在程式執行時就被例項化,同時將沒初始化的值初始化為0。
區域性內部類 定義:把一個內部類放在方法裡定義。區域性內部類僅在方法裡有效,不能使用訪問修飾符和static來修飾。
匿名內部類 概念:適合建立只需要一次使用的類,建立匿名內部類時會立即建立一個該類的例項,這個定義立即消失。 使用時可以直接使用new來建立一個匿名類。
列舉類
批註:靜態常量(static final)和列舉量(enum)可以通用,但是列舉量可以索引就更好用了。
常量模式:很多程式設計師和企業都喜歡定義靜態常量,並把這些常量放在一個常量類中,看起來很規矩。
列舉解決了靜態常量型別不安全的問題。
- 靜態常量可以做四則運算,列舉不允許;
- 靜態常量沒有名稱空間,這些常量隨便用。
列舉模式: 使用enum關鍵字來定義列舉類。
- 可以實現一個或多個介面;
- 不能有子類;
- 只能使用private來做構造器;
- 列舉類的所有例項必須在類的第一個行顯示列出。
//定義,列舉是個類。
public enum GoodState{
ON,DOWN,REMOVE;
}
//使用
GoodState g=GoodState.valueOf("ON");
if(GoodState.ON==g)
...
反射
概念:反射是指在執行時
狀態可以知道任意一個類的所有屬性和方法,對任意一個物件都可以呼叫他的任意一個方法;通過反射,可以在執行時例項化物件;
跟反射直接相關的模式就是代理模式。
通過反射可以:
- 在執行時判斷一個物件所屬的類;
- 在執行時構造任意一個類的物件。
- 在執行時判斷任意一個類的成員變數和方法;
- 在執行時任意一個物件的方法;
- 生成動態代理。
示例 1.獲取一個物件的包名或類名。
package com.xxx.demo;
public class Test{
public static void main(Stringp[] args){
Test trf=new Test();
System.out.println(trf.getClass().getName());
}
}
com.xxx.demo.Test
2.例項化class類的物件
package com.xxx.demo;
import java.lang.reflect.Method;
public class Test{
public void info(){
System.out.println("ok!");
}
public static void main(Stringp[] args){
// ? 是萬用字元,可以指向任何型別。class1作為中間類來使用。
Class<?> class1=null;
//將class1賦值為com.xxx.demo.Test型別。
class1=Class.forName("com.xxx.demo.Test");
//例項化物件
Test test=(Test)class1.newInstance();
test.info();
//獲取方法
Method method[]=class1.getMethods();
for(ing i=0;i<method.length;i++){
System.out.println(method[i].getName());
}
}
}
ok!
什麼是java執行時環境?就是java執行的時候計算機給你提供了什麼。
Object
Object是所有類的基礎。 Object提供了以下方法:
//比較兩個物件是否是同一個物件(比較雜湊地址)
public boolean equals(Object obj)
//返回物件的雜湊碼。
public int hashCode()
//返回物件的字串。
public String toString()
equals()與==的區別? 預設情況下(equals沒有被重寫),equals只能比較引用型別;==既能比較引用型別也能比較基本型別。
包裝類
java語言不把基本資料型別看做物件,因為它存在與棧中,不存在與堆中。 因此java提供了包裝類將基本資料型別轉化為物件。
批註:包裝應該和介面卡是一個意思,將一個轉換為另一個。
int pInt=500;
Integer wInt = new Integer(pInt);