黑馬程序員--Java基礎學習筆記【單例設計模式、網絡編程、反射】

 

 ------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------    

設計模式分類:

    創建模式:是對類的實例化過程的抽象化,又分爲類創建模式和對象創建模式

        類創建模式:工廠方法模式

        對象:簡單工廠(靜態工廠方法)模式、抽象工廠模式、單例模式、建造模式

    結構模式:描述如何將類或者對象結合在一起形成更大的結構

        適配器模式、缺省模式、合成模式、裝飾模式(包裝模式)、門面模式

    行爲模式:對不同的對象之間劃分責任和算法的抽象化

       不變模式、策略模式、迭代子模式、命令模式、訪問者模式

 

  • 單例設計模式(Singleton,一種對象創建模式)

    單例模式確保某一個類只有一個實例,而且自行實例化並向整個系統提供這個實例。

    如何保證類在內存中只有一個對象?

    1.私有化類的構造方法

    2. 本類的成員位置創建自己的本類對象

    3. 提供公共方法,讓外界獲取這個本類對象

-------------------------------餓漢式--------------------------------

/*

 * 餓漢式,適合開發

 * 在類初始化時,已經自行實例化

 */

class SingletonHungry {

    // 已經自行實例化

    privatestatic SingletonHungry s = new SingletonHungry();

 

    // 私有的默認構造器

    private SingletonHungry() {

    }

 

    // 靜態工廠方法

    publicstatic SingletonHungrygetInstance() {

       returns;

    }

}

---------------------------懶漢式(延遲加載)---------------------------

/*

 * 懶漢式,適合面試

 * 在第一次調用的時候實例化

 */

class SingletonLazy {

    // 沒有final修飾

    privatestatic SingletonLazy s = null;

 

    // 私有的默認構造器

    private SingletonLazy() {

    }

 

    // // 未考慮線程安全問題

    // public static SingletonLazy getInstance() {

    // if (s == null) {

    // s = new SingletonLazy();

    // }

    // return s;

    // }

 

    // // 靜態方法加鎖實現線程安全

    // public static synchronized SingletonLazy getInstance(){

    // if (s == null) {

    // s = new SingletonLazy();

    // }

    // return s;

    // }

 

    // 靜態工廠方法

    // 同步代碼塊實現線程安全,雙重檢查實現高效

    /*

     * 靜態方法鎖的對象是類對象,每個類都有唯一的一個類對象

     * 獲取類對象的方式:類名.class

     */

    /*

     * 靜態方法與非靜態方法同時聲明瞭 synchronized ,他們之間是非互斥關係的。

     * 原因在於,靜態方法鎖的是類對象,而非靜態方法鎖的是當前方法所屬對象。

     */

    publicstatic SingletonLazygetInstance() {

       if (s == null) { // 高效

           synchronized (SingletonLazy.class) { // 安全

              if (s == null) {

                  s = new SingletonLazy();

              }

           }

       }

       returns;

    }

}

 

==============================網絡編程===============================

InetAddress

    getByName 獲取任意主機的 IP 地址

    getHostName 返回字符串形式的主機名

    getHostAddress 得到主機字符串形式IP地址

端口:計算機與外界通信交流的出口

    知名端口:01024;動態端口:102465535

TCP UDP協議

TCP:面向連接的保護可靠傳輸的協議,不定長度的數據

UDP:無連接的協議,每個數據包中包含完整的源、目的信息,傳輸大小有限制 64KB

 

  • UDP 通信

DatagramPacket 用於發送和接收數據的不同構造方法

// 接收數據

DatagramPacket(byte[] ibuft, intlength)

DatagramPacket(byte[] ibuft, intoffset, int length)

// 發送數據(指定對方IP地址和端口)

DatagramPacket(byte[] ibuf, intilength, InetAddress iaddr, int port)

DatagramPacket(byte[] ibuf, intoffset, int ilength, InetAddress iaddr, int port)

 

DatagramPacket 對象的常用方法

InetAddress getAddress() // 返回遠程主機的IP地址

byte[] getData() // 返回字節數組類型的數據

int getLength() // 返回數據的字節數

int getPort() // 返回遠程主機的端口號

SocketAddress getSocketAddress() // 返回遠程主機的SocketAddress

int getOffset() // 返回數據的偏移量

 

