第14次文章:網路編程完善+註解
- 2019 年 10 月 8 日
- 筆記
小白這周把網路編程最後的一部分給結束了,然後接觸了註解的內容。開始下一階段的內容學習。fighting!!!
1、XML 不是 HTML 的替代。XML 和 HTML 為不同的目的而設計:
(1)XML 被設計用來傳輸和存儲數據,其焦點是數據的內容。
(2)HTML 被設計用來顯示數據,其焦點是數據的外觀。
2、HTML 旨在顯示資訊,而 XML 旨在傳輸資訊。
3、XML語言的解析:基本的解析方式有兩種
-SAX:SAX是基於事件流的解析,逐句進行解析每一行程式碼,一旦解析之後,就不會再重複解析了,可以適用於大數據程式碼。
-DOM:DOM是基於XML文檔樹結構的解析。將整個程式碼全部都載入進入電腦中,然後需要哪一行就會去解析哪一行。在使用的時候需要使用大量的記憶體,所以適用情況僅限於小數據量的程式碼。
下面用實例解析XML語言:
1、首先我們先創建一個xml文件
<?xml version="1.0" encoding="UTF-8"?> <persons> <person> <name>至尊寶</name> <age>9000</age> </person> <person> <name>紫霞</name> <age>8000</age> </person> </persons>
解析:上述程式碼就是利用XML語言寫的一個小實例,可以看出,XML語言的風格和HTML風格相似,內容屬性都是成對出現的。所有的XML程式碼第一行都是固定的「<?xml version="1.0" encoding="UTF-8"?>」,以「?xml」開頭,然後是對應的版本號,然後是編碼解碼集。
2、然後創建一個Person類
package com.peng.xml; public class Person { private String name; private int age; public Person() { // TODO Auto-generated constructor stub } public Person(String name, int age) { super(); this.name = name; this.age = age; } 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; } }
解析:此處創建一個Person類主要就是便於對xml程式碼塊中person的處理,在xml程式碼中,我們已經自定義了一個person類,並且使用到了類的屬性,name和age。
3、編寫處理器
package com.peng.xml; public class PersonHandler extends DefaultHandler{ private List<Person> persons; private Person person; private String tag;//記錄標籤名 @Override public void startDocument() throws SAXException { // TODO Auto-generated method stub super.startDocument(); System.out.println("處理文檔開始"); persons = new ArrayList<Person>(); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { System.out.println("開始一個元素"+qName); if(null != qName) { tag = qName; } if(null != qName && qName.equals("person")) { person = new Person(); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { super.characters(ch, start, length); String str = new String(ch,start,length); if(null != tag && tag.equals("name")) { person.setName(str); }else if(null != tag && tag.equals("age")) { Integer age = Integer.valueOf(str); person.setAge(age); } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if (qName.equals("person")) { persons.add(person); } tag = null; } @Override public void endDocument() throws SAXException { // TODO Auto-generated method stub super.endDocument(); System.out.println("文檔處理結束"); } public List<Person> getPersons() { return persons; } }
解析:在編寫自己的處理器的時候,首先需要繼承DefaultHandler類別,然後我們主要重寫了5個方法,分別是代表著開始和結束文件及元素的處理,還有一個對字元的處理。
4、此處我們使用SAX解析方式進行解析XML語言,主要是有4步
package com.peng.xml; public class ParseDemo01 { public static void main(String[] args) throws ParserConfigurationException, SAXException, IOException { //1、獲取解析工廠 SAXParserFactory factory = SAXParserFactory.newInstance(); //2、從解析工廠中獲取解析器 SAXParser parse = factory.newSAXParser(); //3、載入文檔Document註冊處理器 //4、編寫處理器 PersonHandler handler = new PersonHandler(); parse.parse(Thread.currentThread().getContextClassLoader(). getResourceAsStream("com/peng/xml/person.xml"),handler); List<Person> persons = handler.getPersons(); for(Person p:persons) { System.out.println(p.getName()+"----->"+p.getAge()); } } }
5、查看結果

通過結果,我們可以明顯的看出SAX解析的特點,按照事件流的結構進行處理,一行一行的逐條執行。
二、Annotation註解
2.1 Annotation的作用
1、不是程式本身,可以對程式做出解釋。(這一點和注釋沒有什麼區別)
2、可以被其他程式讀取(比如編譯器等)。註解資訊處理流程,是註解和注釋的重大區別,如果沒有註解資訊處理流程,則註解毫無意義。
2.2 Annotation的格式
註解是以"@注釋名"在程式碼中存在的,還可以添加一些參數值,例如:@SuppressWarnings(value="unchecked")。
2.3 Annotaion在哪裡使用
可以附加在package,class,method,field等上面,相當於給它們添加額外的輔助資訊,我們可以通過反射機制編程實現對這些元數據的訪問。
下面我們結合幾個常用的註解實例進行解析:
package com.peng.test.annotation; public class Demo01 { @Override //表示重寫父類方法 public String toString() { return ""; } @Deprecated //表示此方法不建議使用,而不是不能使用 public static void test001() { System.out.println("test001"); } @SuppressWarnings("all") //抑制警告 public static void test002() { List list1 = new ArrayList(); List list2 = new ArrayList<>(); } public static void main(String[] args) { Date d = new Date(); test001(); } }
解析:所有的註解都需要通過「@」符號作為開始,上面我們使用到了三個內置註解,分別是@Override,@Deprecated,@SuppressWarnings("all")。
@Override:表示重寫父類方法,當我們在自己的前面加上「@Override」符號的時候,編譯器會自動檢測,在父類中是否存在這樣一個方法名,如果我們的方法名在父類中沒有檢測到,那麼編譯器會自動報出錯誤,提示我們此處有語法錯誤。
@Deprecated:表示此方法不建議使用,而不是不能使用。在隨著jdk不斷的更新,之前的版本有許多不安全或者容易產生異常的方法會慢慢被解決,但是為了保證jdk向下的兼容性,jdk開發人員會對其進行相應的標註,使用@Deprecated註解,可以提示用戶進行相應的舍取。
@SuppressWarnings:表示抑制警告,在其中可以添加一系列的參數,主要的參數如下:

三、自定義註解
1、我們定義一個簡單的註解:
//target主要用於標記此註解的作用範圍 (屬於元註解) @Target(value= {ElementType.METHOD,ElementType.PACKAGE}) //表示保留策略 runtime 表示在運行的時候被讀取 @Retention(RetentionPolicy.RUNTIME) public @interface PengAnnotation { //注意:此處的studentName() 並不是方法,僅僅是一個參數名 String studentName() default ""; int age() default 0; int id() default -1; String[] schoolName() default {"北京大學","清華大學"}; }
解析:自定義註解的語法格式如上所示,基本上也就是一個類,但是開頭是以「@interface」作為開頭,在註解中定義屬性的時候,需要在屬性名後面加一個小括弧,這裡和我們之前在類中定義屬性值有所不同。
在每個註解中,需要在註解頭上添加兩個元註解,「@Target」和「@Retention」。「@Target」:表示自定義註解適用的範圍,可以用在哪裡,比如用於修飾方法、類、屬性等等。「@Retention」:表示保留策略,此處使用的是runtime,表示在運行的時候被讀取。同時,我們在設定屬性值的時候,也可以對其給一個默認值,這樣當我們使用此註解的時候可以根據用戶的需求再進行屬性值的填寫,而不必強行添加。
2、我們使用此註解放在實例中:
package com.peng.test.annotation; public class Demo02 { @PengAnnotation(studentName="peng",age=2,id=3,schoolName= {"UESTC"}) public void test() { ; } }
解析:在此處,我們已經指定了該註解可以用來修飾方法,所以可以將其添加在方法前面。同時,我們在定義註解「@PengAnnotation」的時候,對屬性值添加了默認值,這樣的話,我們在使用的時候,可以對每一個屬性值進行重新定義,也可以使用默認值,否則的話,編譯器將會報錯。
四、利用反射機制讀取註解
在我們未來的工作中,一般是將數據存儲在資料庫中。然而在java程式中,對數據的描述和資料庫中是不同的,此時我們需要將程式中的數據與資料庫中的數據進行對應,一般的規則是:類和表結構進行對應,屬性和欄位進行對應,對象和記錄進行對應。我們使用註解完成類和表結構的映射關係。
例如我們需要將下面的程式碼和表格進行映射對應:
public class PengStudent{ private String studentName; private int age; private int id; }

在存儲的時候,我們需要使用註解來獲取對應在表格中的每一條資訊。
1、建立一個資料庫和java程式的映射的註解
@Target(value= {ElementType.TYPE}) //僅在類上起作用 @Retention(RetentionPolicy.RUNTIME) public @interface PengTable { String value(); }
2、建立另一個註解,用於說明屬性的一些特點
@Target(value= {ElementType.FIELD}) //僅修飾屬性 @Retention(RetentionPolicy.RUNTIME) public @interface PengField { String columnName();//列名 String type();//數據的類型 int length();//數據的長度 }
3、在我們需要存儲的類中,對類以及屬性值都使用註解進行解釋相關的意義。
@PengTable("tb_student") //將「PengStudent」類型與資料庫「tb_student」做映射 public class PengStudent { @PengField(columnName="age",length=3,type="int") private int age; @PengField(columnName="studentName",length=10,type="varvhar") private String studentName; @PengField(columnName="age",length=10,type="int") private int id; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getStudentName() { return studentName; } public void setStudentName(String studentName) { this.studentName = studentName; } public int getId() { return id; } public void setId(int id) { this.id = id; } }
4、編寫一個第三方程式碼來獲取註解中的資訊
/** * 使用反射讀取註解的資訊,模擬處理註解資訊的流程 */ public class Demo03 { public static void main(String[] args) { try { Class clazz = Class.forName("com.peng.test.annotation.PengStudent"); //獲取此類中的所有註解 Annotation[] annotation = clazz.getAnnotations(); for(Annotation a:annotation) { System.out.println(a); } //在所有的註解中,單獨獲取某一個註解 PengTable p = (PengTable) clazz.getAnnotation(PengTable.class); System.out.println(p.value()); //獲得類的屬性的註解 Field f = clazz.getDeclaredField("studentName");//獲取屬性studengName的註解 PengField pengField = f.getAnnotation(PengField.class); System.out.println(pengField.columnName()+"---"+pengField.type()+"---"+pengField.length()); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
解析:上述程式碼Demo03使用反射讀取註解的資訊,模擬處理註解資訊的流程,當我們模擬完上述流程之後,就可以獲取得到每個註解中的資訊。然後根據獲得的表名、欄位的資訊,拼出DDL語句,然後,使用JDBC執行這個SQL,在資料庫中生成相關的表。
五、對註解的總結
經過上面的講述,大家應該可以對註解有一個初步的映像了,註解與注釋最大區別並不在於解釋說明部分。注釋只能提供給開發者自己進行閱讀,提高程式碼的可讀性,而註解除了提供給開發人員閱讀之外,最大的優勢就在於可以提供給第三方軟體進行閱讀,使得電腦可以提取出註解中的資訊,便於資訊在不同程式之間的傳遞。所以說,在使用註解的時候,如果沒有註解的資訊處理流程,那麼註解將會與注釋毫無區別,同時,註解也將會失去其存在的意義。