国产亚洲精品不卡在线,亚洲午夜国产精品无码老牛影视,亚洲av无码成人黄网站在线观看http://m.tkk7.com/sam-chi/愛Java愛生活zh-cnSun, 11 May 2025 10:42:07 GMTSun, 11 May 2025 10:42:07 GMT60Java注解使用的幾個小技巧http://m.tkk7.com/sam-chi/archive/2010/08/02/327746.html遲宏澤遲宏澤Mon, 02 Aug 2010 06:31:00 GMThttp://m.tkk7.com/sam-chi/archive/2010/08/02/327746.htmlhttp://m.tkk7.com/sam-chi/comments/327746.htmlhttp://m.tkk7.com/sam-chi/archive/2010/08/02/327746.html#Feedback0http://m.tkk7.com/sam-chi/comments/commentRss/327746.htmlhttp://m.tkk7.com/sam-chi/services/trackbacks/327746.html

Java注解使用的幾個小技巧:

  最近經常用到注解,總結了幾個注解使用的小技巧,現整理如下:

 一、使用默認的注解參數:

使用default關鍵字可以指定注解的默認參數:

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface SQL {

String sql() default "";

}

如果我們在使用注解@SQL的時候沒有顯式的去指定sql參數,那么就默認采取default關鍵字所指定的值

二、用value指定默認值

我們經常看到很多注解是這種形式,例如:@SQL("select email from user")

這個注解里面的參數為什么沒有帶名稱呢?其實它的注解是這樣定義的:

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface SQL {

String value() default "";

}

三、在注解中使用數組參數

如果你用過Struts2的注解來配置Action,那么你會看到如下形式的注解:

@Results({   

       @Result(name="success",value=xxx

.jsp",type=org.apache.struts2.dispatcher.ServletRedirectResult.class),   

       @Result(name="input",value="/xxx

.jsp",type=org.apache.struts2.dispatcher.ServletRedirectResult.class)   

})   

怎么來創建這種注解呢?

其實可以把@Results的參數看作是一個@Result的數組

定義如下:

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Result {

}

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Results {

Result[] value();   //沒什么特別的,只是接受了一個數組參數而已

}

四、讓注解可以去修飾多個Target類型

我么使用@Target注解來指定某個注解可以修飾的類型,實際上,同上面一樣,@Target接受的是一個數組參數,利用這一特性我們可以讓注解來修飾多個類型。

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

@Target({ElementType.PARAMETER,ElementType.FIELD})

@Retention(RetentionPolicy.RUNTIME)

public @interface Param {

}

OK!這個注解既可以修飾參數也可以修飾類的屬性



遲宏澤 2010-08-02 14:31 發表評論
]]>
使用SimpleTag支持自定義JSP標簽http://m.tkk7.com/sam-chi/archive/2010/08/01/327695.html遲宏澤遲宏澤Sun, 01 Aug 2010 07:10:00 GMThttp://m.tkk7.com/sam-chi/archive/2010/08/01/327695.htmlhttp://m.tkk7.com/sam-chi/comments/327695.htmlhttp://m.tkk7.com/sam-chi/archive/2010/08/01/327695.html#Feedback1http://m.tkk7.com/sam-chi/comments/commentRss/327695.htmlhttp://m.tkk7.com/sam-chi/services/trackbacks/327695.html     最近復習JSP中。我們知道JSP是Java WEB的一個規范。在這個規范之內我們可以自己去做很多事情。JSP API提供了接口允許我們自己去自定義JSP標簽和EL表達式。自定義JSP標簽的大致思想是這樣的,實現一個包含標簽參數和行為邏輯的類,這個類我們稱它為標記處理器類,它實質上是一個Bean,我們設置標簽的屬性實際上是調用它的setter方法。接下來通過使用標記庫描述文件(TLD)來描述標簽的相關信息,以便在JSP頁面中使用taglib指令時能順利的找到它。下面我們來看看詳細應該怎么去做。
    從JSP2.0開始引入了一個簡單標記處理器接口——javax.servlet.jsp.tagext.SimpleTag接口,這個接口取代了原先JSP1.0提供的3個標記處理器接口,我們只需要使用SimpleTarget接口就可以實現所有類型的JSP標記。之所以稱之為簡單,是因為這樣設計讓開發者在編寫程序上省了不少力氣,但是它可以實現很復雜的功能,并不是說它的功能很簡單。
    該接口包含了如下5個方法:
    void doTag();  //該方法包含了標簽執行的業務邏輯
    JspTag getParent();  //獲取該標簽的父標簽
    setJspBody(JspFragment body); //設置JSP標簽體,關于JspFragment類我們稍后再討論
    setJspContext(JspContext ctx);//設置JSP上下文
    setParent(JspTag parent);  //設置父標簽
