天天看點

Java基礎文法_26_基礎加強02

基礎加強02

    • 1.xml
      • 1.1概述【了解】
      • 1.2标簽的規則【應用】
      • 1.3文法規則【應用】
      • 1.4xml解析【應用】
      • 1.5DTD限制【了解】
      • 1.6schema限制【了解】
      • 1.7伺服器改進【應用】
    • 2.枚舉
      • 2.1概述【了解】
      • 2.2定義格式【應用】
      • 2.3枚舉的特點【了解】
      • 2.4枚舉的方法【應用】
    • 3.注解
      • 3.1概述【了解】
      • 3.2自定義注解【了解】
      • 3.3元注解【了解】
      • 3.4改寫伺服器【了解】

1.xml

1.1概述【了解】

  • 網際網路聯盟(W3C)

    網際網路聯盟(W3C)建立于1994年,又稱W3C理事會。1994年10月在麻省理工學院計算機科學實驗室成立。

    建立者: Tim Berners-Lee (蒂姆·伯納斯·李)。

    是Web技術領域最具權威和影響力的國際中立性技術标準機構。

    到目前為止,W3C已釋出了200多項影響深遠的Web技術标準及實施指南,

    • 如廣為業界采用的超文本标記語言HTML(标準通用标記語言下的一個應用)、
    • 可擴充标記語言XML(标準通用标記語言下的一個子集)
    • 以及幫助殘障人士有效獲得Web資訊的無障礙指南(WCAG)等
      Java基礎文法_26_基礎加強02
  • xml概述

    XML的全稱為(EXtensible Markup Language),是一種可擴充的标記語言

    标記語言: 通過标簽來描述資料的一門語言(标簽有時我們也将其稱之為元素)

    可擴充:标簽的名字是可以自定義的,XML檔案是由很多标簽組成的,而标簽名是可以自定義的

  • 作用
    • 用于進行存儲資料和傳輸資料
    • 作為軟體的配置檔案
  • 作為配置檔案的優勢
    • 可讀性好
    • 可維護性高

1.2标簽的規則【應用】

  • 标簽由一對尖括号和合法辨別符組成
  • 标簽必須成對出現
    <student> </student>
    前邊的是開始标簽,後邊的是結束标簽
               
  • 特殊的标簽可以不成對,但是必須有結束标記
  • 标簽中可以定義屬性,屬性和标簽名空格隔開,屬性值必須用引号引起來
  • 标簽需要正确的嵌套
    這是正确的: <student id="1"> <name>張三</name> </student>
    這是錯誤的: <student id="1"><name>張三</student></name>
               

1.3文法規則【應用】

  • 文法規則
    • XML檔案的字尾名為:xml
    • 文檔聲明必須是第一行第一列

      <?xml version="1.0" encoding="UTF-8" standalone="yes”?>

      version:該屬性是必須存在的

      encoding:該屬性不是必須的

      ​ 打開目前xml檔案的時候應該是使用什麼字元編碼表(一般取值都是UTF-8)

      standalone: 該屬性不是必須的,描述XML檔案是否依賴其他的xml檔案,取值為yes/no

    • 必須存在一個根标簽,有且隻能有一個
    • XML檔案中可以定義注釋資訊
    • XML檔案中可以存在以下特殊字元
      &lt; < 小于
      &gt; > 大于
      &amp; & 和号
      &apos; ' 單引号
      &quot; " 引号
                 
    • XML檔案中可以存在CDATA區

      <![CDATA[ …内容… ]]>

  • 示例代碼
    <?xml version="1.0" encoding="UTF-8" ?>
    <!--注釋的内容-->
    <!--本xml檔案用來描述多個學生資訊-->
    <students>
    
        <!--第一個學生資訊-->
        <student id="1">
            <name>張三</name>
            <age>23</age>
            <info>學生&lt; &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;的資訊</info>
            <message> <![CDATA[内容 <<<<<< >>>>>> ]]]></message>
        </student>
    
        <!--第二個學生資訊-->
        <student id="2">
            <name>李四</name>
            <age>24</age>
        </student>
    
    </students>
               