DatagramSocket 對象的創建及常用方法

    DatagramSocket()

    DatagramSocket(int port)

    DatagramSocket(int port,InetAddress iaddr)

    InetAddress getLocalAddress() // 獲取套接字綁定本機IP地址

    int getLocalPort() // 返回套接字綁定本機端口號

    SocketAddressgetLocalSocketAddress() // 返回包含IP地址和端口號的sa

    void receive(DatagramPacket dp)// 接收數據包

    void send(DatagramPacket dp) // 發送數據包

 

  • 數據報套接字,接收端和發送端程序的編寫步驟

接收端:(明確端口:指定端口或隨機端口)

  1. 調用DatagramSocket(int port)創建一個數據報套接字,並綁定到指定端口

  2. 調用DatagramPacket(byte[] buf,int     length),建立一個字節數組以接收UDP

  3. 調用DatagramSocket類的receive()方法,接收UDP

  4. 最後關閉數據報套接字

發送端:(不需指定端口)

  1. 調用DatagramSocket()創建一個數據報套接字

  2. 調用DatagramPacket(byte[] buf, int     offset, int length, InetAddress address, int port),建立要發送的UDP

  3. 調用DatagramSocket類的send()方法,發送UDP

  4. 最後關閉數據報套接字

 

  • TCP 通信

Socket 的構造方法及常用方法

Socket(String host, int port)

Socket(InetAddress host, int port)

InputStream getInputStream()

OutputStream getOutputStream()

InetAddress getInetAddress() // 返回套接字連接的地址

int getPort() // 返回套接字連接到的遠程端口

close()

 

ServerSocket 的構造方法及常用方法

ServerSocket(int port)

ServerSocket(int port, int queuelength)

// 指定本地端口號,連接請求隊列的長度(最大連接數目),本地網絡地址

ServerSocket(int port, int queuelength, InetAddressbindaddress)

accept() // 偵聽並接受套接字的連接

close()

 

  • C/S通信的編寫步驟

服務器端的編寫流程:

  1. 指定本地端口號,創建ServerSocket對象,監聽指定端口的 Socket 連接

  2. 使用 ss 對象的accept()方法,接收的客戶端連接請求,返回Socket 對象

  3. 獲取Socket對象的輸入/輸出流

  4. 接收數據,處理數據,回傳數據

  5. 關閉流和 Socket,關閉 ServerSocket

客戶端的編寫流程

  1. 1.  指定要連接的 IP 地址和端口號,創建Socket對象

  2. 2.  獲取 socket 對象的輸入/輸出流

  3. 3.  讀寫字節流數據

  4. 4.  關閉流,關閉 Socket

 

  • 客戶端與服務端通信模型如下:

說明: http://pdf7.tarena.com.cn/source/doc/JSD1503Y/6090/index.files/p_w_picpath001.png

1.     服務端創建ServerSocket

2.     通過調用ServerSocket的accept方法監聽客戶端的連接

3.     客戶端創建Socket並指定服務端的地址以及端口來建立與服務端的連接

4.     當服務端accept發現客戶端連接後,獲取對應該客戶端的Socket

5.     雙方通過Socket分別獲取對應的輸入與輸出流進行數據通訊

6.     通訊結束後關閉連接。

 

 

  • 反射 reflection

    Java中類的反射是一種自我管理機制,通過反射可實現:

在運行時判斷任意一個對象所屬的類;

在運行時構造任意一個類的對象;

在運行時判斷任意一個類所具有的成員變量和成員方法;

在運行時調用任意一個對象的方法。

 

    類的加載過程:

加載:將.class文件讀入內存,併爲之創建一個 Class 對象

連接:

驗證內部結構

準備靜態成員分配內存默認初始化

解析二進制數據中的符號引用 --> 直接引用

初始化:

類初始化時機:

創建實例,訪問靜態變量,調用靜態方法,反射強行加載,初始化子類,運行主類

 

  • 三種方式獲取Class文件對象

       // 使用父類方法 getClass 獲取

       Classclass1p.getClass();

       System.out.println(class1);

      

       // 使用類的靜態屬性 class

       Classclass2= Person.class;

       System.out.println(class2);

      

       // 使用Class類的靜態方法 forName

       // 全類名

       Classclass3= Class.forName("cn.itcast.Person");

       System.out.println(class3);

 

  • 通過反射獲取構造方法並使用

       // 獲取class文件中的公有的構造方法

       Constructor<?>[]constructors= class3.getConstructors();

       for (Constructor<?> constructor : constructors) {

           System.out.println(constructor);

       }

      

       // 獲取指定構造方法,空參數

       Constructor<?>constructor= class3.getConstructor();

      

       // 運行獲取到的構造方法

       Objectobject= constructor.newInstance();

       System.out.println(object);

      

       System.out.println("--------------------------");

       // 獲取帶參數構造方法

       // 傳遞參數列表,要傳遞這個數據類型的class對象

       Constructorconstructor2= class3.getConstructor(String.class, int.class);

      

       Objectobject2= constructor2.newInstance("zs", 20);

       System.out.println(object2);

      

       System.out.println("--------------------------");

       // 獲取所有的構造方法

       Constructor<?>[]constructors2= class3.getDeclaredConstructors();

       for (Constructor<?> constructor3 : constructors2) {

           System.out.println(constructor3);

       }

      

       // 獲取私有構造方法並運行

       Constructorconstructor3= class3.getDeclaredConstructor(String.class);

      

//     //調用Constructor父類方法 setAccessible(true)

//     constructor3.setAccessible(true);// 暴力訪問,不建議使用

      

//     constructor3.newInstance("ls");// java.lang.IllegalAccessException

//     System.out.println(constructor3);

      

       System.out.println("==========================");

      

       // 保證空參數的構造方法存在,並且具有可訪問權限

       Classclazz= Class.forName("cn.itcast.Person");

       // 不獲取構造方法,直接調用具有可訪問權限的空參數的構造方法

       Objectobject3= clazz.newInstance();

       System.out.println(object3);

 

  • 通過反射獲取成員變量並使用

       // 獲取所有公共成員變量

       Field[]fields= clazz.getFields();

       for (Field field : fields) {

           System.out.println(field);

       }

      

       // 獲取指定成員變量

//     Fieldfields2 = clazz.getField("age");

//     System.out.println(fields2);

      

       // 修改獲取到的成員變量值,必須有這個類的支持

//     Objectobj = clazz.newInstance();

//     fields2.set(obj,22);

      

       // 獲取所有成員變量

       clazz.getDeclaredFields();

       // 獲取指定的成員變量

       clazz.getDeclaredField("age");

 

  • 通過反射獲取成員方法並使用

       // 獲取所有公共成員方法和繼承的

       Method[]methods= clazz.getMethods();

       for (Method method : methods) {

           System.out.println(method);

       }

      

       // 獲取指定的成員方法 (字符串方法名,Class類型的參數列表)

       Methodmethod= clazz.getMethod("toString");

       System.out.println(method);

       // 運行獲取到的方法,傳遞對象和實際參數

       Objectobj= clazz.newInstance();

       method.invoke(obj);

      

       Methodmethod2= clazz.getMethod("setName",String.class);

       System.out.println(method2);

       method2.invoke(obj, "ww");

      

       // 獲取所有成員方法,不包括繼承的

       clazz.getDeclaredMethods();

       // 獲取指定的成員方法

//     clazz.getDeclaredMethod(name,parameterTypes);

 

 

  • 已知ArrayList<Integer>的一個對象,如何實現往集合中添加一個字符串數據?

package cn.itcast;

 

import java.lang.reflect.InvocationTargetException;

import java.lang.reflect.Method;

import java.util.ArrayList;

 

/*

 * 考查對反射原理的理解

 * 反射將泛型進行擦除

 * 反射繞過編譯器檢查,將不同的數據類型存儲到帶泛型的集合

 */

publicclassReflectTest {

 

    publicstaticvoid main(String[] args) throws NoSuchMethodException,SecurityException, IllegalAccessException,

           IllegalArgumentException,InvocationTargetException {

       ArrayList<Integer>list= newArrayList<>();

       list.add(0);

       list.add(1);

       list.add(2);

       list.add(3);

 

       // 反射獲取ArrayList.class 文件中的add() 方法

       Classclazz= list.getClass();

       Methodmethod= clazz.getMethod("add", Object.class);

       method.invoke(list, "itcast");

 

       System.out.println(list);

    }

 

}

 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章