但是多數情況下我們不需要去親自實現這個接口,因為作為開發者,我們關心的是業務邏輯,也就是doTag()方法的內容,這種情況我們只需要繼承javax.servlet.jsp.tagext.SimpleTagSupport類即可,這個類為我們實現了SimpleTag接口,我們只需要去重寫它的doTag()方法。下面我們來實現一個最簡單的標簽:給標簽傳遞一個參數,讓它在頁面上顯示出來.
首先我們要做的是寫一個標記處理器類:
package test.jsp.tag.simple;

import java.io.IOException;

import javax.servlet.jsp.tagext.SimpleTagSupport;

public class HelloTag extends SimpleTagSupport{
   
    private String name;
   
    public void setName(String name){
        this.name = name;
    }

    @Override
    public void doTag()throws IOException{
        this.getJspContext().getOut().print("Hello! "+name);
    }
}

嗯,這是一個繼承了SimpleTagSupport類的Bean,一樣擁有屬性、setter方法。唯一特別的是重寫了父類的doTag()方法。在這個doTag()中,我們通過獲得一個JSP上下文對象來向頁面輸出一句話:Hello!XXX。

下面是該介紹JspContext對象的時候了,這是一個抽象類,它唯一的子類是PageContext。這么說剛才所返回的實際對象是PageContext類型的。我們可以對其進行強制轉換:PageContext pageCtx = (PageContext)this.getJspContext();

通過PageContext對象我們就可以訪問到Request和Response對象了,如:

HttpServletRequest request = (HttpServletRequest)pageCtx.getRequest();
HttpServletResponse response = (HttpServletResponse)pageCtx.getResponse();

通過這種方式我們就可以在標簽處理器中操作WEB應用各個作用域的數據了。

我們都知道在使用JSP標簽時要在JSP頁面開頭使用taglib指令進行聲明,如:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
taglib指令通過URL來對標簽進行定位。但是它是如何做到的呢?這就要靠TLD了,TLD就是標記庫描述文件(Tag Library Descriptor,TLD),我們看JSTL的JAR包中,META-INF文件夾下每個庫都有一個對應的部署描述文件。TLD實際上是一個XML文件,里面描述了標記庫和其中標記的信息。一個完整的TLD文件結構如下所示:


<taglib xmlns="http://java.sun.com/xml/ns/j2ee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
    version="2.0">
   
  <tlib-version>1.1</tlib-version>
  <short-name>test</short-name>
  <uri>http://test</uri>
 
  <tag>
    <name>hello</name>
    <tag-class>test.jsp.tag.simple.HelloTag</tag-class>
    <body-content>empty</body-content>
    <attribute>
      <name>name</name>
      <required>true</required>
    </attribute>
  </tag>
 
  <tag>
    <name>if</name>
    <tag-class>test.jsp.tag.simple.IfTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
      <name>test</name>
      <rtexprvalue>true</rtexprvalue>
    </attribute>
  </tag>
  <tag>
    <name>foreach</name>
    <tag-class>test.jsp.tag.simple.ForeachTag</tag-class>
    <body-content>scriptless</body-content>
    <attribute>
      <name>items</name>
      <rtexprvalue>true</rtexprvalue>
    </attribute>
    <attribute>
      <name>var</name>
    </attribute>
  </tag>

  <function>
   <description>
      Just for test
   </description>
   <name>add</name>
   <function-class>test.jsp.el.AddEl</function-class>
   <function-signature>int add(int,int)</function-signature>
  </function>
</taglib>