1.4xml解析【應用】

  • 概述

    xml解析就是從xml中擷取到資料

  • 常見的解析思想

    DOM(Document Object Model)文檔對象模型:就是把文檔的各個組成部分看做成對應的對象。

    會把xml檔案全部加載到記憶體,在記憶體中形成一個樹形結構,再擷取對應的值

    Java基礎文法_26_基礎加強02
  • 常見的解析工具
    • JAXP: SUN公司提供的一套XML的解析的API
    • JDOM: 開源組織提供了一套XML的解析的API-jdom
    • DOM4J: 開源組織提供了一套XML的解析的API-dom4j,全稱:Dom For Java
    • pull: 主要應用在Android手機端解析XML
  • 解析的準備工作
    1. 我們可以通過網站:https://dom4j.github.io/ 去下載下傳dom4j

      今天的資料中已經提供,我們不用再單獨下載下傳了,直接使用即可

    2. 将提供好的dom4j-1.6.1.zip解壓,找到裡面的dom4j-1.6.1.jar
    3. 在idea中目前子產品下建立一個libs檔案夾,将jar包複制到檔案夾中
    4. 選中jar包 -> 右鍵 -> 選擇add as library即可
  • 需求
    • 解析提供好的xml檔案
    • 将解析到的資料封裝到學生對象中
    • 并将學生對象存儲到ArrayList集合中
    • 周遊集合
  • 代碼實作
    <?xml version="1.0" encoding="UTF-8" ?>
    <!--注釋的内容-->
    <!--本xml檔案用來描述多個學生資訊-->
    <students>
    
        <!--第一個學生資訊-->
        <student id="1">
            <name>張三</name>
            <age>23</age>
        </student>
    
        <!--第二個學生資訊-->
        <student id="2">
            <name>李四</name>
            <age>24</age>
        </student>
    
    </students>
    
    // 上邊是已經準備好的student.xml檔案
    public class Student {
        private String id;
        private String name;
        private int age;
    
        public Student() {
        }
    
        public Student(String id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
    
        public String getId() {
            return id;
        }
    
        public void setId(String id) {
            this.id = id;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "id='" + id + '\'' +
                    ", name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    
    /**
     * 利用dom4j解析xml檔案
     */
    public class XmlParse {
        public static void main(String[] args) throws DocumentException {
            //1.擷取一個解析器對象
            SAXReader saxReader = new SAXReader();
            //2.利用解析器把xml檔案加載到記憶體中,并傳回一個文檔對象
            Document document = saxReader.read(new File("myxml\\xml\\student.xml"));
            //3.擷取到根标簽
            Element rootElement = document.getRootElement();
            //4.通過根标簽來擷取student标簽
            //elements():可以擷取調用者所有的子标簽.會把這些子标簽放到一個集合中傳回.
            //elements("标簽名"):可以擷取調用者所有的指定的子标簽,會把這些子标簽放到一個集合中并傳回
            //List list = rootElement.elements();
            List<Element> studentElements = rootElement.elements("student");
            //System.out.println(list.size());
    
            //用來裝學生對象
            ArrayList<Student> list = new ArrayList<>();
    
            //5.周遊集合,得到每一個student标簽
            for (Element element : studentElements) {
                //element依次表示每一個student标簽
      
                //擷取id這個屬性
                Attribute attribute = element.attribute("id");
                //擷取id的屬性值
                String id = attribute.getValue();
    
                //擷取name标簽
                //element("标簽名"):擷取調用者指定的子标簽
                Element nameElement = element.element("name");
                //擷取這個标簽的标簽體内容
                String name = nameElement.getText();
    
                //擷取age标簽
                Element ageElement = element.element("age");
                //擷取age标簽的标簽體内容
                String age = ageElement.getText();
    
    //            System.out.println(id);
    //            System.out.println(name);
    //            System.out.println(age);
    
                Student s = new Student(id,name,Integer.parseInt(age));
                list.add(s);
            }
            //周遊操作
            for (Student student : list) {
                System.out.println(student);
            }
        }
    }
               

1.5DTD限制【了解】

  • 什麼是限制

    用來限定xml檔案中可使用的标簽以及屬性

  • 限制的分類
    • DTD
    • schema
  • 編寫DTD限制
    • 步驟
      1. 建立一個檔案,這個檔案的字尾名為.dtd
      2. 看xml檔案中使用了哪些元素

        <!ELEMENT> 可以定義元素

      3. 判斷元素是簡單元素還是複雜元素

        簡單元素:沒有子元素。

        複雜元素:有子元素的元素;

    • 代碼實作
      <!ELEMENT persons (person)>
      <!ELEMENT person (name,age)>
      <!ELEMENT name (#PCDATA)>
      <!ELEMENT age (#PCDATA)>
                 
  • 引入DTD限制
    • 引入DTD限制的三種方法
      • 引入本地dtd
      • 在xml檔案内部引入
      • 引入網絡dtd
    • 代碼實作
      • 引入本地DTD限制
        // 這是persondtd.dtd檔案中的内容,已經提前寫好
        <!ELEMENT persons (person)>
        <!ELEMENT person (name,age)>
        <!ELEMENT name (#PCDATA)>
        <!ELEMENT age (#PCDATA)>
        
        // 在person1.xml檔案中引入persondtd.dtd限制
        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE persons SYSTEM 'persondtd.dtd'>
        
        <persons>
            <person>
                <name>張三</name>
                <age>23</age>
            </person>
        
        </persons>
                   
      • 在xml檔案内部引入
        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE persons [
                <!ELEMENT persons (person)>
                <!ELEMENT person (name,age)>
                <!ELEMENT name (#PCDATA)>
                <!ELEMENT age (#PCDATA)>
                ]>
        
        <persons>
            <person>
                <name>張三</name>
                <age>23</age>
            </person>
        
        </persons>
                   
      • 引入網絡dtd
        <?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE persons PUBLIC "dtd檔案的名稱" "dtd文檔的URL">
        
        <persons>
            <person>
                <name>張三</name>
                <age>23</age>
            </person>
        
        </persons>
                   
  • DTD文法
    • 定義元素

      定義一個元素的格式為:<!ELEMENT 元素名 元素類型>

      簡單元素:

      ​ EMPTY: 表示标簽體為空

      ​ ANY: 表示标簽體可以為空也可以不為空

      ​ PCDATA: 表示該元素的内容部分為字元串

      複雜元素:

      ​ 直接寫子元素名稱. 多個子元素可以使用",“或者”|"隔開;

      ​ ","表示定義子元素的順序 ; “|”: 表示子元素隻能出現任意一個

      ​ "?"零次或一次, "+"一次或多次, "*"零次或多次;如果不寫則表示出現一次

      Java基礎文法_26_基礎加強02
    • 定義屬性

      格式

      定義一個屬性的格式為:<!ATTLIST 元素名稱 屬性名稱 屬性的類型 屬性的限制>

      屬性的類型:

      ​ CDATA類型:普通的字元串

      屬性的限制:

      ​ // #REQUIRED: 必須的

      ​ // #IMPLIED: 屬性不是必需的

      ​ // #FIXED value:屬性值是固定的

    • 代碼實作
      <!ELEMENT persons (person+)>
      <!ELEMENT person (name,age)>
      <!ELEMENT name (#PCDATA)>
      <!ELEMENT age (#PCDATA)>
      <!ATTLIST person id CDATA #REQUIRED>
      
      <?xml version="1.0" encoding="UTF-8" ?>
      <!DOCTYPE persons SYSTEM 'persondtd.dtd'>
      
      <persons>
          <person id="001">
              <name>張三</name>
              <age>23</age>
          </person>
      
          <person id = "002">
              <name>張三</name>
              <age>23</age>
          </person>
      
      </persons>
      ​```
                 

1.6schema限制【了解】

  • schema和dtd的差別
    1. schema限制檔案也是一個xml檔案,符合xml的文法,這個檔案的字尾名.xsd
    2. 一個xml中可以引用多個schema限制檔案,多個schema使用名稱空間區分(名稱空間類似于java包名)
    3. dtd裡面元素類型的取值比較單一常見的是PCDATA類型,但是在schema裡面可以支援很多個資料類型
    4. schema 文法更加的複雜
    Java基礎文法_26_基礎加強02
  • 編寫schema限制
    • 步驟

      1,建立一個檔案,這個檔案的字尾名為.xsd。

      2,定義文檔聲明

      3,schema檔案的根标簽為:

      4,在中定義屬性:

      ​ xmlns=http://www.w3.org/2001/XMLSchema

      5,在中定義屬性 :

      ​ targetNamespace =唯一的url位址,指定目前這個schema檔案的名稱空間。

      6,在中定義屬性 :

      ​ elementFormDefault="qualified“,表示目前schema檔案是一個品質良好的檔案。

      7,通過element定義元素

      8,判斷目前元素是簡單元素還是複雜元素

      Java基礎文法_26_基礎加強02
    • 代碼實作
      <?xml version="1.0" encoding="UTF-8" ?>
      <schema
          xmlns="http://www.w3.org/2001/XMLSchema"
          targetNamespace="http://www.itheima.cn/javase"
          elementFormDefault="qualified"
      >
      
          <!--定義persons複雜元素-->
          <element name="persons">
              <complexType>
                  <sequence>
                      <!--定義person複雜元素-->
                      <element name = "person">
                          <complexType>
                              <sequence>
                                  <!--定義name和age簡單元素-->
                                  <element name = "name" type = "string"></element>
                                  <element name = "age" type = "string"></element>
                              </sequence>
                              
                          </complexType>
                      </element>
                  </sequence>
              </complexType>
      
          </element>
      
      </schema>
      
                 
  • 引入schema限制
    • 步驟

      1,在根标簽上定義屬性xmlns=“http://www.w3.org/2001/XMLSchema-instance”

      2,通過xmlns引入限制檔案的名稱空間

      3,給某一個xmlns屬性添加一個辨別,用于區分不同的名稱空間

      ​ 格式為: xmlns:辨別=“名稱空間位址” ,辨別可以是任意的,但是一般取值都是xsi

      4,通過xsi:schemaLocation指定名稱空間所對應的限制檔案路徑

      ​ 格式為:xsi:schemaLocation = "名稱空間url 檔案路徑“

    • 代碼實作
      <?xml version="1.0" encoding="UTF-8" ?>
      
      <persons
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns="http://www.itheima.cn/javase"
          xsi:schemaLocation="http://www.itheima.cn/javase person.xsd"
      >
          <person>
              <name>張三</name>
              <age>23</age>
          </person>
      
      </persons>
      ​```
                 
  • schema限制定義屬性
    • 代碼示例
      <?xml version="1.0" encoding="UTF-8" ?>
      <schema
          xmlns="http://www.w3.org/2001/XMLSchema"
          targetNamespace="http://www.itheima.cn/javase"
          elementFormDefault="qualified"
      >
      
          <!--定義persons複雜元素-->
          <element name="persons">
              <complexType>
                  <sequence>
                      <!--定義person複雜元素-->
                      <element name = "person">
                          <complexType>
                              <sequence>
                                  <!--定義name和age簡單元素-->
                                  <element name = "name" type = "string"></element>
                                  <element name = "age" type = "string"></element>
                              </sequence>
                              
                              <!--定義屬性,required( 必須的)/optional( 可選的)-->
                              <attribute name="id" type="string" use="required"></attribute>
                          </complexType>
                          
                      </element>
                  </sequence>
              </complexType>
          </element>
          
      </schema>
      
      <?xml version="1.0" encoding="UTF-8" ?>
      <persons
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xmlns="http://www.itheima.cn/javase"
          xsi:schemaLocation="http://www.itheima.cn/javase person.xsd"
      >
          <person id="001">
              <name>張三</name>
              <age>23</age>
          </person>
      
      </persons>
      ​```
                 

1.7伺服器改進【應用】

  • 準備xml檔案
    1. 在目前子產品下的webapp目錄下建立一個檔案夾,名字叫WEB-INF
    2. 建立一個xml檔案,名字叫web.xml
    3. 将資料中的web.xml檔案中引入限制的代碼複制到建立的web.xml檔案中
    4. 将要解析的資料配置到xml檔案中
      Java基礎文法_26_基礎加強02
  • 需求

    把uri和servlet資訊放到一個concurrentHashMap集合當中

    當浏覽器請求一個動态資源時,我們會擷取uri對應的servlet來處理目前業務

  • 實作步驟
    1. 導入dom4j的jar包
    2. 定義一個XmlParseServletConfig類實作ParseServletConfig接口
    3. 在parse方法裡面就可以解析xml檔案了
  • 代碼實作
    // web.xml配置檔案中配置的資訊
    <?xml version="1.0" encoding="UTF-8" ?>
    <web-app xmlns="http://java.sun.com/xml/ns/javaee"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
             version="2.5">
    
        <!--在以後需要配置servlet的時候,就直接在這裡配置就可以了-->
        <servlet>
            <servlet-name>LoginServlet</servlet-name>
            <servlet-class>com.itheima.myservlet.LoginServlet</servlet-class>
        </servlet>
    
        <servlet-mapping>
            <servlet-name>LoginServlet</servlet-name>
            <url-pattern>/servlet/loginservlet</url-pattern>
        </servlet-mapping>
    
    </web-app>
    
    // 定義一個XmlParseServletConfig類實作ParseServletConfig接口
    public class XMLParseServletConfig implements ParseServletConfig {
        //定義web.xml檔案的路徑
        private static final String WEB_XML_PATH = "http-dynamic-server/webapp/WEB-INF/web.xml";
    
    	//在parse方法裡面就可以解析xml檔案了
        @Override
        public void parse() {
            try {
                //1.建立一個解析器對象(注意:如果解析器對象等不能使用,請檢查一下jar包是否導入)
                SAXReader saxReader = new SAXReader();
    
                //2.利用解析器把xml檔案讀取到記憶體中
                Document document = saxReader.read(new File(WEB_XML_PATH));
    
                //3.擷取根節點元素對象
                Element rootElement = document.getRootElement();
    
                //建立一個Map集合,用來存儲servlet的配置資訊
                HashMap<String,String> servletInfoHashMap = new HashMap<>();
    
                //4.擷取根元素對象下所有的servlet元素的對象
                List<Element> servletInfos = rootElement.elements("servlet");
    
                //5.周遊集合,依次擷取到每一個servlet标簽對象
                for (Element servletInfo : servletInfos) {
                    //servletInfo依次表示每一個servlet标簽對象
    
                    //擷取到servlet下的servlet-name元素對象,并且擷取标簽體内容
                    String servletName = servletInfo.element("servlet-name").getText();
                    //擷取到servlet下的servlet-class元素對象,并且擷取标簽體内容
                    String servletClass = servletInfo.element("servlet-class").getText();
    
                    servletInfoHashMap.put(servletName,servletClass);
                }
    
                //--------------------servlet-mapping--------------------------------------
                //擷取到所有的servlet-mapping标簽
                List<Element> servletMappingInfos = rootElement.elements("servlet-mapping");
                //周遊集合依次得到每一個servlet-mapping标簽
                for (Element servletMappingInfo : servletMappingInfos) {
                    //servletMappingInfo依次表示每一個servlet-mapping标簽
    
                    //擷取servlet-mapping标簽标簽中的servlet-name标簽的标簽體内容
                    String servletName = servletMappingInfo.element("servlet-name").getText();
    
                    //擷取servlet-mapping标簽标簽中的url-pattern标簽的标簽體内容
                    String urlPattern = servletMappingInfo.element("url-pattern").getText();
    
                    //通過servletName來擷取到servlet的全類名
                    String servletClassName = servletInfoHashMap.get(servletName);
    
                    //通過反射來建立這個servlet對象
                    Class clazz = Class.forName(servletClassName);
    
                    //擷取該類所實作的所有的接口資訊,得到的是一個數組
                    Class[] interfaces = clazz.getInterfaces();
    
                    //定義一個boolean類型的變量
                    boolean flag =  false;
                    //周遊數組
                    for (Class clazzInfo : interfaces) {
                        //判斷目前所周遊的接口的位元組碼對象是否和HttpServlet的位元組碼檔案對象相同
                        if(clazzInfo == HttpServlet.class){
    
                            //如果相同,就需要更改flag值.結束循環
                            flag = true;
                            break;
                        }
                    }
    
                    if(flag){
                        //true就表示目前的類已經實作了HttpServlet接口
                        HttpServlet httpServlet = (HttpServlet) clazz.newInstance();
                        //4.将uri和httpServlet添加到map集合中
                        ServletConcurrentHashMap.map.put(urlPattern,httpServlet);
                    }else{
                        //false就表示目前的類還沒有實作HttpServlet接口
                        throw new NotImplementsHttpServletException(clazz.getName() + "Not Implements HttpServlet");
                    }
                }
            } catch (NotImplementsHttpServletException e) {
                e.printStackTrace();
            }catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    
    public class LoaderResourceRunnable implements  Runnable {
        @Override
        public void run() {
    //        //執行parse方法
    //        ParseServletConfig parseServletConfig = new PropertiesParseServletConfig();
    //        parseServletConfig.parse();
    
            ParseServletConfig parseServletConfig = new XMLParseServletConfig();
            parseServletConfig.parse();
    
        }
    }
               

2.枚舉

2.1概述【了解】

為了間接的表示一些固定的值,Java就給我們提供了枚舉

是指将變量的值一一列出來,變量的值隻限于列舉出來的值的範圍内

2.2定義格式【應用】

  • 格式
    public enum s {   
    	枚舉項1,枚舉項2,枚舉項3;
    }
    注意: 定義枚舉類要用關鍵字enum
               
  • 示例代碼
    // 定義一個枚舉類,用來表示春,夏,秋,冬這四個固定值
    public enum Season {
        SPRING,SUMMER,AUTUMN,WINTER;
    }
               

2.3枚舉的特點【了解】

  • 特點
    • 所有枚舉類都是Enum的子類
    • 我們可以通過"枚舉類名.枚舉項名稱"去通路指定的枚舉項
    • 每一個枚舉項其實就是該枚舉的一個對象
    • 枚舉也是一個類,也可以去定義成員變量
    • 枚舉類的第一行上必須是枚舉項,最後一個枚舉項後的分号是可以省略的,但是如果枚舉類有其他的東西,這個分号就不能省略。建議不要省略
    • 枚舉類可以有構造器,但必須是private的,它預設的也是private的。

      枚舉項的用法比較特殊:枚舉("");

    • 枚舉類也可以有抽象方法,但是枚舉項必須重寫該方法
  • 示例代碼
    public enum Season {
    
        SPRING("春"){
    
            //如果枚舉類中有抽象方法
            //那麼在枚舉項中必須要全部重寫
            @Override
            public void show() {
                System.out.println(this.name);
            }
    
        },
    
        SUMMER("夏"){
            @Override
            public void show() {
                System.out.println(this.name);
            }
        },
    
        AUTUMN("秋"){
            @Override
            public void show() {
                System.out.println(this.name);
            }
        },
    
        WINTER("冬"){
            @Override
            public void show() {
                System.out.println(this.name);
            }
        };
    
        public String name;
    
        //空參構造
        //private Season(){}
      
        //有參構造
        private Season(String name){
            this.name = name;
        }
      
        //抽象方法
        public abstract void show();
    }
    
    public class EnumDemo {
        public static void main(String[] args) {
            /*
            1.所有枚舉類都是Enum的子類
            2.我們可以通過"枚舉類名.枚舉項名稱"去通路指定的枚舉項
            3.每一個枚舉項其實就是該枚舉的一個對象
            4.枚舉也是一個類,也可以去定義成員變量
            5.枚舉類的第一行上必須是枚舉項,最後一個枚舉項後的分号是可以省略的,
              但是如果枚舉類有其他的東西,這個分号就不能省略。建議不要省略
            6.枚舉類可以有構造器,但必須是private的,它預設的也是private的。
              枚舉項的用法比較特殊:枚舉("");
            7.枚舉類也可以有抽象方法,但是枚舉項必須重寫該方法
        */
      
            //第二個特點的示範
            //我們可以通過"枚舉類名.枚舉項名稱"去通路指定的枚舉項
            System.out.println(Season.SPRING);
            System.out.println(Season.SUMMER);
            System.out.println(Season.AUTUMN);
            System.out.println(Season.WINTER);
      
            //第三個特點的示範
            //每一個枚舉項其實就是該枚舉的一個對象
            Season spring = Season.SPRING;
        }
    }
               

2.4枚舉的方法【應用】

  • 方法介紹
    方法名 說明
    String name() 擷取枚舉項的名稱
    int ordinal() 傳回枚舉項在枚舉類中的索引值
    int compareTo(E o) 比較兩個枚舉項,傳回的是索引值的內插補點
    String toString() 傳回枚舉常量的名稱
    static T valueOf(Class type,String name) 擷取指定枚舉類中的指定名稱的枚舉值
    values() 獲得所有的枚舉項
  • 示例代碼
    public enum Season {
        SPRING,SUMMER,AUTUMN,WINTER;
    }
    
    public class EnumDemo {
        public static void main(String[] args) {
    //        String name() 擷取枚舉項的名稱
            String name = Season.SPRING.name();
            System.out.println(name);
            System.out.println("-----------------------------");
    
    //        int ordinal() 傳回枚舉項在枚舉類中的索引值
            int index1 = Season.SPRING.ordinal();
            int index2 = Season.SUMMER.ordinal();
            int index3 = Season.AUTUMN.ordinal();
            int index4 = Season.WINTER.ordinal();
            System.out.println(index1);
            System.out.println(index2);
            System.out.println(index3);
            System.out.println(index4);
            System.out.println("-----------------------------");
    
    //        int compareTo(E o) 比較兩個枚舉項,傳回的是索引值的內插補點
            int result = Season.SPRING.compareTo(Season.WINTER);
            System.out.println(result);//-3
            System.out.println("-----------------------------");
    
    //        String toString()   傳回枚舉常量的名稱
            String s = Season.SPRING.toString();
            System.out.println(s);
            System.out.println("-----------------------------");
    
    //        static <T> T valueOf(Class<T> type,String name)
    //        擷取指定枚舉類中的指定名稱的枚舉值
            Season spring = Enum.valueOf(Season.class, "SPRING");
            System.out.println(spring);
            System.out.println(Season.SPRING == spring);
            System.out.println("-----------------------------");
    
    //        values()       獲得所有的枚舉項
            Season[] values = Season.values();
            for (Season value : values) {
                System.out.println(value);
            }
        }
    }
               

3.注解

3.1概述【了解】

  • 概述

    對我們的程式進行标注和解釋

  • 注解和注釋的差別
    • 注釋: 給程式員看的
    • 注解: 給編譯器看的
  • 使用注解進行配置配置的優勢

    代碼更加簡潔,友善

3.2自定義注解【了解】

  • 格式

    public @interface 注解名稱 {

    ​ public 屬性類型 屬性名() default 預設值 ;

    }

  • 屬性類型
    • 基本資料類型
    • String
    • Class
    • 注解
    • 枚舉
    • 以上類型的一維數組
  • 代碼示範
    public @interface Anno2 {
    }
    
    public enum Season {
        SPRING,SUMMER,AUTUMN,WINTER;
    }
    
    public @interface Anno1 {
    
        //定義一個基本類型的屬性
        int a () default 23;
    
        //定義一個String類型的屬性
        public String name() default "itheima";
    
        //定義一個Class類型的屬性
        public Class clazz() default Anno2.class;
    
        //定義一個注解類型的屬性
        public Anno2 anno() default @Anno2;
    
        //定義一個枚舉類型的屬性
        public Season season() default Season.SPRING;
    
        //以上類型的一維數組
        //int數組
        public int[] arr() default {1,2,3,4,5};
    
        //枚舉數組
        public Season[] seasons() default {Season.SPRING,Season.SUMMER};
    
        //value。後期我們在使用注解的時候,如果我們隻需要給注解的value屬性指派。
        //那麼value就可以省略
        public String value();
    
    }
    
    //在使用注解的時候如果注解裡面的屬性沒有指定預設值。
    //那麼我們就需要手動給出注解屬性的設定值。
    //@Anno1(name = "itheima")
    @Anno1("abc")
    public class AnnoDemo {
    }
               
  • 注意

    如果隻有一個屬性需要指派,并且屬性的名稱是value,則value可以省略,直接定義值即可

  • 自定義注解案例
    • 需求

      自定義一個注解@Test,用于指定類的方法上,如果某一個類的方法上使用了該注解,就執行該方法

    • 實作步驟
      1. 自定義一個注解Test,并在類中的某幾個方法上加上注解
      2. 在測試類中,擷取注解所在的類的Class對象
      3. 擷取類中所有的方法對象
      4. 周遊每一個方法對象,判斷是否有對應的注解
    • 代碼實作
      //表示Test這個注解的存活時間
      @Retention(value = RetentionPolicy.RUNTIME)
      public @interface Test {
      }
      
      public class UseTest {
      
          //沒有使用Test注解
          public void show(){
              System.out.println("UseTest....show....");
          }
      
          //使用Test注解
          @Test
          public void method(){
              System.out.println("UseTest....method....");
          }
      
          //沒有使用Test注解
          @Test
          public void function(){
              System.out.println("UseTest....function....");
          }
      }
      
      public class AnnoDemo {
          public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, InvocationTargetException {
              //1.通過反射擷取UseTest類的位元組碼檔案對象
              Class clazz = Class.forName("com.itheima.myanno3.UseTest");
      
              //建立對象
              UseTest useTest = (UseTest) clazz.newInstance();
      
              //2.通過反射擷取這個類裡面所有的方法對象
              Method[] methods = clazz.getDeclaredMethods();
      
              //3.周遊數組,得到每一個方法對象
              for (Method method : methods) {
                  //method依次表示每一個方法對象。
                  //isAnnotationPresent(Class<? extends Annotation> annotationClass)
                  //判斷目前方法上是否有指定的注解。
                  //參數:注解的位元組碼檔案對象
                  //傳回值:布爾結果。  true 存在  false 不存在
                  if(method.isAnnotationPresent(Test.class)){
                      method.invoke(useTest);
                  }
              }
          }
      }
                 

3.3元注解【了解】

  • 概述

    元注解就是描述注解的注解

  • 元注解介紹
    元注解名 說明
    @Target 指定了注解能在哪裡使用
    @Retention 可以了解為保留時間(生命周期)
    @Inherited 表示修飾的自定義注解可以被子類繼承
    @Documented 表示該自定義注解,會出現在API文檔裡面。
  • 示例代碼
    @Target({ElementType.FIELD,ElementType.TYPE,ElementType.METHOD})  //指定注解使用的位置(成員變量,類,方法)
    @Retention(RetentionPolicy.RUNTIME) //指定該注解的存活時間
    //@Inherited //指定該注解可以被繼承
    public @interface Anno {
    }
    
    @Anno
    public class Person {
    }
    
    public class Student extends Person {
        public void show(){
            System.out.println("student.......show..........");
        }
    }
    
    public class StudentDemo {
        public static void main(String[] args) throws ClassNotFoundException {
            //擷取到Student類的位元組碼檔案對象
            Class clazz = Class.forName("com.itheima.myanno4.Student");
    
            //擷取注解。
            boolean result = clazz.isAnnotationPresent(Anno.class);
            System.out.println(result);
        }
    }
    
               

3.4改寫伺服器【了解】

  • 需求

    目前項目中Servlet和url對應關系,是配置在xml檔案中的,将其改為在Servlet類上通過注解配置實作

  • 實作步驟
    1. 定義一個注解(@WebServlet),注解内有一個屬性urlPatterns
    2. 在servlet類上去使用該注解,來指定目前Servlet的通路路徑
    3. 建立一個注解解析類(AnnoParseServletConfig),該類實作ParseServletConfig接口
    4. 實作parse方法
  • 代碼實作
    @Target(ElementType.TYPE) //指定該注解可以使用在類上
    @Retention(RetentionPolicy.RUNTIME)//指定該注解的存活時間 --- 為運作期
    public @interface WebServlet {
    
        //讓使用者去指定某一個Servlet在進行通路的時候所對應的請求uri
        public String urlPatterns();
    }
    
    // 這裡隻給出了LoginServlet的配置,其他Servlet同理
    @WebServlet(urlPatterns = "/servlet/loginservlet")
    public class LoginServlet implements HttpServlet{
        @Override
        public void service(HttpRequest httpRequest, HttpResponse httpResponse) {
           //處理
            System.out.println("LoginServlet處理了登入請求");
    
           //響應
            httpResponse.setContentTpye("text/html;charset=UTF-8");
            httpResponse.write("登入成功");
        }
    }
    
    public class AnnoParseServletConfig implements ParseServletConfig {
    
        //定義一個servlet路徑所對應的常量
        public static final String SERVLET_PATH = "http-dynamic-server\\src\\com\\itheima\\myservlet";
      
        //定義包名
        public static final String SERVLET_PACKAGE_NAME = "com.itheima.myservlet.";
      
        @Override
        public void parse() {
            //擷取類名
    //  1.獲得servlet所在檔案夾的路徑,并封裝成File對象
            File file = new File(SERVLET_PATH);
    //  2.調用listFiles方法,擷取檔案夾下所有的File對象
            File[] servletFiles = file.listFiles();
    //  3.周遊數組,擷取每一個File對象
            for (File servletFile : servletFiles) {
    //  4.擷取File對象的名字(字尾名)
                String servletFileName = servletFile.getName().replace(".java", "");
    //  5.根據包名 + 類名 得到每一個類的全類名
               String servletFullName = SERVLET_PACKAGE_NAME + servletFileName;
                try {
    //  6.通過全類名擷取位元組碼檔案對象
                    Class servletClazz = Class.forName(servletFullName);
                    //  7.判斷該類是否有WebServlet注解
                    if(servletClazz.isAnnotationPresent(WebServlet.class)){
                    //  8.判斷該Servlet類是否實作HttpServlet接口
                        //擷取該類所實作的所有的接口資訊,得到的是一個數組
                        Class[] interfaces = servletClazz.getInterfaces();
      
                        //定義一個boolean類型的變量
                        boolean flag =  false;
                        //周遊數組
                        for (Class clazzInfo : interfaces) {
                            //判斷目前所周遊的接口的位元組碼對象是否和HttpServlet的位元組碼檔案對象相同
                            if(clazzInfo == HttpServlet.class){
                                //如果相同,就需要更改flag值.結束循環
                                flag = true;
                                break;
                            }
                        }
      
                        if(flag){
                            //  9.如果滿足,則擷取注解中的urlPattrens的值,
                            WebServlet annotation = (WebServlet) servletClazz.getAnnotation(WebServlet.class);
                            String uri = annotation.urlPatterns();
      
                            //  10.建立目前Servlet類對象存入值位置
                            HttpServlet httpServlet = (HttpServlet) servletClazz.newInstance();
                            //  11.存入集合的鍵位置
                            ServletConcurrentHashMap.map.put(uri,httpServlet);
                            //
                        }else{
                            //  12.如果不滿足,抛出異常
                            //false就表示目前的類還沒有實作HttpServlet接口
                            throw new NotImplementsHttpServletException(servletClazz.getName() + "Not Implements HttpServlet");
                        }
                    }
                } catch (NotImplementsHttpServletException e) {
                    e.printStackTrace();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
    
            }
        }
    
    public class LoaderResourceRunnable implements  Runnable {
        @Override
        public void run() {
    //        //執行parse方法
    //        ParseServletConfig parseServletConfig = new PropertiesParseServletConfig();
    //        parseServletConfig.parse();
    
    //        ParseServletConfig parseServletConfig = new XMLParseServletConfig();
    //        parseServletConfig.parse();
    
            ParseServletConfig parseServletConfig = new AnnoParseServletConfig();
            parseServletConfig.parse();
      
        }
    }