1. 程式人生 > 實用技巧 >HTTP中的訊息頭

HTTP中的訊息頭

反射:在類執行時,能夠動態獲取並訪問其構造結構的機制稱為反射機制。

反射是Java中框架設計的核心,通過對類的構造、屬性、方法等資料的獲取提供抽象的底層構建

反射機制:
反射需要先獲得類的class位元組碼,由JVM類載入器(ClassLoader)負責載入,並在記憶體中快取class的內部結構。藉助於Java的反射機制允許快速對類的結構資料進行訪問和呼叫

獲得class位元組碼檔案的三種方式:
  1.Object物件的getClass()方法

獲得方式一
Class<User> userClass = (Class<User>) user.getClass();

  2.類的class靜態屬性(一個類只有一個class,例項化多次對應的都是同一個class,所以class可以用==進行比較,a.getClass==b.getClass)

獲得方式二
Class<User> userClass = User.class;

  3.Class.forName(String classPath)的載入(反射應用的核心

獲得方式三  通過類路徑訪問類的Class資訊,在不知道型別的情況下,可以不寫泛型
Class<User> userClass = (Class<User>) Class.forName("com.igeek.pojo.User");

反射允許獲取到類的各種構造結構,包括構造方法、方法、屬性、介面、註解等
反射能夠對類完成例項構建,並能對方法進行例項呼叫

第三種方法的使用:

Class objClass = Class.forName(“com.igeek.pojo.User”)
Object obj = objClass.newInstance()

獲取類的構造方法

getConstructor(Class<T>… parameterTypes)
getConstructors()

獲取類的屬性

getField(String fieldName)
getFields()

獲取類的方法

getMethod(String methodName,Class<T>…parameterType)
getMethods()

獲取類的介面

getInterfaces()

獲取類的超類

getSuperclass()

XML
Extensible Markup Language 可擴充套件標記語言

作用:
  1.用於對工程進行外部配置
  2.用於描述複雜格式的資料,對資料進行儲存管理
  3.用於跨應用進行資料的互動

每一個XML檔案都以標籤的方式進行編寫,並且必須要有一個跟標籤
XML中每個標籤都稱為節點或元素,標籤體的文字也是節點元素,稱為文字節點

定義根標籤:使用DTD或者是Schema檔案來定義XML的內容

解析XML文件主要有兩種方式:
1.DOM解析
特點: 將整個XML文件全部載入至記憶體中,在記憶體中對文件進行解析
2.SAX解析
特點:使用事件驅動方式進行解析,一邊讀取一邊解析

DOM解析的使用步驟:

1.DOM4j架包匯入:

File——Project Structures——Libraries——選擇DOM所在的位置——OK

2.建立XML

Setting——Editor——File and Code templates——"+"——名稱為“new.xml”——輸入“<?xml version="1.0" encoding="UTF-8"?>”——單擊"OK"

3.新建檔案

新建檔案進行new一個new.xml檔案

MyInterfaceA

package com.igeek;

public interface MyInterfaceA {
}

MyInterfaceB

package com.igeek;

public interface MyInterfaceB {
}

Human類

package com.igeek.pojo;

public class Human {
    public int age;

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

User類

package com.igeek.pojo;

import com.igeek.MyInterfaceA;
import com.igeek.MyInterfaceB;

//實現了A、B兩個介面,繼承了Human類
public class User extends Human implements MyInterfaceA, MyInterfaceB {
    //三個屬性
    private int userId;
    private String userName;
    public String password;

    //空參構造方法
    public User() {
    }

    //帶參構造方法
    public User(int userId, String userName, String password) {
        this.userId = userId;
        this.userName = userName;
        this.password = password;
    }

    //屬性的get 、set方法
    public int getUserId() {
        return userId;
    }
    public void setUserId(int userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }
    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
}

獲取類的方法

package com.igeek;

import com.igeek.pojo.Human;
import com.igeek.pojo.User;

/**
 * 獲得class檔案
 * 反射是基於Class型別訪問的
 * Class物件封裝快取了類的資料結構
 */
public class Demo1 {

    public static void main(String[] args) {
        User user = new User();
        Human human = new User();

        //獲得方式一:返回值為Class,不寫泛型預設為object型別,寫了泛型就要進行強轉
     //將類例項化以後對物件進行獲取class處理

        Class<User> userClass = (Class<User>) user.getClass();

        //獲得方式二:不用對類進行例項化,直接對類進行獲取class處理
        Class<User> userClass = User.class;

     //獲得方式三 通過類路徑訪問類的Class資訊
        try {
            //這個方法是因為:這個方法是可以在不明確型別和其結構時使用,
       (第一個方法都已經將物件例項化出來了,不需要使用反射。)
Class<User> userClass = (Class<User>) Class.forName("com.igeek.pojo.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); }     //上面兩種(第一種和第二種獲取class方法)方式主要用於多型場景下的型別匹配
if(human instanceof User){ System.out.println("human的例項型別是user型別"); } if(human.getClass() == User.class){ System.out.println("human的例項型別是user型別"); } } }

第三種獲取class方法的應用:

package com.igeek;

import com.igeek.pojo.User;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * 使用反射解析類的資料結構
 */
public class Demo2 {

    public static void main(String[] args) {

        try {
            //獲得類的Class物件(第三種方法),該物件封裝了類的資料結構資訊
            Class objClass =  Class.forName("com.igeek.pojo.User");
            //使用反射將類進行例項化
            //該方式只能通過類的無參構造進行例項化
            Object obj = objClass.newInstance();
            System.out.println("例項化後的結果:"+obj);


            //獲得類的所有的構造方法:返回值是構造方法的陣列  構造方法的型別是Constructor型別
            Constructor[] constructors = objClass.getConstructors();
       //可獲得私有的構造方法
       Constructor[] constructors=ObjClass.getDeclareConstructors(); System.out.println(
"該類有"+constructors.length+"個構造方法"); //遍歷所有的構造 for (Constructor constructor : constructors) { System.out.println("\n-----------------------------"); //獲得構造方法的引數數量 int paramCount = constructor.getParameterCount(); System.out.println("構造方法的引數數量:"+paramCount); //獲得構造方法的引數型別 Class[] paramClassArray = constructor.getParameterTypes(); for (Class paramClass : paramClassArray) { System.out.print(paramClass.getName()+"\t"); } } System.out.println(); //根據引數獲得指定的構造方法 //獲得無參的構造 Constructor constructor1 = objClass.getConstructor(); System.out.println(constructor1); //根據構造方法來例項化物件 Object obj1 = constructor1.newInstance(); System.out.println(obj1); //獲得帶參構造方法:通過引數的class獲取指定的構造方法
       //基本型別和包裝類的class是不同的
Constructor constructor2 = objClass.getConstructor(int.class,String.class,String.class); //使用帶參的構造方法例項化物件
       //可以用Object接收
       Object obj2=constructor2.newInstance(100,"tom","123");
       //也可強轉後用User接收 User user = (User) constructor2.newInstance(100,"tom","123"); System.out.println(user.getUserId()+"\t"+user.getUserName()+"\t"+user.getPassword()); //獲得當前類的父類 Class superClass = objClass.getSuperclass(); System.out.println("\n------------父類------------");
       //若結果是Object則這個類沒有手動進行extends繼承 System.out.println(superClass);
//獲取實現的介面 Class[] interfaceClasses = objClass.getInterfaces(); System.out.println("\n---------實現的介面---------"); for (Class interfaceClass : interfaceClasses) { System.out.println(interfaceClass.getName()); }

//獲得屬性 //訪問當前允許訪問(具有訪問許可權)到的屬性,包括父類繼承得到的屬性
       (不同包中加了protect或者加了private或者沒加訪問修飾符的都沒有訪問許可權)
Field[] fields = objClass.getFields(); //訪問當前類(本類)直接宣告的屬性,不論訪問修飾符是什麼 Field[] fields = objClass.getDeclaredFields(); System.out.println("\n------------屬性-------------"); for (Field field : fields) { //獲得屬性的名稱 System.out.println("屬性名稱:"+field.getName()); //獲得屬性的型別 System.out.println("屬性型別:"+field.getType()); } System.out.println("\n-------------------------------"); //獲得指定名稱屬性 Field nameField = objClass.getDeclaredField("userName"); //為屬性提供訪問許可權,即使是私有屬性也將允許訪問處理 nameField.setAccessible(true); //屬性進行賦值,第一個引數表示該屬性從屬的物件,第二個引數表示要設定的值 //set方法允許對屬性進行賦值,但是會根據屬性本身的訪問修飾符來決定是否可以成功操作
       (paivate時不能被set,但是setAccessible後即可不管是什麼訪問修飾符都可以進行設定可以訪問處理)
nameField.set(user,"jack"); //System.out.println(user.getUserName()); //獲取屬性的值 Object value = nameField.get(user); System.out.println(value); System.out.println("--------------方法的訪問-------------");
       //獲取所有方法,包括私有的
       Method[] methods=objClass.getDeclareMethods();
       //獲取所有方法 Method[] methods
= objClass.getMethods(); for (Method method : methods) { //獲取方法的名稱 System.out.println("方法名:"+method.getName()); //獲取返回值型別 Class returnClass = method.getReturnType(); System.out.println("返回值型別:"+returnClass); //獲取方法的引數型別 Class[] paramClassArray = method.getParameterTypes(); System.out.println("方法的引數:"); for (Class paramClass : paramClassArray) { System.out.println(paramClass); } System.out.println("------------------"); } //獲取一個指定名稱的方法:第一個引數是方法的名稱,第二個引數是引數的型別,可以多個可以一個可以沒有 Method setMethod = objClass.getMethod("setUserName", String.class); //使用反射呼叫方法(修改原內容):第一個引數是代表修改的哪個物件中的內容,第二個引數是要修改成的值 setMethod.invoke(user, "admin"); Method getMethod = objClass.getMethod("getUserName"); //呼叫方法(獲得返回值):返回值是Object型別,如果呼叫的方法沒有返回值,則返回的值null Object returnValue = getMethod.invoke(user); System.out.println("返回值是:"+returnValue); } catch (Exception e) { e.printStackTrace(); } } }

例子:

使用反射動態解析javax.swing.JFrame類

使用反射例項化該物件

使用反射動態解析該類的構造方法,獲得構造方法的引數數量和型別

並使用無參構造以及帶有String的構造
方法來例項化JFrame物件

package Demo1;
import java.lang.reflect.Constructor;

public class Demo {
    public static void main(String[] args) {
        //獲取類方法
        try {
            Object objClass=Class.forName("javax.swing.JFrame");
            //使用反射例項化該物件
            Object obj=((Class) objClass).newInstance();
            System.out.println("例項化後的物件是:"+obj);

            //使用反射動態解析該類的構造方法,獲得構造方法的引數數量和型別
            Constructor[] constructors=((Class) objClass).getConstructors();
            System.out.println("共有"+constructors.length+"個構造方法");
            //獲得構造方法的引數數量和型別
            for (Constructor constructor : constructors) {
                //獲取引數數量
                int count=constructor.getParameterCount();
                System.out.println("該構造方法有"+count+"個引數");
                //獲取引數型別
                Class[] classes=constructor.getParameterTypes();
                for (Class aClass : classes) {
                    System.out.println(aClass.getName()+"\t");
                }
            }
            //使用無參構造
            Constructor con1=((Class) objClass).getConstructor();
            Object Obj1=con1.newInstance();
            System.out.println("無參構造例項化物件是:"+Obj1);

            //帶有String的構造
            Constructor con2=((Class) objClass).getConstructor(String.class);
            Object Obj2=con2.newInstance("我是一個標題");
            System.out.println("帶參構造例項化物件是:"+Obj2);

若是想要獲得父類和子類所以的屬性,則需要進行遞迴,先對子類進行屬性的獲得,然後獲得子類的父類,如果不是Object型別,則使用遞迴將父類傳入繼續進行屬性的獲得

XML的使用:

根標籤:(user是標籤名稱, id是標籤屬性, 1001是標籤值, userName和password是標籤體的內容)

XML中每個標籤都稱為節點或元素,標籤體的文字也是節點元素,稱為文字節點

(紫色標記的都是節點,紅色標記的都是文字加點,所以一共11個節點)

框架中靈活處理的內容都要寫成配置檔案,通過底層程式碼對配置檔案進行解析,解析完成後通過反射進行處理呼叫

<?xml version="1.0" encoding="UTF-8"?>
//相當於集合儲存使用者資訊 <users>   //使用者一   <user id="1001" age=20>     //標籤體(標籤內容)     <userName>tom</userName>     <password>tom123</password>   </user>   //標籤二:使用者二   <user id="1002" age=21>     //標籤體(標籤內容)     <userName>jack</userName>     <password>jack123</password>   </user> </users>
package com.igeek;

import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import java.util.List;

/**
 * 使用DOM4J對XML文件進行解析
 */
public class Demo3 {

    public static void main(String[] args) {

        //使用ClassLoader獲取資源是在類路徑(src資料夾內)中訪問的
        //System.out.println(Demo3.class.getClassLoader().getResource("").getPath());
        //使用類自身Class物件獲取資源是在類所在的包路徑中訪問的
        //System.out.println(Demo3.class.getResource("").getPath());
        //從類路徑中訪問檔案並將檔案轉換為輸入流
        //System.out.println(Demo3.class.getClassLoader().getResourceAsStream("test.xml"));
        try {
            //建立SAX解析器物件
            SAXReader reader = new SAXReader();
            //通過獲取xml檔案的輸入流,載入文件
       //通過類的class獲取classLoader ,在通過classLoader讀取檔案的輸入流
       //這個方式是從當前類所在的包中查詢test.xml檔案
       //Document document=reader.read(Dome3.class.getClass().getResourceAsStream("test.xml"));
       //這個方式是從整個專案的路徑中查詢test.xml檔案 Document document = reader.read(Demo3.class.getClassLoader().getResourceAsStream("test.xml")); //獲取文件的根節點物件 Element root = document.getRootElement(); //訪問節點的名字 System.out.println(root.getName()); //訪問節點中的所有下一層子節點 List<Element> list = root.elements();//獲取的是陣列:所有的節點 //遍歷user標籤 for (Element element : list) { System.out.println(element.getName()); //訪問標籤的所有屬性,也可以通過attribute通過名稱獲取單獨的一個屬性 List<Attribute> attributeList = element.attributes();//得到的是集合所有的屬性 //遍歷屬性(屬性的型別是:Attibute標籤的型別是:Element for (Attribute attribute : attributeList) { //獲取屬性的名稱 System.out.print("\t"+attribute.getName()+":"); //獲取屬性的值 System.out.println(" "+attribute.getValue()); } //獲得指定的userName子標籤 Element nameNode = element.element("userName"); System.out.println("\t"+nameNode.getName()); //獲取userName的標籤體文字:trim是去除空格(如果只是需要查詢不需要操作,也可以不用接收直接列印) String name = nameNode.getTextTrim(); System.out.println("\t\t"+name); //獲取password子標籤 Element pwdNode = element.element("password"); System.out.println("\t"+pwdNode.getName()); System.out.println("\t\t"+pwdNode.getTextTrim()); } } catch (DocumentException e) { e.printStackTrace(); } } }