起始標簽是taglib,<tlib-version>定義了taglib的版本號,<short-name>定義了標簽庫的簡稱,<uri>定義了URI標識,taglib就是通過此URI來找到相關的標記庫的。
接下來的<tag>標簽便是定義JSP標簽的屬性了:
以下是必須的屬性
<name>標簽名稱
<tag-class>標記器類
<body-content>動作體類型,JSP2.0支持如下動作體:
empty 空標記
jsp:可以包含標簽、EL和Scriptlet
scriptless:不允許Java腳本內容
tagdependent:對體不進行處理
<attribute>標簽定義了標簽參數。
其中:
<name>標簽指定了參數的名稱。
<required>指定了參數是否是必要的。true是必要,false是不必要
<rtexprvalue>指定了是否允許使用表達式(包括EL表達式和Java表達式),true為允許,false為不允許

<funtion>標簽定義了EL表達式,我們稍后再做介紹。


如何執行動作體?
我們在編寫JSP頁面時經常會用到<c:if>和<c:forEach>之類的標簽
<c:if test="true">
  <p>條件是真的,執行!</p>
</c:if>
只要滿足條件,就會去執行動作體,那么我們怎么在自定義JSP標記中去執行動作體呢?
首先我們先要來研究一個叫做JspFragment的類。JspFragment代表了JSP標簽的動作體,我們通過它的invoke方法就可以執行動作體,下面我們來實現一個類似于<c:if>的標簽:
package test.jsp.tag.simple;

import java.io.IOException;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.JspFragment;
import javax.servlet.jsp.tagext.SimpleTagSupport;

public class IfTag extends SimpleTagSupport{

    private boolean test;
   
    public void setTest(boolean test){
        this.test = test;
    }
   
        @Override
    public void doTag()throws IOException,JspException{
        JspFragment body = getJspBody();
        //如果成立則執行相應邏輯
        if(test){
            body.invoke(null);
        }
    }
}
只要滿足了條件,標簽動作體就會執行。
invoke方法接受一個java.io.Writer對象,使用這個對象將內容輸出到頁面,如果不輸出則可以給它傳遞一個null參數。

JSP中引入了EL表達式給我們的開發帶來了很大的方便,同自定義標簽一樣,允許開發者去自定義EL表達式函數,定義EL表達式函數要比定義標簽簡單多了,我們甚至不需要去實現任何接口,假設我們要實現一個簡單的EL表達式函數來計算兩個數的和,就可以這樣:

package test.jsp.tag.simple;

public class Calculator {

    public static int add(int a,int b){
        return a+b;
    }
   
    public static int minus(int a,int b){
        return a-b;
    }
   
    public static int multiply(int a,int b){
        return a*b;
    }
   
    public static int divide(int a,int b){
        return a/b;
    }
}

這個類中全部是static方法,這是一個工具類。
然后我們只需要在TLD聲明即可:

<function>
   <description>
      Just for test
   </description>
   <name>add</name>
   <function-class>test.jsp.el.AddEl</function-class>
   <function-signature>int add(int,int)</function-signature>
</function>

function-signature類似于C語言中的函數聲明,通過這個找到到底調用類中哪個工具方法。
使用的時候只需要這樣就可以了:${test:add(1,2)}運行時輸出結果為3




遲宏澤 2010-08-01 15:10 發表評論
]]>
戲說Java泛型http://m.tkk7.com/sam-chi/archive/2010/07/31/327644.html遲宏澤遲宏澤Sat, 31 Jul 2010 08:04:00 GMThttp://m.tkk7.com/sam-chi/archive/2010/07/31/327644.htmlhttp://m.tkk7.com/sam-chi/comments/327644.htmlhttp://m.tkk7.com/sam-chi/archive/2010/07/31/327644.html#Feedback0http://m.tkk7.com/sam-chi/comments/commentRss/327644.htmlhttp://m.tkk7.com/sam-chi/services/trackbacks/327644.html戲說Java泛型 
Sun在Java 5之后的版本中引入了泛型技術(Generic).泛型是指具有一個或多個類型參數的類或者是接口.泛型技術其實在C++的STL中早已廣泛使用,在Java中泛型主要是用來構建安全的集合,我們在使用JCF(Java Collections Framework)時經常碰到它們的身影.當然泛型還有很多用處,它可以大大提高程序的可復用性。但是至少有90%的Java程序員都只在構建集合時使用這種技術.在Java中引入泛型技術之前,我們使用集合時,可以向其中加入任何對象,這就造成了很多不安全的因素,例如: 

//in the main() 
          …… 
List intList=new ArrayList(); 

intList.add(new Integer(10)); 
intList.add(new Integer(20)); 
intList.add(new Integer(30)); 
intList.add(new String("Sam")); 

int sum=getSum(intList); 

         …… 


public static int getSum(List intListIn){ 
   Iterator i=intList.iterator();     //獲取迭代器對象 
   int sum=0; 
   while(i.hasNext()){ 
     Integer num=(Integer)i.next();  //將集合中得到的對象強制轉換為Integer,Note:這里最容易出現問題! 
     sum+=num.intValue();            /*進行拆箱操作,當然在Java5之后的版本這個動作可以自動完成,我們這里模擬的是Java1.4,研究泛型我們需要復古~ 
   }                                  *這是一門新的科學,叫做代碼考古學^_^ */ 
   return sum; 


這個程序會編譯成功!并且不會出現警告!但是在運行時會拋出ClassCastException這種運行時異常,String不能通過Integer的instanceof測試,并且我們從集合中取出元素時,因為返回的類型都是Object,我們必須對其進行強制轉換,嗯~這個操作是我最討厭的——不但麻煩,多敲了好幾下鍵盤,而且非常不安全,我不敢確定這個Object是我所希望轉換成的類型,如果真要做這種操作,希望大家都先進行一下instanceof測試,安全第一,受罪第二,不過現在確保安全是為了以后受更少的罪!將來在維護程序時,你甚至可能會因為這個小小的原因而一怒之下產生想重寫整個程序的沖動!嗯~實不相瞞,我就這樣做過~血的教訓! 

但是有了泛型一切都好了起來,我們可以告訴編譯器每個集合中接受哪些對象類型,編譯器會自動為你做轉換工作,這樣以來我們在編譯時就知道是否向集合中插入了類型錯誤的元素. 

List<Integer> intList=new ArrayList<Integer>(); 

現在intList這個集合就只能夠接受Integer類型的對象: 
intList.add(new Integer(12)); 
如果我們向其中加入一個非Integer的對象,那么編譯器將報錯! 


考慮這種情況: 
List<E> list=new ArrayList<E>; 
如果F是E的子類型,list中能添加F類型的對象嗎?當然可以!同數組一樣,子類都可以加入到父類型的集合中,另外對于接口也是如此,比如Bird類和Plane類都實現了一個Flyable的接口,我們想要在一個集合中放置所有"具有飛行能力"的對象,就可以很簡單的這樣做: 
List<Flyable> flyerList=new ArrayList<Flyable>(); 
flyerList.add(new Bird()); 
flyerList.add(new Plane()); 
這樣很和諧,不是嗎?像List<Object>這種形式的集合當然就可以容納天下所有類型的對象了! 

您可能會疑問,List<Object>能夠容納所有的對象,那么它不就與原生態(我們將不帶任何泛型信息的類型成為原生態類型,原生態是一個很時髦的東西,但是在Java中我們要避免它)的List相同了嗎?也就是說: 
List list=new ArrayList(); 
List<Object> objList=new ArayList<Object>(); 
上述這兩行代碼所產生的東西是完全一樣的嗎?其實它們是有差距的,我們通過一個小程序來驗證: 

        public static void main(String[] args){ 
List<String>names=new ArrayList<String>(); 
names.add("Sam"); 
names.add("Jack"); 
names.add("James"); 
names.add("Lucy"); 
sayAllNames(names); 


private static void sayAllNames(List list){               //我們在這里用的是原生態集合參數 
Iterator iterator=list.iterator(); 
while(iterator.hasNext()){ 
System.out.println(iterator.next()); 




程序運行的非常順利!它可以喊出集合中包含的所有名字,同時我們也看到,我們可以將List<String>傳遞給一個接收原生態List的方法.如果你擅長向編譯器"找茬"的話,可能會發現這個地方似乎有一個漏洞,然后你會嘗試寫出類似如下的代碼: 

       public static void main(String[] args){ 
List<String>names=new ArrayList<String>(); 
names.add("Sam"); 
names.add("Jack"); 
names.add("James"); 
names.add("Lucy"); 
addElement(names); 


private static void addElement(List list){ 
list.add(new Integer(10)); 


我們將一個Integer對象插入到一個String類型的集合中.測試一下,程序能成功編譯,但是會產生警告,如果你是在命令行下使用的javac命令進行編譯,就可以看到這條警告:使用了未經檢查或不安全的操作.如果使用現代IDE,例如Eclipse,也會看到用使人很不舒服的黃色曲線標識著list.add(new Integer(10))這條語句.可見編譯器非常不希望我們這樣做!但是之所以能通過編譯,主要是為了保持移植兼容性,與過去的Java代碼保持兼容. 


泛型最初加入到Java中并不受歡迎.Sun在Java中引入泛型技術最大的挑戰就是做到使具有類型安全的泛型類和原來的原生態類能夠協同工作,然而這樣就會如上述代碼所示,引起許多棘手的代碼安全問題,編譯器就只能就這個問題發出警告,提醒程序員最好不要這樣做.這些安全隱患我們總是在程序運行時才能發現,JVM對于泛型這種東西毫無概念!泛型概念對于編譯器而言是嚴格的,編譯器在編譯具有泛型信息的代碼時,會對泛型類型進行驗證,然后執行一個類型擦除過程,也就是從類字節碼中去掉這些信息!當JVM在運行時就看不到所謂的泛型了,這個就是編譯器的"泛型陰謀",我們有必要了解這個事實. 


下面我們將原生態的List換成List<Object>,情況會怎么樣呢? 

         public static void main(String[] args){ 
List<String>names=new ArrayList<String>(); 
names.add("Sam"); 
names.add("Jack"); 
names.add("James"); 
names.add("Lucy"); 
addElement(names); 


private static void addElement(List<Object> list){ 
list.add(new Integer(10)); 



嗯~它會出錯!我們一再強調泛型是安全的,我們不能把一個List<String>傳遞給一個接受List<Object>參數的方法!如果您對Java數組比較熟悉,此時可能會產生疑問,您可能會經常碰見這樣的代碼: 
        
        Object[] objects=new Integer[]{1,2,3,4,5,6}; 

我們可以很正常的將一個子類型的數組賦給一個超類型的數組的引用,但是我們絕對不可以這樣做: 
        List<Object>objList=new ArrayList<String>(); 
編譯器是堅決不會讓你通過的!嗯~你感到泛型不夠人性化是不是?它要是能跟數組一樣就方便了~但是你看一看下面的程序,也許你就不會這么想了,相反,你或許還會認為Java中的數組存在缺陷: 

        public static void main(String[] args){ 
Integer[] intArray=new Integer[]{1,2,3,4,5}; 
changeElement(intArray); 


public static void changeElement(Object[] objects){ 
objects[0]=new String("I Love Java7");       //Hi!問題出在這兒! 

嗯~你是不是發現同上面的某個程序類似?它同樣可以通過編譯,但是我們在運行時發現它會產生一個叫做ArrayStoreException的異常!顧名思義,我們向這個數組當中放入了它所不能接受的東西.這一切的禍根都是源于Java允許我們可以將一個子類型的數組賦給一個超類型的數組的引用~然而使用泛型就不會發生這種情況,編譯器堅決阻止這種情況的存在! 

數組同泛型似乎是水火不相容,數組是具體化的對象,只有在程序運行時才能搞清楚它們的類型,而對于泛型,我們前面說過,它僅僅在編譯的時候才會存在!基于這個原因我們不可以創建具有泛型信息的數組:例如new E[] new List<Object>[] 這些做法都是錯誤的!一定要注意! 


然而有一種神奇的方法能夠將泛型為子類型的集合創遞給泛型為父類型的引用,我們在Windows下查找文件時經常會用到通配符,比如"*.jpg"表示所有JPG類型的文件,在Java中也有一套適用于泛型的通配符,下面是一個運用了泛型通配符的程序: 


import java.util.*; 
public class Test { 

public static void main(String[] args){ 
List<Knight>knights=new ArrayList<Knight>(); 

knights.add(new Knight()); 
knights.add(new Knight()); 
knights.add(new Knight()); 

doAttack(knights); 


public static void doAttack(List<? extends Rpg>rpgs){ 
Iterator<? extends Rpg>iterator=rpgs.iterator(); 
while(iterator.hasNext()){ 
iterator.next().commonAttack();  //這里next()方法返回的是Rpg 





class abstract Rpg{ 
  
        public abstract void commonAttack(); 


class Knight extends Rpg{ 
    
       public void commonAttack(){ 
           System.out.println("The common attack of the knight is very strong!"); 
       } 


class Magician extends Rpg{ 

       public void commonAttack(){ 
            System.out.println("The common attack of the magician is very weak"); 
       } 


我們在上述程序中簡單的構建了幾個游戲的角色類,抽象類Rpg及它的子類Knight(騎士)和Magician(術士),所有的游戲角色都會進行普通攻擊,然而攻擊的能力各不相同,騎士的攻擊強度比較大,而術士的普通攻擊相對要弱一些,他們主要依靠高科技的魔法攻擊~基于這個原則,我們在Rpg的子類中重寫了這個方法.現在我們要做的是讓一群騎士和術士進行戰斗.用doAttack()方法來號召他們戰斗.您或許早就注意了doAttack()的參數很奇怪:List<? extends Rpg> 

這個就是前面我們所說的泛型通配符,<? extends Rpg>表示可以接受泛型類型是Rpg或Rpg子類型的集合,并且,很重要的一點,千萬不要向這些集合中添加任何元素,否則會引起編譯錯誤,原因很簡單,如果允許添加元素的話,很有可能將一個術士插入到一群騎士的隊伍當中!有一個例外,你可以向其中添加null元素 

通配符?后的extends不僅代表著子類也代表的接口的實現,比如<? extends Serializable>表示所有實現泛型類型實現Serializable接口的集合.嗯~我沒寫錯,的確是extends,盡管這是一個接口,記住,沒有<? implements Serializable>這種形式,這就是語法,我們必須遵守 

除了extends,另外還有一個泛型通配符關鍵字super,關于它的作用,請閱讀下面的程序: 


import java.util.*; 
public class Test { 

public static void main(String[] args){ 
List<Knight>knights=new ArrayList<Knight>(); 

knights.add(new Knight()); 
knights.add(new Knight()); 
knights.add(new Knight()); 

List<Rpg>rpgs=new ArrayList<Rpg>(); 

addKnight(rpgs); 



public static void addKnight(List<? super Knight>list){ 
list.add(new Knight()); 





class abstract Rpg{ 
  
        public abstract void commonAttack(); 


class Knight extends Rpg{ 
    
       public void commonAttack(){ 
           System.out.println("The common attack of the knight is very strong!"); 
       } 


class Magician extends Rpg{ 

       public void commonAttack(){ 
            System.out.println("The common attack of the magician is very weak"); 
       } 


你一眼就會注意到,我們終于可以用親愛的add()方法來添加不是null的東西了!這都是super的功勞,List<? super Knight>的意思是凡是泛型類型為Knight和Knight超類的集合都能夠接受,在程序中你可以看到。我們可以將新的騎士加入到騎士的隊伍當中,或者是將騎士加入到混合角色的隊伍當中,不會發生將騎士插入到專業的術士隊伍當中這樣的錯誤,因為編譯器會阻止術士類型的集合傳遞到這個增加騎士的方法中 

然而當我們什么關鍵字都不使用呢?就像這樣List<?> 你認為它等同于List<Object>嗎?那么你錯了,我們前面說過,為了安全,List<Object>只能接受泛型類型為Object類型的集合,而List<?>可以接受泛型類型為任何類型的集合!List<?>和List<? extends Object>是等同的,大家可以自己寫程序測試一下!可以繼續把我的騎士和術士的故事講下去~ 

使用通配符時要注意,通配符只是針對引用聲明使用,使用new生成對象時不可以使用通配符! 
List<? extends Rpg> rpgs=new ArrayList<Knight>();  //這是正確的 
List<? extends Rpg> magicians=new ArrayList<? super Magician>();  //這是錯誤的! 

我們說過,應用泛型可以大大提高程序的可復用性,下面我們將學習如何創建我們自己的泛型類,比上面的要簡單,至少沒有那么多的編譯錯誤和異常,呵呵,可以把心情放松一下,下面的例子,我們構造一個使用泛型的鏈表節點: 

class Node<T>{                               
private T value;                    //節點所包含的值 
private Node<T> nextNode;           //節點所指向的下一個節點 

public Node(T valueIn){ 
value=valueIn; 
nextNode=null; 


public void setValue(T valueIn){ 
value=valueIn; 

public T getValue(){ 
return value; 


public void setNextNode(Node<T> nodeIn){ 
nextNode=nodeIn; 

public Node<T> getNextNode(){ 
return nextNode; 




如你所見,T就是泛型的標識符,然后在類中,我們可以像使用正常類一樣使用泛型標識符,在類定義中可以使用多個泛型標識符: 
class Map<K,V>{ 
   …… 

我們也可以使用通配符來指定泛型所允許的范圍: 
class RpgHolder<T extends Rpg>{       //只允許RPG及其子類 
  …… 


有時候我們不需要使用一個泛型類,我們只需要在普通類中簡單的定義一個支持泛型的方法: 
public  <T extends Rpg> void makeRpgList(T t){ 

   List<T> rpgList=new ArrayList<T>(); 
   rpgList.add(t); 



首先我們要聲明方法的泛型標識符<T extends Rpg>,然后像泛型類那樣在方法中使用泛型 

Java 5出現之后,學習變得越來越困難,泛型技術是主要的困難因素之一,之所以困難主要是因為它要與以前的代碼保持兼容,這就大大的增加了復雜性,您也看到了,前面的那一大堆問題~但是學習泛型技術是很有用的,增加了代碼的可復用性,以及類型安全.本文主要闡述了一些簡單的理論,大家平時要多練習,有很多事可以做,比如可以嘗試用泛型去重新實現一些數據結構,優化一些常用的工具類,你會發現這是件非常有趣的事! 

下面是我自己寫的一個類似List的集合——Tiny,當然比起JCF來在實際應用中性能不是很好,但是包含了基本的集合操作,習慣了JCF,很多數據結構的具體實現都忘得差不多了~得復習了~哈哈~閑著沒事練手~練手~這個是使用一個長度可變的數組來實現的,大家可以嘗試一下用鏈表來實現它的另一個版本LinkedTiny,這樣可以省去變化數組長度的麻煩~ 
/*-------------- Iterator.java--------*/ 
package sam.adt; 

public interface Iterator<T> { 

boolean hasNext(); 
T next(); 


/*--------------- Tiny.java---------*/ 
package sam.adt; 
import java.io.*; 
public interface Tiny<T> extends Serializable{ 
void add(T valueIn);                    //將值添加到集合的尾部 
void remove();                          //刪除集合的最后一個元素 
void removeFirst();                     //刪除集合中的第一個元素 
void addToHead(T valueIn);              //將值添加到集合的頭部 
boolean remove(T valueIn);              //刪除值為valueIn的元素 
boolean add(int indexIn,T valueIn);     //在指定索引處添加值 
boolean remove(int indexIn);            //刪除指定索引處的元素 
T get(int indexIn);                     //得到指定索引處的元素 
int indexOf(T valueIn);                 //獲取指定值的索引 
boolean replace(int indexIn,T valueIn); //將index處的值替換為value 
int size();                             //獲取集合中當前元素數目 
void clear();                           //清除整個集合中的元素 
boolean contain(T valueIn);             //測試集合中是否包含值為valueIn的元素 
Iterator<T> iterator();                 //返回該集合的迭代器對象 


/*-------------- ArrayTiny.java------*/ 
package sam.adt; 

public class ArrayTiny<T> implements Tiny<T>{ 

private static final long serialVersionUID=19891107000000001L; 

private final int INIT_SIZE=10;              //默認初始化數組大小 
private Object[] elements;                   //用來存儲數據的數組 
private int size;                            //集合的邏輯大小 

//適合ArrayTiny的迭代器 
private class ArrayIterator implements Iterator<T>{ 

private int currentPos;    //記錄迭代的位置索引 

public ArrayIterator(){ 
currentPos=0; 


public boolean hasNext() { 
return currentPos<size; 


public T next() { 
T value=(T)elements[currentPos]; 
currentPos++; 
return value; 




public ArrayTiny(){ 
super(); 
elements=new Object[INIT_SIZE]; 
size=0; 


public ArrayTiny(Iterator<T> iterator){ 
this(); 
while(iterator.hasNext()){ 
addArrayLength(); 
this.add(iterator.next()); 
size++; 



//增加內部數組的長度 
private void addArrayLength(){ 
if(size==elements.length){ 
int newSize=size*2; 
Object[] tempArray=new Object[newSize]; 
for(int i=0;i<size;i++){ 
tempArray[i]=elements[i]; 

elements=null; 
System.gc(); 
elements=tempArray; 


//減小內部數組的長度 
private void reduceArrayLength(){ 
if(size<elements.length/4&&size>INIT_SIZE){ 
int newSize=Math.max(size*2,INIT_SIZE); 
Object[] tempArray=new Object[newSize]; 
for(int i=0;i<size;i++){ 
tempArray[i]=elements[i]; 

elements=null; 
System.gc(); 
elements=tempArray; 



public boolean add(int indexIn, T valueIn) { 
if(indexIn>=0&&indexIn<size){ 
addArrayLength(); 
for(int i=size;i>indexIn;i--){ 
elements[i]=elements[i-1]; 

elements[indexIn]=valueIn; 
size++; 

return false; 


public void add(T valueIn) { 
addArrayLength(); 
elements[size]=valueIn; 
size++; 


public void addToHead(T valueIn) { 
add(0,valueIn); 


public void clear() { 
elements=null; 
elements=new Object[INIT_SIZE]; 


public boolean contain(T valueIn) { 
int index=indexOf(valueIn); 
if(index!=-1)return true; 
return false; 


public T get(int indexIn) { 
if(indexIn>=0&&indexIn<size){ 
return (T)elements[indexIn]; 

return null; 


public int indexOf(T valueIn){ 
for(int i=0;i<size;i++){ 
if(elements[i].equals(valueIn))return i; 

return -1; 


public Iterator<T> iterator() { 
return new ArrayIterator(); 


public void remove() { 
elements[size-1]=null; 
size--; 
reduceArrayLength(); 


public boolean remove(int indexIn) { 
if(indexIn>=0&&indexIn<size){ 
for(int i=indexIn;i<size;i++){ 
elements[i]=elements[i+1]; 

size--; 
reduceArrayLength(); 
return true; 

return false; 


public boolean remove(T valueIn) { 
int index=indexOf(valueIn); 
return remove(index); 


public void removeFirst() { 
remove(0); 


public boolean replace(int indexIn, T valueIn) { 
if(indexIn>=0&&indexIn<size){ 
elements[indexIn]=valueIn; 

return false; 


public int size() { 
return size; 





遲宏澤 2010-07-31 16:04 發表評論
]]>
主站蜘蛛池模板: 中文字幕版免费电影网站| 亚洲JLZZJLZZ少妇| 精品一卡2卡三卡4卡免费视频| 亚洲福利在线播放| 羞羞网站在线免费观看| 亚洲成A人片在线观看无码3D| 九九九精品视频免费| 亚洲 国产 图片| eeuss影院ss奇兵免费com| 国产成人精品亚洲精品| 中出五十路免费视频| 亚洲成AV人片在线观看ww| 日本高清不卡aⅴ免费网站| 亚洲高清在线播放| 日本免费一区二区在线观看| 亚洲熟妇色自偷自拍另类| 在线观看免费人成视频色| 亚洲精品乱码久久久久久V| 四虎永久免费影院| 一级美国片免费看| 久久亚洲精品国产精品黑人| 99久久99久久精品免费观看| 久久精品亚洲AV久久久无码| 日本免费无遮挡吸乳视频电影| 免费人成在线观看播放a| 亚洲伊人色欲综合网| 永久看日本大片免费35分钟| 亚洲色图激情文学| 亚洲国产精品不卡毛片a在线| a毛看片免费观看视频| 亚洲avav天堂av在线网爱情| 免费a级毛片无码av| 日本在线免费播放| 亚洲男同gay片| 亚洲中文字幕无码不卡电影| 国产无人区码卡二卡三卡免费 | 成人毛片18岁女人毛片免费看| 在线观看国产一区亚洲bd| 亚洲成av人在线视| 性感美女视频在线观看免费精品| 四虎影视大全免费入口|