<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    2010年1月4日

    (轉貼)數據庫連接(內連接,外連接,交叉連接)

    數據庫連接分為:內連接,外連接(左、右連接,全連接),交叉連接
    文章地址 : http://www.zxbc.cn/html/20080527/51189.html
    轉載 
    內連接:把兩個表中數據對應的數據查出來 
    外連接:以某個表為基礎把對應數據查出來(全連接是以多個表為基礎) 
    student表 
    no name 
    1     a 
    2     b 
    3     c 
    4     d 
    grade表 
    no grade 
    1     90 
    2     98 
    3     95 
    內連接 inner join(查找條件中對應的數據,no4沒有數據不列出來) 
    語法:select * from student inner join grade on student.no = grade.no 
    結果 
    student.no name grade.no grade 
    1             a             1         90 
    2             b             2         98 
    3             c             3         95 
    左連接(左表中所有數據,右表中對應數據) 
    語法:select * from student left join grade on student.no = grade.no 
    結果: 
    student.no name grade.no grade 
    1                 a         1         90 
    2                 b         2         98 
    3                 c         3         95 
    4                 d     
    右連接(右表中所有數據,左表中對應數據) 
    語法:select * from student right join grade on student.no = grade.no 
    結果: 
    student.no name grade.no grade 
    1                 a         1         90 
    2                 b         2         98 
    3                 c         3         95 
    全連接 
    語法:select * from student full join grade on student.no = grade.no 
    結果: 
    no name grade 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 
    1     a     90 
    2     b     98 
    3     c     95 
    注:access 中不能直接使用full join ,需要使用union all 將左連接和右連接合并后才可以

    交叉連接
    將兩個表所有行組合,連接后的行數為兩個表行數的乘積(笛卡爾積)
    語法,借用上面的例子應該是
    select * from student cross join grade

    行數應該為12行 :
    no name grade 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d  
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 
    1     a     90 
    2     b     98 
    3     c     95 
    4     d 

    posted @ 2011-11-30 17:24 AK47 閱讀(490) | 評論 (0)編輯 收藏

    JAXB向Xml非根節點添加一個或多個屬性

    JAXB 向Xml非根節點添加一個或多個屬性,直接上代碼,關于JAXB的相關注解可查閱JAVA API。

    原創文章,轉載請注明出處。http://www.tkk7.com/kangdy/archive/2011/11/23/364635.html

    code1: colors類  根節點
    code1
    package com.kangdy.test;

    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlElement;
    import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement(name = "Colors")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Colors {
        
        @XmlElement(name = "red",nillable=true)
        private Red red;
        
        @XmlElement(name = "blue",nillable=true)
        private Blue blue;

        public Red getRed() {
            return red;
        }

        public Blue getBlue() {
            return blue;
        }

        public void setRed(Red red) {
            this.red = red;
        }

        public void setBlue(Blue blue) {
            this.blue = blue;
        }
    }

    code2:  Red類  子節點
    code2package com.kangdy.test;

    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement(name = "red")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Red {
        
        private String value;
        
        @XmlAttribute(name = "att1")
        private String att;
        
        public String getValue() {
            return value;
        }
        
        public void setValue(String value) {
            this.value = value;
        }

        public String getAtt() {
            return att;
        }

        public void setAtt(String att) {
            this.att = att;
        }
        
    }


    code3:  類 Blue 子節點
    code3
    package com.kangdy.test;

    import javax.xml.bind.annotation.XmlAccessType;
    import javax.xml.bind.annotation.XmlAccessorType;
    import javax.xml.bind.annotation.XmlAttribute;
    import javax.xml.bind.annotation.XmlRootElement;

    @XmlRootElement(name = "blue")
    @XmlAccessorType(XmlAccessType.FIELD)
    public class Blue {
        private String value;
        
        @XmlAttribute(name = "att2")
        private String att2;
        
        @XmlAttribute(name = "att1")
        private String att;
        
        public String getAtt() {
            return att;
        }

        public void setAtt(String att) {
            this.att = att;
        }

        public String getValue() {
            return value;
        }

        public void setValue(String value) {
            this.value = value;
        }

        public String getAtt2() {
            return att2;
        }

        public void setAtt2(String att2) {
            this.att2 = att2;
        }
    }

    code4: main類
    code4
    package com.kangdy.test;

    import java.io.StringWriter;

    import javax.xml.bind.JAXBContext;
    import javax.xml.bind.Marshaller;

    public class Jaxbtest {
        public static void main(String[] args) throws Exception {

            StringWriter writer = new StringWriter();
            JAXBContext jc = JAXBContext.newInstance(Colors.class);
            Marshaller ma = jc.createMarshaller();
            ma.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            
            Colors colors = new Colors();
            Red red = new Red();
            red.setAtt("att-red");
            red.setValue("red");
            Blue blue = new Blue();
            blue.setValue("blue");
            blue.setAtt("att-blue");
            blue.setAtt2("blue-att2");
            colors.setRed(red);
            colors.setBlue(blue);
            
            ma.marshal(colors, writer);
            System.out.println(writer.toString());

        }
    }

    運行結果:
    結果
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
    <Colors>
        <red att1="att-red">
            <value>red</value>
        </red>
        <blue att1="att-blue" att2="blue-att2">
            <value>blue</value>
        </blue>
    </Colors>

    posted @ 2011-11-23 14:33 AK47 閱讀(10126) | 評論 (4)編輯 收藏

    (轉載)關于paramsPrepareParamsStack

    原帖地址:
    http://hi.baidu.com/%CC%AB%C6%BD%D1%F31986/blog/item/110b13b1384e805e08230259.html
    轉貼

    paramsPrepareParamsStack在Struts 2.0中是一個很奇妙的interceptor stack,以至于很多人疑問為何不將其設置為默認的interceptor stack。paramsPrepareParamsStack主要解決了ModelDriven和Preparable的配合問題,從字面上理解來說, 這個stack的攔截器調用的順序為:首先params,然后prepare,接下來modelDriven,最后再params。Struts 2.0的設計上要求modelDriven在params之前調用,而業務中prepare要負責準備model,準備model又需要參數,這就需要在 prepare之前運行params攔截器設置相關參數,這個也就是創建paramsPrepareParamsStack的原因。流程如下:
       1. params攔截器首先給action中的相關參數賦值,如id  
       2. prepare攔截器執行prepare方法,prepare方法中會根據參數,如id,去調用業務邏輯,設置model對象
       3. modelDriven攔截器將model對象壓入value stack,這里的model對象就是在prepare中創建的
       4. params攔截器再將參數賦值給model對象
       5. action的業務邏輯執行 依據此stack,一個action的代碼通常如下

    public class UserAction extends ActionSupport implements ModelDriven, Preparable {
        private User user;
        private int id;
        private UserService service; // user business service

        public void setId(int id) {
            this.id = id;
        }

        /**
         * create a new user if none exists, otherwise load the user with the
         * specified id
         */
        public void prepare() throws Exception {
            if (id == 0) {
                user = new User();
            } else {
                user = service.findUserById(id);
            }
        }

        public Object getModel() {
            return user;
        }

        /**
         * create or update the user and then view the created user
         */
        public String update() {
            if (id == 0) {
                service.create(user);
            } else {
                service.update(user);
            }
            return "redirect";
        }

        /**
         * delete the user and go to a default home page
         */
        public String delete() {
            service.deleteById(id);
            return "home";
        }

        /**
         * show the page allowing the user to view the existing data
         */
        public String view() {
            return "view";
        }

        /**
         * show the page allowing the user to view the existing data and change the
         * values
         */
        public String edit() {
            return "input";
        }

    在上述代碼中,edit和view都不需要根據id再為界面準備數據,因為prepare方法已經準備好了model,這些方法很簡單。對于update 方法,prepare首先會從數據庫中加載數據,然后params攔截器會將參數值付給model,在update直接更新就可以,不會出現數據被亂更新 的情況。象Hibernate框架,會判斷哪些字段更新了,然后進行更新,性能也不會損失。
    通過paramsPrepareParamsStack可以讓流程更明確,代碼更簡潔,也更利于大家的交流。

    posted @ 2011-11-16 15:39 AK47 閱讀(441) | 評論 (0)編輯 收藏

    (轉載) Struts 2雜談(1):ValueStack對象的傳送帶機制

    Struts 2雜談(1):ValueStack對象的傳送帶機
    作者:nokiaguy  原文地址:http://blog.csdn.net/nokiaguy/article/details/4684750
    轉貼
       眾所周知,Strut 2的Action類通過屬性可以獲得所有相關的值,如請求參數、Action配置參數、向其他Action傳遞屬性值(通過chain結果)等等。要獲得 這些參數值,我們要做的唯一一件事就是在Action類中聲明與參數同名的屬性,在Struts 2調用Action類的Action方法(默認是execute方法)之前,就會為相應的Action屬性賦值。
        要完成這個功能,有很大程度上,Struts 2要依賴于ValueStack對象。這個對象貫穿整個Action的生命周期(每個Action類的對象實例會擁有一個ValueStack對象)。當 Struts 2接收到一個.action的請求后,會先建立Action類的對象實例,并且將Action類的對象實例壓入ValueStack對象中(實際 上,ValueStack對于相當一個棧),而ValueStack類的setValue和findValue方法可以設置和獲得Action對象的屬性 值。Struts 2中的某些攔截器正是通過ValueStack類的setValue方法來修改Action類的屬性值的。如params攔截器用于將請求參數值映射到相 應成Action類的屬性值。在params攔截器中在獲得請求參數值后,會使用setValue方法設置相應的Action類的屬性。
        從這一點可以看出,ValueStack對象就象一個傳送帶,當客戶端請求.action時,Struts 2在創建相應用Action對象后就將Action對象放到了ValueStack傳送帶上,然后ValueStack傳送帶會帶著Action對象經過 若干攔截器,在每一攔截器中都可以通過ValueStack對象設置和獲得Action對象中的屬性值。實際上,這些攔截器就相當于流水線作業。如果要對 Action對象進行某項加工,再加一個攔截器即可,當不需要進行這項工作時,直接將該攔截器去掉即可。
        下面我們使用一個例子來演示這個過程。在這個例子中實現了一個攔截器,該攔截器的功能是將一個屬性文件中的key-value對映射成相應的屬性的值。如下面是一個屬性文件的內容:

        name = 超人
        price = 10000

        我們可以在Action類中定義name和price屬性,在Action中引用這個攔截器后,就會自動為屬性賦值。
        在使用該攔截器有如下規則:
        1.  攔截器讀取的屬性文件路徑由path參數指定。
        2.  屬性文件的編碼格式由encoding參數指定,默認值是UTF-8。
        3.  如果某個key中包含有“.”(該符號不能出現在標識符中),則有如下處理方法:
        (1)將Action類的屬性名定義為去掉“.”的key。例如,key為person.name,而屬性名可定義為personname。
        (2)將Action類的屬性名定義為將“.”替換成其他字符的表示符號。例如,key為person.name,而屬性名可定義為person_name,其中“_”由separator參數指定。
        4.  如果key太長,也可以直接使用Action參數進行映射,例如,key為country.person.name,可做如下映射:
          <param name="countrypersonname">name</param>
          要注意的是,name屬性值不能包含“.”,因此,應將key值中的“.”去掉。現在就可以直接在Action類中定義名為name的屬性的,name屬性的值會與key值相同。
        5.  上面所有的規則可以同時使用。

    攔截器的源代碼:

    package interceptors;

    import java.util.Enumeration;
    import java.util.Map;
    import java.util.Properties;
    import java.io.InputStream;
    import java.io.FileInputStream;
    import com.opensymphony.xwork2.ActionContext;
    import com.opensymphony.xwork2.ActionInvocation;
    import com.opensymphony.xwork2.config.entities.ActionConfig;
    import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
    import com.opensymphony.xwork2.util.ValueStack;

    public class PropertyInterceptor extends AbstractInterceptor
    {
        
    private static final String DEFAULT_PATH_KEY = "path";
        
    private static final String DEFAULT_ENCODING_KEY = "encoding";
        
    private static final String DEFAULT_SEPARATOR_KEY = "separator";

        
    protected String pathKey = DEFAULT_PATH_KEY;
        
    protected String encodingKey = DEFAULT_ENCODING_KEY;
        
    protected String separatorKey = DEFAULT_SEPARATOR_KEY;

        
    public void setPathKey(String pathKey) 
        {
            
    this.pathKey = pathKey;
        }

        
    public void setEncodingKey(String encodingKey)
        {
            
    this.encodingKey = encodingKey;
        }

        
    public void setSeparatorKey(String separatorKey)
        {
            
    this.separatorKey = separatorKey;
        }

        @Override
        
    public String intercept(ActionInvocation invocation) throws Exception
        {
            ActionConfig config 
    = invocation.getProxy().getConfig();

            Map
    <String, String> parameters = config.getParams();
            
    if (parameters.containsKey(pathKey))
            {
                String path 
    = parameters.get(pathKey);
                String encoding 
    = parameters.get(encodingKey);
                String separator 
    = parameters.get(separatorKey);
                
    if (encoding == null)
                    encoding 
    = "UTF-8";
                
    if (separator == null)
                    separator 
    = "";
                path 
    = invocation.getAction().getClass().getResource(path)
                        .getPath();
                Properties properties 
    = new Properties();
                InputStream is 
    = new FileInputStream(path);
                java.io.Reader reader 
    = new java.io.InputStreamReader(is, encoding);
                
                properties.load(reader);
                ActionContext ac 
    = invocation.getInvocationContext();
                ValueStack stack 
    = ac.getValueStack();
                System.out.println(stack.hashCode());
                Enumeration names 
    = properties.propertyNames();
                
    while (names.hasMoreElements())
                {
                    
    //  下面會使用setValue方法修改ValueStack對象中的相應屬性值
                    String name = names.nextElement().toString();
                    
    if (!name.contains("."))
                        stack.setValue(name, properties.get(name)); 

                    String newName 
    = null;
                    newName 
    = parameters.get(name.replaceAll("//."""));
                    
    if (newName != null)
                        stack.setValue(newName, properties.get(name));

                    
    if (!separator.equals(""))
                    {
                        newName 
    = name.replaceAll("//.""");
                        stack.setValue(newName, properties.get(name));
                    }               
                    newName 
    = name.replaceAll("//.", separator);
                    stack.setValue(newName, properties.get(name));
                } 
            }
            
    return invocation.invoke();
        }
    }

    用于測試的Action類的源代碼:

    package actions;

    public class MyAction
    {
        
    private String name;
        
    private Integer price;
        
    private String log4jappenderstdout;
        
    private String log4j_rootLogger;
        
    private String conversionPattern;

        
    public String getName()
        {
            
    return name;
        }

        
    public void setName(String name)
        {
            
    this.name = name;
        }

        
    public Integer getPrice()
        {
            
    return price;
        }

        
    public void setPrice(Integer price)
        {
            
    this.price = price;
        }

        
    public String getLog4jappenderstdout()
        {
            
    return log4jappenderstdout;
        }

        
    public void setLog4jappenderstdout(String log4jappenderstdout)
        {
            
    this.log4jappenderstdout = log4jappenderstdout;
        }

        
    public String getLog4j_rootLogger()
        {
            
    return log4j_rootLogger;
        }

        
    public void setLog4j_rootLogger(String log4j_rootLogger)
        {
            
    this.log4j_rootLogger = log4j_rootLogger;
        }

        
    public String getConversionPattern()
        {
            
    return conversionPattern;
        }

        
    public void setConversionPattern(String conversionPattern)
        {
            
    this.conversionPattern = conversionPattern;
        }

        
    public String execute()
        {
            System.out.println(
    "name:" + name);
            System.out.println(
    "price:" + price);
            System.out.println(
    "log4jappenderstdout:" + log4jappenderstdout);
            System.out.println(
    "log4j_rootLogger:" + log4j_rootLogger);
            System.out.println(
    "conversionPattern:" + conversionPattern);
            
    return null;
        }
    }

    Action類的配置代碼如:

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE struts PUBLIC
        "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN"
        "http://struts.apache.org/dtds/struts-2.1.dtd"
    >
    <struts>
        
    <package name="struts" extends="struts-default">

            
    <interceptors>
                
    <interceptor name="property"
                    class
    ="interceptors.PropertyInterceptor" />
                
    <interceptor-stack name="myStack">
                    
    <interceptor-ref name="defaultStack" />
                    
    <interceptor-ref name="property" />
                
    </interceptor-stack>
            
    </interceptors>
            
    <action name="test" class="actions.MyAction">
                
    <interceptor-ref name="myStack" />
                
    <param name="path">/log4j.properties</param>
                
    <param name="encoding">UTF-8</param>
                
    <param name="separator">_</param>
                
    <param name="log4jappenderstdoutlayoutConversionPattern">
                    conversionPattern
                
    </param>

            
    </action>
        
    </package>
    </struts>

      請將log4j.properties文件復制到WEB-INF/classes目錄,并在該文件中加入name和price屬性。

    測試結果:

    name:中國
    price:
    34
    log4jappenderstdout:org.apache.log4j.ConsoleAppender
    log4j_rootLogger:error
    , stdout
    conversionPattern:%d{ABSOLUTE} %5p %c{
    1}:%L - %m%n

        由于property攔截器在defaultStack后引用,因此,在該攔截器中設置的屬性值是最終結果,如果將property攔截器放在 defaultStack前面(將兩個<interceptor-ref>元素掉換一下),就可以通過同名勝Action配置參數或請求參數 來干預最終究輸出結果了。

    posted @ 2011-11-11 17:21 AK47 閱讀(373) | 評論 (0)編輯 收藏

    (轉貼)Struts2數據傳輸的背后機制:ValueStack(值棧)

         摘要: (轉)Struts2數據傳輸的背后機制:ValueStack(值棧)原文地址 :http://blog.csdn.net/li_tengfei/article/details/6098134轉載 1.     數據傳輸背后機制:ValueStack(值棧)   在這一切的背后,是因為有了ValueStack(值棧)!   Valu...  閱讀全文

    posted @ 2011-11-11 16:19 AK47 閱讀(818) | 評論 (0)編輯 收藏

    structs2配置UrlRewriteFilter

    轉載每個網頁或請求都是一個url地址,一般,這個地址可能是.do,.page,.action之類的并加上'?'號、'&'號查詢串等構成的一個長長的的url。很urgly。

    一般的url----------------------------------------------------------較好的url
    http://www.xxx.net/user/profile.do?id=20001   ====> http://www.xxx.net/user/20001
    http://www.xxx.net/forum/board.do?name=java   ====> http://www.xxx.net/forum/java
    http://www.xxx.net/forum/thread.do?id=29923   ====> http://www.xxx.net/thread/29923

    后者明顯較為直觀和漂亮。

    使用url rewrite可以很好的改善這個狀況。網站url rewrite應用是非常廣泛的,良好的url設計給用戶帶來的非常好的體驗,同時也能吸引搜索引擎的注意。
    原文地址:http://www.iteye.com/topic/53834
    使用方式:
    1 配置web.xml文件
    樣例:
        <listener>
            <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <filter>
            <filter-name>encodingFilter</filter-name>
            <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
            <init-param>
                <param-name>encoding</param-name>
                <param-value>UTF-8</param-value>
            </init-param>
        </filter>
        <filter-mapping>
            <filter-name>encodingFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <filter>
            <filter-name>osivFilter</filter-name>
            <filter-class>
                org.springframework.orm.hibernate3.support.OpenSessionInViewFilter</filter-class>
        </filter>
        <listener>
            <listener-class>
                org.springframework.web.context.request.RequestContextListener</listener-class>
        </listener>
        <filter-mapping>
            <filter-name>osivFilter</filter-name>
            <url-pattern>/*</url-pattern>
        </filter-mapping>
        <!--配置UrlRewriteFilter過濾器-->
        <filter>
            <filter-name>UrlRewriteFilter</filter-name>
            <filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>UrlRewriteFilter</filter-name>
            <url-pattern>*.html</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
            <dispatcher>INCLUDE</dispatcher>
        </filter-mapping>
        <filter>
            <filter-name>struts-prepare</filter-name>
            <filter-class>
                org.apache.struts2.dispatcher.ng.filter.StrutsPrepareFilter</filter-class>
            <init-param>
                <param-name>actionPackages</param-name>
                <param-value>com.secneo.action.*.*</param-value>
            </init-param>
        </filter>
        <filter>
            <filter-name>struts2</filter-name>
            <filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class>
        </filter>

        <filter>
            <filter-name>struts-execute</filter-name>
            <filter-class>
                org.apache.struts2.dispatcher.ng.filter.StrutsExecuteFilter</filter-class>
        </filter>
        <filter>
            <filter-name>struts-cleanup</filter-name>
            <filter-class>org.apache.struts2.dispatcher.ActionContextCleanUp</filter-class>
        </filter>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <!--在structs2中使用UrlRewriteFilter過濾器-->
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.action</url-pattern>
            <dispatcher>REQUEST</dispatcher>
            <dispatcher>FORWARD</dispatcher>
            <dispatcher>INCLUDE</dispatcher>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts2</filter-name>
            <url-pattern>*.tag</url-pattern>
        </filter-mapping>

        <filter-mapping>
            <filter-name>struts-prepare</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-prepare</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-prepare</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>

        <filter-mapping>
            <filter-name>struts-execute</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-execute</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-execute</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>

        <filter-mapping>
            <filter-name>struts-cleanup</filter-name>
            <url-pattern>*.jsp</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-cleanup</filter-name>
            <url-pattern>*.action</url-pattern>
        </filter-mapping>
        <filter-mapping>
            <filter-name>struts-cleanup</filter-name>
            <url-pattern>*.tld</url-pattern>
        </filter-mapping>
        <listener>
            <listener-class>
                org.springframework.web.util.IntrospectorCleanupListener</listener-class>
        </listener>
    2  在WEB-INF目錄下添加urlrewrite.xml 文件,根據具體需要寫規則
    樣例:
    <?xml version="1.0" encoding="utf-8"?>
    <urlrewrite>
        <rule>
            <from>^/(.*).html$</from>
            <to type="forward">/$1.action</to>
        </rule>
        <rule>
            <from>^/(.*).html?(.*)$</from>
            <to type="forward">/$1.action?$2</to>
        </rule>
    </urlrewrite>

    posted @ 2011-11-09 17:22 AK47 閱讀(1776) | 評論 (0)編輯 收藏

    structs2 filter的執行順序

    根據servlet2.3規范filter執行是按照web.xml配置的filter-mapping先后順序進行執行。
    所以自己配置的過濾器放在structs2的過濾器之前。

    posted @ 2011-11-09 15:44 AK47 閱讀(375) | 評論 (0)編輯 收藏

    structs2攔截器

    深入struct2攔截器  這篇文章很好,細致講解了structs2和攔截器的原理。
    http://zhanghong.iteye.com/blog/452465
    轉載在每次對你的 Action的 execute()方法請求時,系統會生成一個 ActionInvocation對象,這個對象保存了 action和你所配置的所有的攔截器以及一些狀態信息。比如你的應用使用的是 defaultStack,系統將會以攔截器棧配置的順序將每個攔截器包裝成一個個 InterceptorMapping(包含攔截器名字和對應的攔截器對象 )組成一個 Iterator保存在 ActionInvocation中。在執行 ActionInvocation的 invoke()方法時會對這個 Iterator進行迭代,每次取出一個 InterceptorMapping,然后執行對應 Interceptor的 intercept(ActionInVocation inv)方法,而 intercept(ActionInInvocation inv)方法又包含當前的 ActionInInvcation對象作為參數,而在每個攔截器中又會調用 inv的 invoke()方法,這樣就會進入下一個攔截器執行了,這樣直到最后一個攔截器執行完,然后執行 Action的 execute()方法 (假設你沒有配置訪問方法,默認執行 Action的 execute()方法 )。在執行完 execute()方法取得了 result后又以相反的順序走出攔截器棧,這時可以做些清理工作。最后系統得到了一個 result,然后根據 result的類型做進一步操作。

    配置攔截器:Struts2中提供了大量的攔截器,多個攔截器可以組成一個攔截器棧,系統配置了一個默認的攔截器棧 defaultStack,具體包括那些攔截器以及順序可以在struts-default.xml中找到。
    1)
    <package name="default" extends="struts-default">
       <interceptors>
           <interceptor name="timer" class=".."/>
           <interceptor name="logger" class=".."/>
       </interceptors>

       <action name="login"
          class="tutorial.Login">
            <interceptor-ref name="timer"/>
            <interceptor-ref name="logger"/>
             <result name="input">login.jsp</result>
             <result name="success"
                type="redirectAction">/secure/home</result>
       </action>
    </package>

    2)
    <package name="default" extends="struts-default">
       <interceptors>
            <interceptor name="timer" class=".."/>
            <interceptor name="logger" class=".."/>
            <interceptor-stack name="myStack">
               <interceptor-ref name="timer"/>
               <interceptor-ref name="logger"/>
           <interceptor-ref name="defaultStack"/>    
            </interceptor-stack>
        </interceptors>

    <action name="login"
         class="tutuorial.Login">
             <interceptor-ref name="myStack"/>
             <result name="input">login.jsp</result>
             <result name="success"
                 type="redirectAction">/secure/home</result>
    </action>
    </package>

    攔截器執行順序:
    <interceptor-stack name="xaStack">
      <interceptor-ref name="thisWillRunFirstInterceptor"/>
      <interceptor-ref name="thisWillRunNextInterceptor"/>
      <interceptor-ref name="followedByThisInterceptor"/>
      <interceptor-ref name="thisWillRunLastInterceptor"/>
    </interceptor-stack>

    執行順序:
    thisWillRunFirstInterceptor
      thisWillRunNextInterceptor
        followedByThisInterceptor
          thisWillRunLastInterceptor
            MyAction1
            MyAction2 (chain)
            MyPreResultListener
            MyResult (result)
          thisWillRunLastInterceptor
        followedByThisInterceptor
      thisWillRunNextInterceptor
    thisWillRunFirstInterceptor


    自定義攔截器:必須實現 com.opensymphony.xwork2.interceptor.Interceptor 也可以繼承 AbstractInterceptor

    攔截器要保證線程安全。因為structs2中攔截器會在請求間共享

    posted @ 2011-11-08 18:35 AK47 閱讀(1443) | 評論 (0)編輯 收藏

    (轉貼)struts2 工作原理圖

         摘要: 原貼地址:http://blog.csdn.net/qjyong/article/details/1795833轉貼 最近學習struts2,其實它就是webwork2.2的升級版,現附上原理圖 上圖來源于Struts2官方站點,是Struts 2 的整體結構。一個請求在Struts2框架中的處理大概分為以下幾個步驟1 客戶端初始化一個指向Servlet容器(例如Tomcat)的請求2 ...  閱讀全文

    posted @ 2011-11-08 15:10 AK47 閱讀(1636) | 評論 (0)編輯 收藏

    重新認識Java finally

    關于java finally 網上有2篇文章個人認為相當不錯
    以下是轉貼內容:

    1 . JAVA finally字句的異常丟失和返回值覆蓋解析
    原帖地址 :
    http://blog.csdn.net/sureyonder/article/details/5560538
    轉貼
    Java虛擬機在每個try語句塊和與其相關的catch子句的結尾 處都會“調用”finally子句的子例程。實際上,finally子句在方法內部的表現很象“微型子例程”。finally子句正常結束后-指的是finally子句中最后一條語句正常執行完畢,不包括拋出異常,或執行return、continue、break等情況,隸屬于這個finally子句的微型子例程執行“返回”操作。程序在第一次調用微型子例程的地方繼續執行后面的語句。

    finally“微型子例程”不等同于方法函數的調用,finally子句都是在同一個棧內執行的,微型子例程的“返回”操作也不會涉及到方法退棧,僅僅是使程序計數器pc跳轉到同一個方法的一個不同的位置繼續執行。
    一 異常丟失
        public static void exceptionLost()  
         {  
           try  
           {  
             try  
             {  
               throw new Exception( "exception in try" );  
             }  
             finally  
             {  
               throw new Exception( "exception in finally" );  
             }  
           }  
           catch( Exception e )  
           {  
             System.out.println( e );  
           }  
         }  

    exceptionLost()的輸出結果是“exception in finally”,而不是try塊中拋出的異常,這是JAVA異常機制的一個瑕疵-異常丟失。

    在字節碼中,throw語句不是原子性操作。在較老的JDK中,exceptionLost()中try塊的throw語句分解為幾步操作:
    1) 把Exception("exception in try")對象引用存儲到一個局部變量中
      astore_2  // pop the reference to the thrown exception, store into local variable 2
    2) 調用finally微型子程序
    3) 把局部變量中的Exception("exception in try")對象引用push到操作數棧頂,然后拋出異常
      aload_2  // push the reference to the thrown exception from local variable 2

      athrow   // throw the exception

    如果finally通過break、return、continue,或者拋出異常而退出,那么上面的第3步就不會執行。

    在JDK1.6中,通過字節碼我們可以看到,finally子句作為一種特殊的catch來實現的,下面是exceptionLost()方法的異常表:

    Exception table:
      from   to   target  type
       0     10    10     any
     0     21    21     Class java/lang/Exception

    finally可以捕獲從0行到9行之間拋出的任何類型(any)的異常,并重新拋出捕獲的異常,或者拋出一個自己構造的新異常,這個新異常就會覆蓋try語句塊中的異常。
    二 返回值覆蓋

        public static int getValue()  
         {  
           int value = 0;  
             
           try  
           {  
             value = 100;  
               
             return value;  
           }  
           finally  
           {  
             value = 200;  
           }  
         }  

    這個方法的返回值是100還是200?結果是100。
    在字節碼中,return語句不是原子性操作,它會把getValue()中的return語句分解為幾步操作:
    1) 把value值存儲到一個局部變量(這里命名為temp)中:
       iload_0   // push local variable 0 - the 100
       istore_2   //  pop an int (the 100), store into local varaible 2
    2) 調用finally微型子程序
    3) 把局部變量(指temp)的值push到操作數棧頂,然后返回到調用方法
         iload_2  // push local varaible 2 - the 100
       ireturn      // return int on top of the stack - the 100: return 100

    由于return語句在返回之前會把返回值保存到一個臨時的局部變量中,所以在finally子句內對value重新賦值不會影響返回值。

    了解finally子句內在的一些知識,我們能夠了解finally能夠做什么和不能夠做什么,這樣會幫助我們正確使用finally子句。

    2 . 關于 Java 中 finally 語句塊的深度辨析
    原帖地址 :
    http://www.ibm.com/developerworks/cn/java/j-lo-finally/index.html?ca=drs-
    轉貼
    關于 Java 虛擬機是如何編譯 finally 語句塊的問題,有興趣的讀者可以參考《 The JavaTM Virtual Machine Specification, Second Edition 》中 7.13 節 Compiling finally。那里詳細介紹了 Java 虛擬機是如何編譯 finally 語句塊。實際上,Java 虛擬機會把 finally 語句塊作為 subroutine(對于這個 subroutine 不知該如何翻譯為好,干脆就不翻譯了,免得產生歧義和誤解。)直接插入到 try 語句塊或者 catch 語句塊的控制轉移語句之前。但是,還有另外一個不可忽視的因素,那就是在執行 subroutine(也就是 finally 語句塊)之前,try 或者 catch 語句塊會保留其返回值到本地變量表(Local Variable Table)中。待 subroutine 執行完畢之后,再恢復保留的返回值到操作數棧中,然后通過 return 或者 throw 語句將其返回給該方法的調用者(invoker)。請注意,前文中我們曾經提到過 return、throw 和 break、continue 的區別,對于這條規則(保留返回值),只適用于 return 和 throw 語句,不適用于 break 和 continue 語句,因為它們根本就沒有返回值。

    posted @ 2011-11-01 16:56 AK47 閱讀(832) | 評論 (0)編輯 收藏

    (轉貼) jqGrid整理

    原帖地址:
    http://www.cnblogs.com/mycoding/archive/2011/07/07/2099878.html

    一、 jqGrid的加載。

    1.引用相關頭文件

    引入CSS:

    <link href="Scripts/jquery-ui-1.8.1.custom.css" rel="stylesheet" type="text/css" />

    <link href="Scripts/ui.jqgrid.css" rel="stylesheet" type="text/css" />

    引入JS:

    <script src="Scripts/jquery-1.5.1.js" type="text/javascript"></script>

    <script src="Scripts/jquery-ui.min.js" type="text/javascript"></script>

    <script src="Scripts/grid.locale-en.js" type="text/javascript"></script>

    <script src="Scripts/jquery.jqGrid.min.js" type="text/javascript"></script>

    因為jqGrid3.6及以后的版本集成了jQuery UI,所以,此處需要導入UI相關js和css。另外grid.locale-en.js這個語言文件必須在jquery.jqGrid.min.js之前加載,否則會出問題。

    2.將jqgrid加入頁面中

    根據jqGrid的文檔,要想生成一個jqGrid,最直接的方法就是:

    $("#list").jqGrid(options);

    其中list是頁面上的一個table:<table id="list"></table>

    下面是一個簡單的例子:

    <script type="text/javascript">
     
    $(document).ready(function () {
     
    jQuery("#list").jqGrid({
     
    url: 'Handler.ashx',
     
    datatype: "json",
     
    mtype: 'GET',
     
    colNames: ['SalesReasonID', 'Name', 'ReasonType', 'ModifiedDate'],
     
    colModel: [
     
    { name: 'SalesReasonID', index: 'SalesReasonID', width: 40, align: "left", editable: true },
     
    { name: 'Name', index: 'Name', width: 100, align: "center" },
     
    { name: 'ReasonType', index: 'ReasonType', width: 100, align: "center" },
     
    { name: 'ModifiedDate', index: 'ModifiedDate', width: 150, align: "center", search: false }
     
    ],
     
    rowList: [10, 20, 30],
     
    sortname: 'SalesReasonID',
     
    viewrecords: true,
     
    sortorder: "desc",
     
    jsonReader: {
     
    root: "griddata",
     
    total: "totalpages",
     
    page: "currpage",
     
    records: "totalrecords",
     
    repeatitems: false
     
    },
     
    pager: jQuery('#pager'),
     
    rowNum: 5,
     
    altclass: 'altRowsColour',
     
    //width: 'auto',
     
    width: '500',
     
    height: 'auto',
     
    caption: "DemoGrid"
     
    }).navGrid('#pager', { add: true, edit: true, del: true,search:false,refresh:false }); ;
     
    })

    二、 jqgrid的重要選項

    具體的options參考,可以訪問jqGrid文檔關于option的章節(http://www.trirand.com/jqgridwiki/doku.php?id=wiki:options)。其中有幾個是比較常用的,重點介紹一下:

    • url :jqGrid控件通過這個參數得到需要顯示的數據,具體的返回值可以使XML也可以是Json。
    • datatype :這個參數用于設定將要得到的數據類型。類型包括:json 、xml、xmlstring、local、javascript、function。
    • mtype : 定義使用哪種方法發起請求,GET或者POST。
    • height :Grid的高度,可以接受數字、%值、auto,默認值為150。
    • width :Grid的寬度,如果未設置,則寬度應為所有列寬的之和;如果設置了寬度,則每列的寬度將會根據shrinkToFit選項的設置,進行設置。
    • shrinkToFit :此選項用于根據width計算每列寬度的算法。默認值為true。如果shrinkToFit為true且設置了width值,則每列寬度會根據 width成比例縮放;如果shrinkToFit為false且設置了width值,則每列的寬度不會成比例縮放,而是保持原有設置,而Grid將會有 水平滾動條。
    • autowidth :默認值為false。如果設為true,則Grid的寬度會根據父容器的寬度自動重算。重算僅發生在Grid初始化的階段;如果當父容器尺寸變化了,同時也需要變化Grid的尺寸的話,則需要在自己的代碼中調用setGridWidth方法來完成。
    • pager :定義頁碼控制條Page Bar,在上面的例子中是用一個div(<div id=”pager”></div>)來放置的。
    • sortname :指定默認的排序列,可以是列名也可以是數字。此參數會在被傳遞到Server端。
    • viewrecords :設置是否在Pager Bar顯示所有記錄的總數。
    • caption :設置Grid表格的標題,如果未設置,則標題區域不顯示。
    • rowNum :用于設置Grid中一次顯示的行數,默認值為20。正是這個選項將參數rows(prmNames中設置的)通過url選項設置的鏈接傳遞到Server。注意如果Server返回的數據行數超過了rowNum的設定,則Grid也只顯示rowNum設定的行數。
    • rowList :一個數組,用于設置Grid可以接受的rowNum值。例如[10,20,30]。
    • colNames :字符串數組,用于指定各列的題頭文本,與列的順序是對應的。
    • colModel :最重要的數組之一,用于設定各列的參數。(稍后詳述)
    • prmNames :這是一個數組,用于設置jqGrid將要向Server傳遞的參數名稱。(稍后詳述)
    • jsonReader :這又是一個數組,用來設定如何解析從Server端發回來的json數據。(稍后詳述)

    2.1 prmNames選項

    prmNames是jqGrid的一個重要選項,用于設置jqGrid將要向Server傳遞的參數名稱。其默認值為:

    prmNames : {

    page:"page", // 表示請求頁碼的參數名稱

    rows:"rows", // 表示請求行數的參數名稱

    sort: "sidx", // 表示用于排序的列名的參數名稱

    order: "sord", // 表示采用的排序方式的參數名稱

    search:"_search", // 表示是否是搜索請求的參數名稱

    nd:"nd", // 表示已經發送請求的次數的參數名稱

    id:"id", // 表示當在編輯數據模塊中發送數據時,使用的id的名稱

    oper:"oper", // operation參數名稱

    editoper:"edit", // 當在edit模式中提交數據時,操作的名稱

    addoper:"add", // 當在add模式中提交數據時,操作的名稱

    deloper:"del", // 當在delete模式中提交數據時,操作的名稱

    subgridid:"id", // 當點擊以載入數據到子表時,傳遞的數據名稱

    npage: null,

    totalrows:"totalrows" // 表示需從Server得到總共多少行數據的參數名稱,參見jqGrid選項中的rowTotal

    }

    2.2 jsonReader選項

    jsonReader是jqGrid的一個重要選項,用于設置如何解析從Server端發回來的json數據,如果Server返回的是xml數據,則對應的使用xmlReader來解析。jsonReader的默認值為:

    jsonReader : {

    root: "rows", // json中代表實際模型數據的入口

    page: "page", // json中代表當前頁碼的數據

    total: "total", // json中代表頁碼總數的數據

    records: "records", // json中代表數據行總數的數據

    repeatitems: true, // 如果設為false,則jqGrid在解析json時,會根據name來搜索對應的數據元素(即可以json中元素可以不按順序);而所使用的name是來自于colModel中的name設定。

    cell: "cell",

    id: "id",

    userdata: "userdata",

    subgrid: {

    root:"rows",

    repeatitems: true,

    cell:"cell"

    }

    }

    假如有下面一個json字符串:

    {"totalpages":"3","currpage":"1","totalrecords":"11","griddata": [{"SalesReasonID":"1","Name":"Price","ReasonType":"Other","ModifiedDate":"1998 年6月1日"},{"SalesReasonID":"2","Name":"On Promotion","ReasonType":"Promotion","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"3","Name":"Magazine Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"4","Name":"Television Advertisement","ReasonType":"Marketing","ModifiedDate":"1998年6月1日"}, {"SalesReasonID":"5","Name":"Manufacturer","ReasonType":"Other","ModifiedDate":"1998 年6月1日"}]}

    其對應的jsonReader為:jsonReader: {

    root: "griddata",

    total: "totalpages",

    page: "currpage",

    records: "totalrecords",

    repeatitems: false

    }

    注:cell、id在repeatitems為true時可以用到,即每一個記錄是由一對id和cell組合而成,即可以適用另一種json結構。援引文檔中的例子:

    repeatitems為true時:

    jQuery("#gridid").jqGrid({  

         ...  

         jsonReader : {  

             root:"invdata",  

             page: "currpage",  

             total: "totalpages",  

             records: "totalrecords"

         },  

         ...  

    });  

    json結構為:

    {   

    "totalpages": "xxx",   

    "currpage": "yyy",  

    "totalrecords": "zzz",  

    "invdata" : [  

                      {"id" :"1", "cell" :["cell11", "cell12", "cell13"]},   // cell中不需要各列的name,只要值就OK了,但是需要保持對應

                      {"id" :"2", "cell" :["cell21", "cell22", "cell23"]},  

                      ...  

         ]  

    }  

    repeatitems為false時:

    jQuery("#gridid").jqGrid({  

         ...  

         jsonReader : {  

             root:"invdata",  

             page: "currpage",  

             total: "totalpages",  

             records: "totalrecords",  

             repeatitems: false,  

             id: "0"

         },  

         ...  

    });  

    json結構為:

    {   

    "totalpages" : "xxx",   

    "currpage" : "yyy",  

    "totalrecords" : "zzz",  

    "invdata" : [  

                     {"invid" : "1","invdate":"cell11", "amount" :"cell12", "tax" :"cell13", "total" :"1234", "note" :"somenote"}, // 數據中需要各列的name,但是可以不按列的順序

                      {"invid" : "2","invdate":"cell21", "amount" :"cell22", "tax" :"cell23", "total" :"2345", "note" :"some note"},  

                      ...  

         ]  

    }  

    2.3 colModel的重要選項

    colModel也有許多非常重要的選項,在使用搜索、排序等方面都會用到。這里先只說說最基本的。

    • name :為Grid中的每個列設置唯一的名稱,這是一個必需選項,其中保留字包括subgrid、cb、rn。
    • index :設置排序時所使用的索引名稱,這個index名稱會作為sidx參數(prmNames中設置的)傳遞到Server。
    • label :當jqGrid的colNames選項數組為空時,為各列指定題頭。如果colNames和此項都為空時,則name選項值會成為題頭。
    • width :設置列的寬度,目前只能接受以px為單位的數值,默認為150。
    • sortable :設置該列是否可以排序,默認為true。
    • search :設置該列是否可以被列為搜索條件,默認為true。
    • resizable :設置列是否可以變更尺寸,默認為true。
    • hidden :設置此列初始化時是否為隱藏狀態,默認為false。
    • formatter :預設類型或用來格式化該列的自定義函數名。常用預設格式有:integer、date、currency、number等(具體參見文檔 )。

    三、 注意事項

    1. 動態改變Add Form或者Edit Form中的select的內容,如:改變下圖中的Comparator下拉中的內容。

    clip_image002

    $("#list_d").navGrid('#pager_d',{add:true,edit:true,del:true,search:false,refresh:false},

    {

    checkOnSubmit:false, closeAfterEdit: true,recreateForm:true,

    beforeInitData:function(formid){

    initComparator();

    },

    beforeShowForm: function(formid){

    $("#list_d").jqGrid('setColProp', 'Name', { editrules:{required:false},});

    $('#tr_Name', formid).hide();

    }

    },//edit

    {},//add

    {}//del

    beforeInitData, beforeShowForm在每次點擊編輯的時候都會執行。initComparator的作用是通過ajax獲取數據,然后利 用$("#list_d").jqGrid('setColProp', 'Comparator', { editoptions: { value: valueString} });來設置Comparator下拉中的內容。其中valueString的格式如下’ equal to: equal to; not equal to: not equal to’。鍵值之間用冒號隔開,2項之間用分號隔開。注意:把recreateForm設為true,否則'setColProp'只在第一次調用時有效。

    2. var rowNum = parseInt($(this).getGridParam("records"), 10); 得到數據條數。

    3. jQuery("#list_d").clearGridData();清空數據。

    4. jQuery("#list").getCell(ids,"Key");獲取第ids行的key列。

    5. $("#list").jqGrid('setSelection', "1");選中第一行。放在loadComplete:中在gird加載完成的時候自動選中第一行。 loadComplete:function(data){$("#list").jqGrid('setSelection', "1");

    }

    6. 對于像1中的可編輯的字段,可以設定rule,參見http://www.trirand.com/jqgridwiki/doku.php?id=wiki:common_rules#editrules

    7. 修改Option,以URL為例

    jQuery("#list_d").jqGrid('setGridParam',{url:"xxx.aspx",page:1}).trigger('reloadGrid');


    復雜的表格可以參考jquery grid demo網站 :




    posted @ 2011-11-01 14:23 AK47 閱讀(2321) | 評論 (0)編輯 收藏

    (轉載)Spring 注解@Component,@Service,@Controller,@Repository

    Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個擁有特殊語義的注釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個注釋和 @Component 是等效的,但是從注釋類的命名上,很容易看出這 3 個注釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個注釋和 @Component 相比沒有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應用程序采用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋。

    在 一個稍大的項目中,通常會有上百個組件,如果這些組件采用xml的bean定義來配置,顯然會增加配置文件的體積,查找以及維護起來也不太方便。 Spring2.5為我們引入了組件自動掃描機制,他可以在類路徑底下尋找標注了 @Component,@Service,@Controller,@Repository注解的類,并把這些類納入進spring容器中管理。它的作用 和在xml文件中使用bean節點配置組件時一樣的。要使用自動掃描機制,我們需要打開以下配置信息: 
    Java代碼

    1. <?xml version="1.0" encoding="UTF-8" ?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans   http://www.springframework.org/schema/beans/spring-beans-2.5.xsd   http://www.springframework.org/schema/context   http://www.springframework.org/schema/context/spring-context-2.5.xsd"  
    2. >  
    3.   
    4. <context:component-scan base-package=”com.eric.spring”>   
    5. </beans>   
       /*其中base-package為需要掃描的包(含所有子包)

         @Service用于標注業務層組件,

         @Controller用于標注控制層組件(如struts中的action),

         @Repository用于標注數據訪問組件,即DAO組件,

         @Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。

        */   


    6. @Service public class VentorServiceImpl implements iVentorService {   
    7. } @Repository public class VentorDaoImpl implements iVentorDao {  
    8. }

    /*getBean的默認名稱是類名(頭字母小 寫),如果想自定義,可以@Service(“aaaaa”)這樣來指定,這種bean默認是單例的,如果想改變,可以使用 @Service(“beanName”) @Scope(“prototype”)來改變。可以使用以下方式指定初始化方法和銷毀方法(方法名任意): @PostConstruct public void init() {  

    */
    9. }  
    10. @PreDestroy public void destory() {  
    11. } 

    注入方式:

    把 DAO實現類注入到service實現類中,把service的接口(注意不要是service的實現類)注入到action中,注入時不要new 這個注入的類,因為spring會自動注入,如果手動再new的話會出現錯誤,然后屬性加上@Autowired后不需要getter()和 setter()方法,Spring也會自動注入。至于更具體的內容,等對注入的方式更加熟練后會做個完整的例子上來。

    注解:

    在 spring的配置文件里面只需要加上<context:annotation-config/> 和<context:component-scan base-package="需要實現注入的類所在包"/>,可以使用base-package="*"表示全部的類。   

    <context:component-scan base-package=”com.eric.spring”> 

    其中base-package為需要掃描的包(含所有子包)

    在接口前面標上@Autowired和@Qualifier注釋使得接口可以被容器注入,當接口存在兩個實現類的時候必須指定其中一個來注入,使用實現類首字母小寫的字符串來注入,如:

    1.     @Autowired     
    2.   
    3.     @Qualifier("chinese")      
    4.   
    5.     private Man man;   

    否則可以省略,只寫@Autowired   。 

    @Service服務層組件,用于標注業務層組件,表示定義一個bean,自動根據bean的類名實例化一個首寫字母為小寫的bean,例如Chinese實例化為chinese,如果需要自己改名字則:@Service("你自己改的bean名")。   

    @Controller用于標注控制層組件(如struts中的action)

    @Repository持久層組件,用于標注數據訪問組件,即DAO組件

    @Component泛指組件,當組件不好歸類的時候,我們可以使用這個注解進行標注。 


    @Service 
    public class VentorServiceImpl implements iVentorService { 
    }

    @Repository 
    public class VentorDaoImpl implements iVentorDao { 


    getBean 的默認名稱是類名(頭字母小寫),如果想自定義,可以@Service(“aaaaa”) 這樣來指定,這種

    bean默認是單例的,如果想改變,可以使用@Service(“beanName”) @Scope(“prototype”)來改變。

    可以使用以下方式指定初始化方法和銷毀方法(方法名任意):

    @PostConstruct

    public void init() { 



    @PreDestroy

    public void destory() { 

    }

    posted @ 2011-10-10 16:46 AK47 閱讀(49714) | 評論 (3)編輯 收藏

    (轉貼)使用 Spring 2.5 注釋驅動的 IoC 功能

    原帖地址
    http://www.ibm.com/developerworks/cn/java/j-lo-spring25-ioc/

    概述

    注釋配置相對于 XML 配置具有很多的優勢:

    • 它可以充分利用 Java 的反射機制獲取類結構信息,這些信息可以有效減少配置的工作。如使用 JPA 注釋配置 ORM 映射時,我們就不需要指定 PO 的屬性名、類型等信息,如果關系表字段和 PO 屬性名、類型都一致,您甚至無需編寫任務屬性映射信息——因為這些信息都可以通過 Java 反射機制獲取。
    • 注釋和 Java 代碼位于一個文件中,而 XML 配置采用獨立的配置文件,大多數配置信息在程序開發完成后都不會調整,如果配置信息和 Java 代碼放在一起,有助于增強程序的內聚性。而采用獨立的 XML 配置文件,程序員在編寫一個功能時,往往需要在程序文件和配置文件中不停切換,這種思維上的不連貫會降低開發效率。

    因此在很多情況下,注釋配置比 XML 配置更受歡迎,注釋配置有進一步流行的趨勢。Spring 2.5 的一大增強就是引入了很多注釋類,現在您已經可以使用注釋配置完成大部分 XML 配置的功能。在這篇文章里,我們將向您講述使用注釋進行 Bean 定義和依賴注入的內容。

     
    原來我們是怎么做的      
    在使用注釋配置之前,先來回顧一下傳統上是如何配置 Bean 并完成 Bean 之間依賴關系的建立。下面是 3 個類,它們分別是 Office、Car 和 Boss,這 3 個類需要在 Spring 容器中配置為 Bean:    
       
    Office 僅有一個屬性:    
         
    清單 1. Office.java    
                        
    package com.baobaotao;    
    public class Office {    
        private String officeNo =”001”;    
       
        //省略 get/setter    
       
        @Override   
        public String toString() {    
            return "officeNo:" + officeNo;    
        }    
    }    
           
    Car 擁有兩個屬性:    
         
    清單 2. Car.java 
                         
    package com.baobaotao;    
       
    public class Car {    
        private String brand;    
        private double price;    
       
        // 省略 get/setter    
       
        @Override   
        public String toString() {    
            return "brand:" + brand + "," + "price:" + price;    
        }    
    }    
          
    Boss 擁有 Office 和 Car 類型的兩個屬性:    
      
    清單 3. Boss.java    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
       
        // 省略 get/setter    
       
        @Override   
        public String toString() {    
            return "car:" + car + "\n" + "office:" + office;    
        }    
    }    
        
    我們在 Spring 容器中將 Office 和 Car 聲明為 Bean,并注入到 Boss Bean 中:下面是使用傳統 XML 完成這個工作的配置文件 beans.xml:    
        
    清單 4. beans.xml 將以上三個類配置成 Bean    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">    
        <bean id="boss" class="com.baobaotao.Boss">    
            <property name="car" ref="car"/>    
            <property name="office" ref="office" />    
        </bean>    
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="002"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
    當我們運行以下代碼時,控制臺將正確打出 boss 的信息:    
      
    清單 5. 測試類:AnnoIoCTest.java    
                        
    import org.springframework.context.ApplicationContext;    
    import org.springframework.context.support.ClassPathXmlApplicationContext;    
    public class AnnoIoCTest {    
       
        public static void main(String[] args) {    
            String[] locations = {"beans.xml"};    
            ApplicationContext ctx =     
                new ClassPathXmlApplicationContext(locations);    
            Boss boss = (Boss) ctx.getBean("boss");    
            System.out.println(boss);    
        }    
    }    
        
    這說明 Spring 容器已經正確完成了 Bean 創建和裝配的工作。    
         
    使用 @Autowired 注釋    
       
    Spring 2.5 引入了 @Autowired 注釋,它可以對類成員變量、方法及構造函數進行標注,完成自動裝配的工作。來看一下使用 @Autowired 進行成員變量自動注入的代碼:    
      
    清單 6. 使用 @Autowired 注釋的 Boss.java    
                        
    package com.baobaotao;    
    import org.springframework.beans.factory.annotation.Autowired;    
       
    public class Boss {    
       
        @Autowired   
        private Car car;    
       
        @Autowired   
        private Office office;    
       
        …    
    }    
           
    Spring 通過一個 BeanPostProcessor 對 @Autowired 進行解析,所以要讓 @Autowired 起作用必須事先在 Spring 容器中聲明 AutowiredAnnotationBeanPostProcessor Bean。   

    清單 7. 讓 @Autowired 注釋工作起來    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">    
       
        <!-- 該 BeanPostProcessor 將自動起作用,對標注 @Autowired 的 Bean 進行自動注入 -->    
        <bean class="AutowiredAnnotationBeanPostProcessor  
            org.springframework.beans.factory.annotation.  "/>    
       
        <!-- 移除 boss Bean 的屬性注入配置的信息 -->    
        <bean id="boss" class="com.baobaotao.Boss"/>    
         
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="001"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
        
    這 樣,當 Spring 容器啟動時,AutowiredAnnotationBeanPostProcessor 將掃描 Spring 容器中所有 Bean,當發現 Bean 中擁有 @Autowired 注釋時就找到和其匹配(默認按類型匹配)的 Bean,并注入到對應的地方中去。    
       
    按 照上面的配置,Spring 將直接采用 Java 反射機制對 Boss 中的 car 和 office 這兩個私有成員變量進行自動注入。所以對成員變量使用 @Autowired 后,您大可將它們的 setter 方法(setCar() 和 setOffice())從 Boss 中刪除。    
       
    當然,您也可以通過 @Autowired 對方法或構造函數進行標注,來看下面的代碼:    
        
    清單 8. 將 @Autowired 注釋標注在 Setter 方法上    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
       
         @Autowired   
        public void setCar(Car car) {    
            this.car = car;    
        }    
         
        @Autowired   
        public void setOffice(Office office) {    
            this.office = office;    
        }    
        …    
    }    
         
    這時,@Autowired 將查找被標注的方法的入參類型的 Bean,并調用方法自動注入這些 Bean。而下面的使用方法則對構造函數進行標注:    
        
    清單 9. 將 @Autowired 注釋標注在構造函數上    
                        
    package com.baobaotao;    
       
    public class Boss {    
        private Car car;    
        private Office office;    
         
        @Autowired   
        public Boss(Car car ,Office office){    
            this.car = car;    
            this.office = office ;    
        }    
         
        …    
    }    
           
    由于 Boss() 構造函數有兩個入參,分別是 car 和 office,@Autowired 將分別尋找和它們類型匹配的 Bean,將它們作為 Boss(Car car ,Office office) 的入參來創建 Boss Bean。    
         
    當候選 Bean 數目不為 1 時的應對方法    
       
    在 默認情況下使用 @Autowired 注釋進行自動注入時,Spring 容器中匹配的候選 Bean 數目必須有且僅有一個。當找不到一個匹配的 Bean 時,Spring 容器將拋出 BeanCreationException 異常,并指出必須至少擁有一個匹配的 Bean。我們可以來做一個實驗:    
       
       
    清單 10. 候選 Bean 數目為 0 時    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
         xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd ">    
         
        <bean class="AutowiredAnnotationBeanPostProcessor  
            org.springframework.beans.factory.annotation.  "/>     
       
        <bean id="boss" class="com.baobaotao.Boss"/>    
       
        <!-- 將 office Bean 注釋掉 -->    
        <!-- <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
        </bean>-->    
       
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
         
    由于 office Bean 被注釋掉了,所以 Spring 容器中將沒有類型為 Office 的 Bean 了,而 Boss 的 office 屬性標注了 @Autowired,當啟動 Spring 容器時,異常就產生了。    
       
    當 不能確定 Spring 容器中一定擁有某個類的 Bean 時,可以在需要自動注入該類 Bean 的地方可以使用 @Autowired(required = false),這等于告訴 Spring:在找不到匹配 Bean 時也不報錯。來看一下具體的例子:    
       
       
    清單 11. 使用 @Autowired(required = false)    
                        
    package com.baobaotao;    
       
    import org.springframework.beans.factory.annotation.Autowired;    
    import org.springframework.beans.factory.annotation.Required;    
       
    public class Boss {    
       
        private Car car;    
        private Office office;    
       
        @Autowired   
        public void setCar(Car car) {    
            this.car = car;    
        }    
        @Autowired(required = false)    
        public void setOffice(Office office) {    
            this.office = office;    
        }    
        …    
    }    
        
    當 然,一般情況下,使用 @Autowired 的地方都是需要注入 Bean 的,使用了自動注入而又允許不注入的情況一般僅會在開發期或測試期碰到(如為了快速啟動 Spring 容器,僅引入一些模塊的 Spring 配置文件),所以 @Autowired(required = false) 會很少用到。    
       
    和找不到一個類型匹配 Bean 相反的一個錯誤是:如果 Spring 容器中擁有多個候選 Bean,Spring 容器在啟動時也會拋出 BeanCreationException 異常。來看下面的例子:    
        
    清單 12. 在 beans.xml 中配置兩個 Office 類型的 Bean    
                        
    …     
    <bean id="office" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
    </bean>    
    <bean id="office2" class="com.baobaotao.Office">    
        <property name="officeNo" value="001"/>    
    </bean>    
    …    
         
    我們在 Spring 容器中配置了兩個類型為 Office 類型的 Bean,當對 Boss 的 office 成員變量進行自動注入時,Spring 容器將無法確定到底要用哪一個 Bean,因此異常發生了。    
       
    Spring 允許我們通過 @Qualifier 注釋指定注入 Bean 的名稱,這樣歧義就消除了,可以通過下面的方法解決異常:    
      
    清單 13. 使用 @Qualifier 注釋指定注入 Bean 的名稱    
                        
    @Autowired   
    public void setOffice(@Qualifier("office")Office office) {    
        this.office = office;    
    }    
        
     
    @Qualifier("office") 中的 office 是 Bean 的名稱,所以 @Autowired 和 @Qualifier 結合使用時,自動注入的策略就從 byType 轉變成 byName 了。@Autowired 可以對成員變量、方法以及構造函數進行注釋,而 @Qualifier 的標注對象是成員變量、方法入參、構造函數入參。正是由于注釋對象的不同,所以 Spring 不將 @Autowired 和 @Qualifier 統一成一個注釋類。下面是對成員變量和構造函數入參進行注釋的代碼:    
       
    對成員變量進行注釋:    
      
    清單 14. 對成員變量使用 @Qualifier 注釋    
                        
    public class Boss {    
        @Autowired   
        private Car car;    
         
        @Autowired   
        @Qualifier("office")    
        private Office office;    
        …    
    }    
         
        
    對構造函數入參進行注釋:    
        
    清單 15. 對構造函數變量使用 @Qualifier 注釋    
                        
    public class Boss {    
        private Car car;    
        private Office office;    
       
        @Autowired   
        public Boss(Car car , @Qualifier("office")Office office){    
            this.car = car;    
            this.office = office ;    
        }    
    }    
         
    @Qualifier 只能和 @Autowired 結合使用,是對 @Autowired 有益的補充。一般來講,@Qualifier 對方法簽名中入參進行注釋會降低代碼的可讀性,而對成員變量注釋則相對好一些。    
        
       
    使用 JSR-250 的注釋    
       
    Spring 不但支持自己定義的 @Autowired 的注釋,還支持幾個由 JSR-250 規范定義的注釋,它們分別是 @Resource、@PostConstruct 以及 @PreDestroy。    
       
    @Resource   
       
    @Resource 的作用相當于 @Autowired,只不過 @Autowired 按 byType 自動注入,面 @Resource 默認按 byName 自動注入罷了。@Resource 有兩個屬性是比較重要的,分別是 name 和 type,Spring 將 @Resource 注釋的 name 屬性解析為 Bean 的名字,而 type 屬性則解析為 Bean 的類型。所以如果使用 name 屬性,則使用 byName 的自動注入策略,而使用 type 屬性時則使用 byType 自動注入策略。如果既不指定 name 也不指定 type 屬性,這時將通過反射機制使用 byName 自動注入策略。    
       
    Resource 注釋類位于 Spring 發布包的 lib/j2ee/common-annotations.jar 類包中,因此在使用之前必須將其加入到項目的類庫中。來看一個使用 @Resource 的例子:    
       
    清單 16. 使用 @Resource 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import javax.annotation.Resource;    
       
    public class Boss {    
        // 自動注入類型為 Car 的 Bean    
        @Resource   
        private Car car;    
       
        // 自動注入 bean 名稱為 office 的 Bean    
        @Resource(name = "office")    
        private Office office;    
    }    
         
    一般情況下,我們無需使用類似于 @Resource(type=Car.class) 的注釋方式,因為 Bean 的類型信息可以通過 Java 反射從代碼中獲取。    
       
    要讓 JSR-250 的注釋生效,除了在 Bean 類中標注這些注釋外,還需要在 Spring 容器中注冊一個負責處理這些注釋的 BeanPostProcessor:    
       
    <bean     
      class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor"/>    
         
      
    CommonAnnotationBeanPostProcessor 實現了 BeanPostProcessor 接口,它負責掃描使用了 JSR-250 注釋的 Bean,并對它們進行相應的操作。    
       
    @PostConstruct 和 @PreDestroy   
       
    Spring 容器中的 Bean 是有生命周期的,Spring 允許在 Bean 在初始化完成后以及 Bean 銷毀前執行特定的操作,您既可以通過實現 InitializingBean/DisposableBean 接口來定制初始化之后 / 銷毀之前的操作方法,也可以通過 <bean> 元素的 init-method/destroy-method 屬性指定初始化之后 / 銷毀之前調用的操作方法。關于 Spring 的生命周期,筆者在《精通 Spring 2.x—企業應用開發精解》第 3 章進行了詳細的描述,有興趣的讀者可以查閱。    
       
    JSR-250 為初始化之后/銷毀之前方法的指定定義了兩個注釋類,分別是 @PostConstruct 和 @PreDestroy,這兩個注釋只能應用于方法上。標注了 @PostConstruct 注釋的方法將在類實例化后調用,而標注了 @PreDestroy 的方法將在類銷毀之前調用。    
      
    清單 17. 使用 @PostConstruct 和 @PreDestroy 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import javax.annotation.Resource;    
    import javax.annotation.PostConstruct;    
    import javax.annotation.PreDestroy;    
       
    public class Boss {    
        @Resource   
        private Car car;    
       
        @Resource(name = "office")    
        private Office office;    
       
        @PostConstruct   
        public void postConstruct1(){    
            System.out.println("postConstruct1");    
        }    
       
        @PreDestroy   
        public void preDestroy1(){    
            System.out.println("preDestroy1");     
        }    
        …    
    }    
         
    您只需要在方法前標注 @PostConstruct 或 @PreDestroy,這些方法就會在 Bean 初始化后或銷毀之前被 Spring 容器執行了。    
       
    我 們知道,不管是通過實現 InitializingBean/DisposableBean 接口,還是通過 <bean> 元素的 init-method/destroy-method 屬性進行配置,都只能為 Bean 指定一個初始化 / 銷毀的方法。但是使用 @PostConstruct 和 @PreDestroy 注釋卻可以指定多個初始化 / 銷毀方法,那些被標注 @PostConstruct 或 @PreDestroy 注釋的方法都會在初始化 / 銷毀時被執行。    
       
    通過以下的測試代碼,您將可以看到 Bean 的初始化 / 銷毀方法是如何被執行的:    
      
    清單 18. 測試類代碼    
                        
    package com.baobaotao;    
       
    import org.springframework.context.support.ClassPathXmlApplicationContext;    
       
    public class AnnoIoCTest {    
       
        public static void main(String[] args) {    
            String[] locations = {"beans.xml"};    
            ClassPathXmlApplicationContext ctx =     
                new ClassPathXmlApplicationContext(locations);    
            Boss boss = (Boss) ctx.getBean("boss");    
            System.out.println(boss);    
            ctx.destroy();// 關閉 Spring 容器,以觸發 Bean 銷毀方法的執行    
        }    
    }    
         
       
    這 時,您將看到標注了 @PostConstruct 的 postConstruct1() 方法將在 Spring 容器啟動時,創建 Boss Bean 的時候被觸發執行,而標注了 @PreDestroy 注釋的 preDestroy1() 方法將在 Spring 容器關閉前銷毀 Boss Bean 的時候被觸發執行。    
           
    使用 <context:annotation-config/> 簡化配置    
       
    Spring 2.1 添加了一個新的 context 的 Schema 命名空間,該命名空間對注釋驅動、屬性文件引入、加載期織入等功能提供了便捷的配置。我們知道注釋本身是不會做任何事情的,它僅提供元數據信息。要使元數 據信息真正起作用,必須讓負責處理這些元數據的處理器工作起來。     
       
    而我們前面所介紹的 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor 就是處理這些注釋元數據的處理器。但是直接在 Spring 配置文件中定義這些 Bean 顯得比較笨拙。Spring 為我們提供了一種方便的注冊這些 BeanPostProcessor 的方式,這就是 <context:annotation-config/>。請看下面的配置:    
         
    清單 19. 調整 beans.xml 配置文件    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
         xmlns:context="http://www.springframework.org/schema/context"   
         xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
     http://www.springframework.org/schema/context     
     http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
         
        <context:annotation-config/>     
       
        <bean id="boss" class="com.baobaotao.Boss"/>    
        <bean id="office" class="com.baobaotao.Office">    
            <property name="officeNo" value="001"/>    
        </bean>    
        <bean id="car" class="com.baobaotao.Car" scope="singleton">    
            <property name="brand" value=" 紅旗 CA72"/>    
            <property name="price" value="2000"/>    
        </bean>    
    </beans>    
          
    <context:annotationconfig/> 將隱式地向 Spring 容器注冊 AutowiredAnnotationBeanPostProcessor、CommonAnnotationBeanPostProcessor、 PersistenceAnnotationBeanPostProcessor 以及 equiredAnnotationBeanPostProcessor 這 4 個 BeanPostProcessor。    
       
    在配置文件中使用 context 命名空間之前,必須在 <beans> 元素中聲明 context 命名空間。    
       
        
    使用 @Component   
       
    雖 然我們可以通過 @Autowired 或 @Resource 在 Bean 類中使用自動注入功能,但是 Bean 還是在 XML 文件中通過 <bean> 進行定義 —— 也就是說,在 XML 配置文件中定義 Bean,通過 @Autowired 或 @Resource 為 Bean 的成員變量、方法入參或構造函數入參提供自動注入的功能。能否也通過注釋定義 Bean,從 XML 配置文件中完全移除 Bean 定義的配置呢?答案是肯定的,我們通過 Spring 2.5 提供的 @Component 注釋就可以達到這個目標了。    
       
    下面,我們完全使用注釋定義 Bean 并完成 Bean 之間裝配:    
       
       
    清單 20. 使用 @Component 注釋的 Car.java    
                        
    package com.baobaotao;    
       
    import org.springframework.stereotype.Component;    
       
    @Component   
    public class Car {    
        …    
    }    
         
         
    僅需要在類定義處,使用 @Component 注釋就可以將一個類定義了 Spring 容器中的 Bean。下面的代碼將 Office 定義為一個 Bean:    
        
    清單 21. 使用 @Component 注釋的 Office.java    
                        
    package com.baobaotao;    
       
    import org.springframework.stereotype.Component;    
       
    @Component   
    public class Office {    
        private String officeNo = "001";    
        …    
    }    
         
    這樣,我們就可以在 Boss 類中通過 @Autowired 注入前面定義的 Car 和 Office Bean 了。    
       
    清單 22. 使用 @Component 注釋的 Boss.java    
                        
    package com.baobaotao;    
       
    import org.springframework.beans.factory.annotation.Autowired;    
    import org.springframework.beans.factory.annotation.Required;    
    import org.springframework.beans.factory.annotation.Qualifier;    
    import org.springframework.stereotype.Component;    
       
    @Component("boss")    
    public class Boss {    
        @Autowired   
        private Car car;    
       
        @Autowired   
        private Office office;    
        …    
    }    
        
    @Component 有一個可選的入參,用于指定 Bean 的名稱,在 Boss 中,我們就將 Bean 名稱定義為“boss”。一般情況下,Bean 都是 singleton 的,需要注入 Bean 的地方僅需要通過 byType 策略就可以自動注入了,所以大可不必指定 Bean 的名稱。    
       
    在使用 @Component 注釋后,Spring 容器必須啟用類掃描機制以啟用注釋驅動 Bean 定義和注釋驅動 Bean 自動注入的策略。Spring 2.5 對 context 命名空間進行了擴展,提供了這一功能,請看下面的配置:    
        
    清單 23. 簡化版的 beans.xml    
                        
    <?xml version="1.0" encoding="UTF-8" ?>    
    <beans xmlns="http://www.springframework.org/schema/beans"   
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"   
        xmlns:context="http://www.springframework.org/schema/context"   
        xsi:schemaLocation="http://www.springframework.org/schema/beans     
     http://www.springframework.org/schema/beans/spring-beans-2.5.xsd    
     http://www.springframework.org/schema/context     
     http://www.springframework.org/schema/context/spring-context-2.5.xsd">    
        <context:component-scan base-package="com.baobaotao"/>    
    </beans>    
          
    這 里,所有通過 <bean> 元素定義 Bean 的配置內容已經被移除,僅需要添加一行 <context:component-scan/> 配置就解決所有問題了——Spring XML 配置文件得到了極致的簡化(當然配置元數據還是需要的,只不過以注釋形式存在罷了)。<context:component-scan/> 的 base-package 屬性指定了需要掃描的類包,類包及其遞歸子包中所有的類都會被處理。    
       
    <context:component-scan/> 還允許定義過濾器將基包下的某些類納入或排除。Spring 支持以下 4 種類型的過濾方式,通過下表說明:    
       
    表 1. 掃描過濾方式    
    過濾器類型 說明     
    注釋 假如 com.baobaotao.SomeAnnotation 是一個注釋類,我們可以將使用該注釋的類過濾出來。     
    類名指定 通過全限定類名進行過濾,如您可以指定將 com.baobaotao.Boss 納入掃描,而將 com.baobaotao.Car 排除在外。     
    正則表達式 通過正則表達式定義過濾的類,如下所示: com\.baobaotao\.Default.*     
    AspectJ 表達式 通過 AspectJ 表達式定義過濾的類,如下所示: com. baobaotao..*Service+     
       
    下面是一個簡單的例子:    
       
    <context:component-scan base-package="com.baobaotao">    
        <context:include-filter type="regex"     
            expression="com\.baobaotao\.service\..*"/>    
        <context:exclude-filter type="aspectj"     
            expression="com.baobaotao.util..*"/>    
    </context:component-scan>    
          
    值 得注意的是 <context:component-scan/> 配置項不但啟用了對類包進行掃描以實施注釋驅動 Bean 定義的功能,同時還啟用了注釋驅動自動注入的功能(即還隱式地在內部注冊了 AutowiredAnnotationBeanPostProcessor 和 CommonAnnotationBeanPostProcessor),因此當使用 <context:component-scan/> 后,就可以將 <context:annotation-config/> 移除了。    
       
    默認情況下通過 @Component 定義的 Bean 都是 singleton 的,如果需要使用其它作用范圍的 Bean,可以通過 @Scope 注釋來達到目標,如以下代碼所示:    
       
    清單 24. 通過 @Scope 指定 Bean 的作用范圍    
                        
    package com.baobaotao;    
    import org.springframework.context.annotation.Scope;    
    …    
    @Scope("prototype")    
    @Component("boss")    
    public class Boss {    
        …    
    }    
         
    這樣,當從 Spring 容器中獲取 boss Bean 時,每次返回的都是新的實例了。    
          
    采用具有特殊語義的注釋    
       
    Spring 2.5 中除了提供 @Component 注釋外,還定義了幾個擁有特殊語義的注釋,它們分別是:@Repository、@Service 和 @Controller。在目前的 Spring 版本中,這 3 個注釋和 @Component 是等效的,但是從注釋類的命名上,很容易看出這 3 個注釋分別和持久層、業務層和控制層(Web 層)相對應。雖然目前這 3 個注釋和 @Component 相比沒有什么新意,但 Spring 將在以后的版本中為它們添加特殊的功能。所以,如果 Web 應用程序采用了經典的三層分層結構的話,最好在持久層、業務層和控制層分別采用 @Repository、@Service 和 @Controller 對分層中的類進行注釋,而用 @Component 對那些比較中立的類進行注釋。    
            
    注釋配置和 XML 配置的適用場合    
       
    是否有了這些 IOC 注釋,我們就可以完全摒除原來 XML 配置的方式呢?答案是否定的。有以下幾點原因:    
       
    注 釋配置不一定在先天上優于 XML 配置。如果 Bean 的依賴關系是固定的,(如 Service 使用了哪幾個 DAO 類),這種配置信息不會在部署時發生調整,那么注釋配置優于 XML 配置;反之如果這種依賴關系會在部署時發生調整,XML 配置顯然又優于注釋配置,因為注釋是對 Java 源代碼的調整,您需要重新改寫源代碼并重新編譯才可以實施調整。     
    如果 Bean 不是自己編寫的類(如 JdbcTemplate、SessionFactoryBean 等),注釋配置將無法實施,此時 XML 配置是唯一可用的方式。     
    注釋配置往往是類級別的,而 XML 配置則可以表現得更加靈活。比如相比于 @Transaction 事務注釋,使用 aop/tx 命名空間的事務配置更加靈活和簡單。     
    所 以在實現應用中,我們往往需要同時使用注釋配置和 XML 配置,對于類級別且不會發生變動的配置可以優先考慮注釋配置;而對于那些第三方類以及容易發生調整的配置則應優先考慮使用 XML 配置。Spring 會在具體實施 Bean 創建和 Bean 注入之前將這兩種配置方式的元信息融合在一起。    
           
    小結    
       
    Spring 在 2.1 以后對注釋配置提供了強力的支持,注釋配置功能成為 Spring 2.5 的最大的亮點之一。合理地使用 Spring 2.5 的注釋配置,可以有效減少配置的工作量,提高程序的內聚性。但是這并不意味著傳統 XML 配置將走向消亡,在第三方類 Bean 的配置,以及那些諸如數據源、緩存池、持久層操作模板類、事務管理等內容的配置上,XML 配置依然擁有不可替代的地位。

    posted @ 2011-10-10 15:49 AK47 閱讀(330) | 評論 (0)編輯 收藏

    (轉貼)數據庫三范式經典實例解析

    數據庫的設計范式是數據庫設計所需要滿足的規范,滿足這些規范的數據庫是簡潔的、結構明晰的,同時,不會發生插入(insert)、刪除(delete)和更新(update)操作異常。反之則是亂七八糟,不僅給數據庫的編程人員制造麻煩,而且面目可憎,可能存儲了大量不需要的冗余信息。
         設計范式是不是很難懂呢?非也,大學教材上給我們一堆數學公式我們當然看不懂,也記不住。所以我們很多人就根本不按照范式來設計數據庫。
         實質上,設計范式用很形象、很簡潔的話語就能說清楚,道明白。本文將對范式進行通俗地說明,并以筆者曾經設計的一個簡單論壇的數據庫為例來講解怎樣將這些范式應用于實際工程。

    范式說明
         第一范式(1NF):數據庫表中的字段都是單一屬性的,不可再分。這個單一屬性由基本類型構成,包括整型、實數、字符型、邏輯型、日期型等。
         例如,如下的數據庫表是符合第一范式:

    字段1 字段2 字段3 字段4
    ? ? ? ?
     而這樣的數據庫表是不符合第一范式的:
    字段1 字段2 字段3 字段4
    ? ? 字段3.1 字段3.2 ?

     

         很顯然,在當前的任何關系數據庫管理系統(DBMS)中,傻瓜也不可能做出不符合第一范式的數據庫,因為這些DBMS不允許你把數據庫表的一列再分成二列或多列。因此,你想在現有的DBMS中設計出不符合第一范式的數據庫都是不可能的。
         第二范式(2NF):數據庫表中不存在非關鍵字段對任一候選關鍵字段的部分函數依賴(部分函數依賴指的是存在組合關鍵字中的某些字段決定非關鍵字段的情況),也即所有非關鍵字段都完全依賴于任意一組候選關鍵字。
         假定選課關系表為SelectCourse(學號, 姓名, 年齡, 課程名稱, 成績, 學分),關鍵字為組合關鍵字(學號, 課程名稱),因為存在如下決定關系:
         (學號, 課程名稱) → (姓名, 年齡, 成績, 學分)
         這個數據庫表不滿足第二范式,因為存在如下決定關系:
         (課程名稱) → (學分)
         (學號) → (姓名, 年齡)
    即存在組合關鍵字中的字段決定非關鍵字的情況。
         由于不符合2NF,這個選課關系表會存在如下問題:
         (1) 數據冗余:
         同一門課程由n個學生選修,"學分"就重復n-1次;同一個學生選修了m門課程,姓名和年齡就重復了m-1次。
         (2) 更新異常:
         若調整了某門課程的學分,數據表中所有行的"學分"值都要更新,否則會出現同一門課程學分不同的情況。
         (3) 插入異常:
         假設要開設一門新的課程,暫時還沒有人選修。這樣,由于還沒有"學號"關鍵字,課程名稱和學分也無法記錄入數據庫。
         (4) 刪除異常:
         假設一批學生已經完成課程的選修,這些選修記錄就應該從數據庫表中刪除。但是,與此同時,課程名稱和學分信息也被刪除了。很顯然,這也會導致插入異常。

         把選課關系表SelectCourse改為如下三個表:
         學生:Student(學號, 姓名, 年齡);
         課程:Course(課程名稱, 學分);
         選課關系:SelectCourse(學號, 課程名稱, 成績)。
         這樣的數據庫表是符合第二范式的,消除了數據冗余、更新異常、插入異常和刪除異常。
         另外,所有單關鍵字的數據庫表都符合第二范式,因為不可能存在組合關鍵字。
         第三范式(3NF):在第二范式的基礎上,數據表中如果不存在非關鍵字段對任一候選關鍵字段的傳遞函數依賴則符合第三范式。所謂傳遞函數依賴,指的是如果存在"A → B → C"的決定關系,則C傳遞函數依賴于A。因此,滿足第三范式的數據庫表應該不存在如下依賴關系:
         關鍵字段 → 非關鍵字段x → 非關鍵字段y
         假定學生關系表為Student(學號, 姓名, 年齡, 所在學院, 學院地點, 學院電話),關鍵字為單一關鍵字"學號",因為存在如下決定關系:
         (學號) → (姓名, 年齡, 所在學院, 學院地點, 學院電話)
    這個數據庫是符合2NF的,但是不符合3NF,因為存在如下決定關系:
         (學號) → (所在學院) → (學院地點, 學院電話)
    即存在非關鍵字段"學院地點"、"學院電話"對關鍵字段"學號"的傳遞函數依賴。
         它也會存在數據冗余、更新異常、插入異常和刪除異常的情況,讀者可自行分析得知。
         把學生關系表分為如下兩個表:
         學生:(學號, 姓名, 年齡, 所在學院);
         學院:(學院, 地點, 電話)。
    這樣的數據庫表是符合第三范式的,消除了數據冗余、更新異常、插入異常和刪除異常。
         鮑依斯-科得范式(BCNF):在第三范式的基礎上,數據庫表中如果不存在任何字段對任一候選關鍵字段的傳遞函數依賴則符合第三范式。
         假設倉庫管理關系表為StorehouseManage(倉庫ID, 存儲物品ID, 管理員ID, 數量),且有一個管理員只在一個倉庫工作;一個倉庫可以存儲多種物品。這個數據庫表中存在如下決定關系:
         (倉庫ID, 存儲物品ID) →(管理員ID, 數量)
         (管理員ID, 存儲物品ID) → (倉庫ID, 數量)
         所以,(倉庫ID, 存儲物品ID)和(管理員ID, 存儲物品ID)都是StorehouseManage的候選關鍵字,表中的唯一非關鍵字段為數量,它是符合第三范式的。但是,由于存在如下決定關系:
         (倉庫ID) → (管理員ID)
         (管理員ID) → (倉庫ID)
    即存在關鍵字段決定關鍵字段的情況,所以其不符合 BCNF范式。它會出現如下異常情況:
         (1) 刪除異常:
         當倉庫被清空后,所有"存儲物品ID"和"數量"信息被刪除的同時,"倉庫ID"和"管理員ID"信息也被刪除了。
         (2) 插入異常:
         當倉庫沒有存儲任何物品時,無法給倉庫分配管理員。
         (3) 更新異常:
         如果倉庫換了管理員,則表中所有行的管理員ID都要修改。
         把倉庫管理關系表分解為二個關系表:
         倉庫管理:StorehouseManage(倉庫ID, 管理員ID);
         倉庫:Storehouse(倉庫ID, 存儲物品ID, 數量)。
         這樣的數據庫表是符合BCNF范式的,消除了刪除異常、插入異常和更新異常。


    原帖地址: http://www.cublog.cn/u/23975/showart.php?id=391210

    posted @ 2011-02-21 14:45 AK47 閱讀(321) | 評論 (0)編輯 收藏

    Hibernate 實體對象的生命周期匯總

    本帖匯總了網上幾篇關于hibernate的生命周期的帖子。

    轉載:

    實體對象的生命周期在Hibernate應用中是一個很關鍵的概念,正確的理解實體對象的生命周期將對我們應用Hibernate做持久層設計起到很大的作用.而所謂的實體對象的生命周期就是指實體對象由產生到被GC回收的一段過程.在這過程中我們需要理解的就是實體對象生命周期中的三種狀態.

    1. 自由狀態(Transient)
    所謂的Transient狀態,即實體對象在內存中自由存在,與數據庫中的記錄無關,通常是我們的J2EE中 VO,并沒有被納入Hibernate的實體管理容器.

    1    Test test = new Test();
    2        test.setName("energykk");
    3        //此時的test對象處于Transient(自由狀態)并沒有被Hibernate框架所管理
    4        

    2.持久狀態(Persistent)
    何謂 Persistent? 即實體對象已經處于被Hibernate實體管理容器容器所管理的狀態.這種狀態下這個實體對象的引用將被納入Hibernate實體管理容器容器所管理.
    處于Persistent狀態的實體對象,對它的變更也將被固化到數據庫中.
    在J2EE中通常指的是一個PO.
    Transaction tr = session.beginTransaction();
            session.save(test);
            
    //此時的test對象已經處于Persistent(持久狀態)它被Hibernate 納入實體管理容器
            tr.commit();
            Transaction tr2 
    = session.beginTransaction();
            test.setName(
    "xukai");
            
    //在這個事務中我們并沒有顯示的調用save()方法但是由于Persistent狀態的對象將會自動的固化到
            
    //數據庫中,因此此時正處在Persistent狀態的test對象的變化也將自動被同步到數據庫中
            tr2.commit();

    處于Persistent狀態的實體可以簡單的理解為:如果一個實體對象與session發生了關聯,并且處于session的有效期內,那么這個實體對象就處于Persistent狀態.

    3.游離狀態(Detached)
    處于Persistent狀態的實體對象,其對應的session關閉以后,那么這個實體就處于 Detached狀態.
    我們可以認為session對象就是一個Persistent的宿主,一旦這個宿主失效,那么這個實體就處于 Detached狀態.

    session.close();
            
    //與test對象關聯的session被關閉,因此此時的test對象進入 Detached(游離狀態)
            
            session2 
    = HibernateSessionFactory.getSession();
            Transaction tr3 
    = session2.beginTransaction();
            session2.update(test);
            
    //此時正處于Detached狀態的test對象由于再次借助與session2被納入到Hibernate的實體管理容器所以此時的
            
    //test對象恢復到Persistent狀態
            test.setName("jjjj");
            tr3.commit();
            
            session2.close();

    既然Transient狀態的實體與Detached狀態的實體都與Hibernate的實體管理容器沒有關系,那他們到底存在哪些差異?
    差異就在于處于Transient狀態的只有一個Name的屬性.此時的test對象所包含的數據信息僅限于此,他與數據庫中的記錄沒有任何瓜葛.
    但是處于Detached狀態的實體已經不止包含Name這個屬性,還被賦予了主鍵也就是通常POJO里的id屬性,由于id是主鍵,他可以確定數據庫表中的一條
    唯一的記錄,那么自然的處于Detached狀態的實體就能與數據庫表中擁有相同id的記錄相關聯.
    這就是他們之間所存在的差異, 簡而言之,Transient狀態的實體缺乏與數據庫表記錄之間的聯系,而Detached狀態的試題恰恰相反.只不過是脫離了session這個數據庫操作平臺而已.
    原帖地址 : http://www.tkk7.com/energykk/archive/2007/05/08/115927.html

     生命周期圖:
    原圖地址:http://hi.baidu.com/quest2run/blog/item/39e1d08c7dbd45f4503d9222.html
     

    persistence context



    生命周期特征總結 :
    原帖地址 : http://blog.csdn.net/hgd250/archive/2008/08/06/2775943.aspx
    Transient:

        與數據庫中的記錄沒有任何關系,即沒有與其相關聯的數據庫記錄.
        與session沒有任何關系.即沒有通過session對象的實例對其進行任何持久化的操作
    Persistent:
        每個persistent狀態的實體對象都與一個session對象的實例相關聯
        處于 Persistent狀態的實體對象是與數據庫中的記錄相關聯的.
        Hibernate會依據persistent狀態的實體對象的屬性變化而改變數據庫中相對應的記錄
    .
    Detached:
        游離態是由持久態實體對象轉變而來的.
        游離態實體不再與session對象相關聯.
        游離態實體對象與數據庫中的記錄沒有直接聯系,對其所做的任何修改將不會影響到到數據庫中的數據.
        游離態實體對象在數據庫有相對應的數據記錄,如果沒有被其他事務刪除.

    posted @ 2011-02-14 14:26 AK47 閱讀(333) | 評論 (0)編輯 收藏

    (轉貼)BigInteger 和 BigDecimal

    高精度數字
    Java 提供了兩個類專門用于進行高精度運算BigInteger 和 BigDecimal ,盡管它們可大致劃分到與封裝器相同的類別里,但兩者都沒有對應的主類型;這兩個類都有自己的一系列方法,類似于我們針對主類型執行的操作,也就是說能用 int 或float 做的事情,用BigInteger和BigDecimal 一樣可以做,只是必須換用方法調用,而不是使用運算符。此外由于牽涉更多,所以運算速度會慢一點總之我們犧牲了速度,但換來了精度。

    高精度浮點數BigDecimal

    一些非整數值(如幾美元和幾美分這樣的小數)需要很精確。浮點數不是精確值,所以使用它們會導致舍入誤差。因此,使用浮點數來試圖表示象貨幣量這樣的精確數量不是一個好的想法。使用浮點數來進行美元和美分計算會得到災難性的后果。浮點數最好用來表示象測量值這類數值,這類值從一開始就不怎么精確。
        從 JDK 1.3 起,Java 開發人員就有了另一種數值表示法來表示非整數:BigDecimal。BigDecimal 是標準的類,在編譯器中不需要特殊支持,它可以表示任意精度的小數,并對它們進行計算。在內部,可以用任意精度任何范圍的值和一個換算因子來表示 BigDecimal,換算因子表示左移小數點多少位,從而得到所期望范圍內的值。因此,用 BigDecimal 表示的數的形式為 unscaledValue*10-scale。
    用于加、減、乘和除的方法給  BigDecimal 值提供了算術運算。由于 BigDecimal 對象是不可變的,這些方法中的每一個都會產生新的 BigDecimal 對象。因此,因為創建對象的開銷,BigDecimal 不適合于大量的數學計算,但設計它的目的是用來精確地表示小數。如果您正在尋找一種能精確表示如貨幣量這樣的數值,則 BigDecimal 可以很好地勝任該任務。
    如浮點類型一樣,BigDecimal 也有一些令人奇怪的行為。尤其在使用 equals() 方法來檢測數值之間是否相等時要小心。equals() 方法認為,兩個表示同一個數但換算值不同(例如,100.00 和  100.000)的 BigDecimal 值是不相等的。然而,compareTo() 方法會認為這兩個數是相等的,所以在從數值上比較兩個  BigDecimal 值時,應該使用 compareTo() 而不是 equals()。
    另外還有一些情形,任意精度的小數運算仍不能表示精確結果。例如,1 除以 9 會產生無限循環的小數 .111111...。出于這個原因,在進行除法運算時,BigDecimal 可以讓您顯式地控制舍入。movePointLeft() 方法支持 10 的冪次方的精確除法。
    對于 BigDecimal,有幾個可用的構造函數。其中一個構造函數以雙精度浮點數作為輸入,另一個以整數和換算因子作為輸入,還有一個以小數的 String 表示作為輸入。要小心使用  BigDecimal(double) 構造函數, 因為如果不了解它,會在計算過程中產生舍入誤差。請使用基于整數或 String 的構造函數。
    如果使用 BigDecimal(double) 構造函數不恰當,在傳遞給 JDBC setBigDecimal() 方法時,會造成似乎很奇怪的 JDBC 驅動程序中的異常。例如,考慮以下 JDBC 代碼,該代碼希望將數字 0.01 存儲到小數字段:
      PreparedStatement ps =connection.prepareStatement("INSERT INTO Foo SET name=?, value=?");
      ps.setString(1, "penny");
      ps.setBigDecimal(2, new BigDecimal(0.01));
      ps.executeUpdate();
         在執行這段似乎無害的代碼時會拋出一些令人迷惑不解的異常(這取決于具體的 JDBC 驅動程序),因為 0.01 的雙精度近似值會導致大的換算值,這可能會使 JDBC 驅動程序或數據庫感到迷惑。JDBC 驅動程序會產生異常,但可能不會說明代碼實際上錯在哪里,除非意識到二進制浮點數的局限性。相反,使用 BigDecimal("0.01") 或 BigDecimal(1, 2) 構造 BigDecimal 來避免這類問題, 因為這兩種方法都可以精確地表示小數。
     

    code :

    import java.math.BigDecimal;
    /** * *
    * <p>Title: 開源,開放</p>
    * * <p>Description: opeansource</p>
    * * <p>Copyright: Copyright (c) 2004</p>
    * * <p>Company: ?海棠</p>
    * * @author HaiTang Ming
    * * @version 1.0 */
    public class BigDecimalUtil { 
    //默認除法運算精度,及即保留小數點多少位 
    private static final int DEF_DIV_SCALE = 2; 
    //這個類不能實例化 
    private BigDecimalUtil (){   } 
    /**   
      * * 提供精確的加法運算。   
      * * @param v1 被加數   
      * * @param v2 加數   
      * * @return 兩個參數的和   
      * */ 
    public static double add(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.add(b2)).doubleValue(); 

    /**

      *提供精確的減法運算。 
      * * @param v1 被減數 
      * * @param v2 減數 
      * * @return 兩個參數的差
      **/ 
    public static double sub(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.subtract(b2)).doubleValue(); 

    /**   
      * * 提供精確的乘法運算。   
      * * @param v1 被乘數   
      * * @param v2 乘數   
      * * @return 兩個參數的積   
      * */
    public static double mul(double v1,double v2){   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.multiply(b2)).doubleValue(); 

    /**   
      * * 提供(相對)精確的除法運算,當發生除不盡的情況時,精確到   
      * * 小數點以后多少位,以后的數字四舍五入。   
      * * @param v1 被除數   
      * * @param v2 除數   
      * * @return 兩個參數的商   
      * */ 
    public static double div(double v1,double v2){   
      return div(v1,v2,DEF_DIV_SCALE); 

    /**   
      * * 提供(相對)精確的除法運算。當發生除不盡的情況時,由scale參數指   
      * * 定精度,以后的數字四舍五入。   
      * * @param v1 被除數 
      * @param v2 除數   
      * * @param scale 表示表示需要精確到小數點以后幾位。   
      * * @return 兩個參數的商   
      * */ 
    public static double div(double v1,double v2,int scale){   
      if(scale<0){     
       throw new IllegalArgumentException("The scale must be a positive integer or zero");   
      }   
      BigDecimal b1 = new BigDecimal(Double.toString(v1));   
      BigDecimal b2 = new BigDecimal(Double.toString(v2));   
      return (b1.divide(b2,scale,BigDecimal.ROUND_HALF_UP)).doubleValue(); 

    /**   
      * * 提供精確的小數位四舍五入處理。   
      * * @param v 需要四舍五入的數字   
      * * @param scale 小數點后保留幾位   
      * * @return 四舍五入后的結果   
      * */ 
    public static double round(double v,int scale){ 
      if(scale<0){     
       throw new IllegalArgumentException("The scale must be a positive integer or zero");
      }   
      BigDecimal b = new BigDecimal(Double.toString(v));   
      BigDecimal one = new BigDecimal("1");   
      return (b.divide(one,scale,BigDecimal.ROUND_HALF_UP)).doubleValue(); 
    }   
    public static void main(String[] args){   
      System.out.println(add(234.44,534.90));
     
      double a = 123.345678;   
      double d = round(a,2);   
      System.out.println("round("+a+",2)--->"+d); 
    }
    }

    高精度整數BigInteger

    BigInteger支持任意精度的整數,也就是說我們可精確表示任意大小的整數值;同時在運算過程中不會丟失任何信息;
    在BigInteger類中有所有的基本算術運算方法,如加、減、乘、除,以及可能會用到的位運算如或、異或、非、左移、右移等。下面是一些方法的例子:當然,如果要有更多的使用方法,可以查閱java api 。

    code :public class BigIntegerTest { 
    public BigIntegerTest() {   } 
    /**   
      * * 測試BigInteger
      * */ 
    public static void testBigInteger() {   
      BigInteger bi = new BigInteger("888");   
      //multiply :乘法   
      BigInteger result = bi.multiply(new BigInteger("2"));   
      System.out.println(result);   
      //divide : 除法   
      result = bi.divide(new BigInteger("2"));   
      System.out.println(result);   
      //add : 加法   
      result = bi.add(new BigInteger("232"));   
      System.out.println(result);   
      //subtract :減法   
      result = bi.subtract(new BigInteger("23122"));   
      System.out.println(result);   
      result = bi.shiftRight(2);   
      System.out.println(result); 
    }   
    public static void main(String[] args) {   
      testBigInteger(); 
    }
    }
    原貼地址http://dev.firnow.com/course/3_program/java/javaxl/2008914 /142796_2.html

    posted @ 2010-12-10 14:16 AK47 閱讀(1029) | 評論 (0)編輯 收藏

    (轉貼) 超大整數相加,超過了long的范圍,你要怎么做!

     

    引用:

     這個只能夠用字符串的形式來處理了,因為計算機能夠處理的最大是long型,本文以字符串的形式來進行超大數據的相加,理論上只要你的內存允許,相加多大的數都可以。

    /**

     * 超大整數相加:

     * 題目要求:如果系統要使用超大整數(超過long的范圍),請你設計一個數據結構來存儲這種

     * 超大型數字以及設計一種算法來實現超大整數的加法運算

     * @author Administrator

     *

     */

    public class VeryBigNumAdd {

     

        /**

         * @param args

         */

        public static void main(String[] args) {

           // TODO Auto-generated method stub

           /*

           String a="1223232";

           for(int i=a.length()-1;i>=0;i--)

           {

               System.out.print(a.charAt(i));

           }

           */

           VeryBigNumAdd vbn=new VeryBigNumAdd();

           String a="123453243455535634535252345234677576252241234123523453664563634";

           String b="123453243455535634535252345234677576252241234123523453664563634";

           String result=vbn.doAdd(a,b);

           System.out.println("result:"+result);

        }

        /**

         *

         * @param a 加數字符串1

         * @param b 加數字符串2

         * @return 結果字符串

         * 分析:

         * 1、取得兩個字符串的長度

         * 2、把兩個的長度做比較,并得出較長的長度,及較短的長度

         * 3、把長度較短的加數字符串,在左面補0,使之與較長的字符串一樣長

         * 4、從最高位,一個個數的取出來相加,當然首先得轉換為整型

         * 5、設置進位,如果兩個數相加及加上進位大于等于10,并且這不是最左邊一個字符相加,相加結果等于

         *    (取出1+取出2+進位)-10,并把進位設為1;如果沒有大于10,就把進位設為0,如些循環,把

         *    相加的結果以字符串的形式結合起來,就得到最后的結果

         */

        String doAdd(String a,String b)

        {

           String str="";

           int lenA=a.length();

           int lenB=b.length();

           int maxLen=(lenA>lenB) ? lenA : lenB;

           int minLen=(lenA<lenB) ? lenA : lenB;

           String strTmp="";

           for(int i=maxLen-minLen;i>0;i--)

           {

               strTmp+="0";

           }

           //把長度調整到相同

           if(maxLen==lenA)

           {

               b=strTmp+b;

           }else

               a=strTmp+a;

           int JW=0;//進位

           for(int i=maxLen-1;i>=0;i--)

           {        

               int tempA=Integer.parseInt(String.valueOf(a.charAt(i)));

               int tempB=Integer.parseInt(String.valueOf(b.charAt(i)));

               int temp;

               if(tempA+tempB+JW>=10 && i!=0)

               {

                  temp=tempA+tempB+JW-10;

                  JW=1;

               }

               else

               {

                  temp=tempA+tempB+JW;

                  JW=0;

               }        

               str=String.valueOf(temp)+str;        

           }

           return str;

        }

     

    }

     

    原帖地址: http://blog.csdn.net/fenglibing/archive/2007/08/23/1756773.aspx

        
        其實java 本身也提供了api ,java.math.BigInteger;import java.math.BigDecimal; 也可以實現。

    code :

    package com.kangdy.test;

    import java.math.BigInteger;
    import java.math.BigDecimal;

    public class NumberTest {
     public static void main(String args[]){
      BigInteger b1= new BigInteger("2222222222222222222222222");
      BigInteger b2= new BigInteger("8888888888888888888888888");
      BigDecimal b3 = new BigDecimal("66666666666666666666666666");
      BigDecimal b4 = new BigDecimal("9999999999999999999999999999");
      System.out.println(b1.add(b2).toString());
      System.out.println(b3.add(b4).toString());
     }
    }

    這里只是給出簡單的例子。



    posted @ 2010-12-10 14:06 AK47 閱讀(927) | 評論 (0)編輯 收藏

    (轉貼)java回調函數

    原帖地址: http://ayzw001.blog.163.com/blog/static/1134114222009420112538726/

    引用:

           所謂回調,就是客戶程序C調用服務程序S中的某個方法a,然后S又在某個時候反過來調用C中的某個方法b,對于C來說,這個b便叫做回調函數。

    一般說來,C不會自己調用b,C提供b的目的就是讓S來調用它,而且是C不得不提供。由于S并不知道C提供的b叫甚名誰,所以S會約定b的接口規范(函數原型),然后由C提前通過S的一個函數r告訴S自己將要使用b函數,這個過程稱為回調函數的注冊,r稱為注冊函數。

    下面舉個通俗的例子:

    某天,我打電話向你請教問題,當然是個難題,:),你一時想不出解決方法,我又不能拿著電話在那里傻等,于是我們約定:等你想出辦法后打手機通知我,這樣,我就掛掉電話辦其它事情去了。過了XX分鐘,我的手機響了,你興高采烈的說問題已經搞定,應該如此這般處理。故事到此結束。

    這個例子說明了“異步+回調”的編程模式。其中,你后來打手機告訴我結果便是一個“回調”過程;我的手機號碼必須在以前告訴你,這便是注冊回調函數;我的手機號碼應該有效并且手機能夠接收到你的呼叫,這是回調函數必須符合接口規范。

     

    如果你還不太清楚看看這段描述合和代碼:

    聲明一個接口,另外一個類有方法里面有個參數以是這個接口類型的,而后在另外類中實現這個接口(java中多用的是匿名內部類),而且以這個匿名的類生成的對象為參數傳到上面提到類中,而后實現回調.......這種用法可以參考java里面常用到的數據庫操作所用到的幾個接口.....

    //聲明一個接口
    public interface ICallBack {
        void postExec();
    }

     

    //另外一個類有方法里面有個參數以是這個接口類型的
    public class FooBar {
        private ICallBack callBack;
        public void setCallBack(ICallBack callBack) {
            this.callBack = callBack;
        }
        public void doSth() {
            callBack.postExec();
        }
    }
    ---------------------------------------
    回調的實現
    public class Test {
        public static void main(String[] args) {
            FooBar foo = new FooBar();
            foo.setCallBack(new ICallBack() {
                public void postExec() {
                    System.out.println("method executed.");
                }
            });
            foo.doSth();//調用函數
        }
    }

    posted @ 2010-12-10 11:22 AK47 閱讀(627) | 評論 (0)編輯 收藏

    (轉貼) 真正理解面向接口編程

    面向對象設計里有一點大家已基本形成共識,就是面向接口編程,我想大多數人對這個是沒有什么覺得需要懷疑的。

    問題是在實際的項目開發中我們是怎么體現的呢? 難道就是每一個實現都提供一個接口就了事了?反過來說,你有時候有沒有覺得接口是多余的事? 又或者,你僅僅是覺得現在類似spring這樣的框架已習慣用接口這種方式而心存當然。

    設計模式解析里提到了面向對象設計考慮的幾個視角,一個是概念層,一個是規約層,一個是實現層。我如果沒有猜錯的話,實際上我們大多數人的眼睛一直是盯著實現層的,而這正是面向對象設計所極力避免的,即你不要在一開始就關注這些細節,你要關注的是規約(接口).

    對于實際項目開發來說,如果我們把實現的過程分為多個階段的話我們不妨這么劃分,第一階段,根據client端的需要去設計我們的規約(interface),在這個階段任何實現都沒有,所有的任務就是定義接口所需要的職責,以及所需要的一些po,vo;第二階段,實現前面定義的規約。而以前我是怎么做的呢? 我是交叉作的,即假模假樣的定義一個接口(其實我心里在想這個東西有屁用),然后定義了一個方法,然后就立即去實現這個方法,再然后我又定義一個方法,繼續去實現,我現在終于想通了,這樣好累,效率很低,最重要的是,這不屬于真正的設計。
    現在我是怎么做的呢?比如一個list.jsp里需要查詢,列表,然后看明細信息,然后增加信息,我會第一步在接口里定義完(這個過程會有整體設計的意識),毫不關心底層實現(數據庫、事務),我的目標就是"我想要這個功能,我想要那個功能",至于那個功能怎么實現在第一階段我認為那不是我的事情(盡管這個事情最終還是由我來做) .大家看這個過程和前面的過程有什么本質的不同呢? 就是分層的概念更加明顯,你的工作更有層次,每次都有先設計再實現的步驟,而前面那個過程很容易就讓你不知不覺地陷入純實現的陷阱中。

    一點感想,歡迎大家拍磚。

    原帖地址: http://www.tkk7.com/alex/archive/2007/03/12/103185.html

    posted @ 2010-11-05 14:09 AK47 閱讀(317) | 評論 (0)編輯 收藏

    數字金額的中文大小寫轉化

    曾經去過一家公司面試。筆試題的最后一題是一個數字金額大小寫轉化的問題。
    當時沒想那么多,僅僅想到應該把數拆開然后添加單位的一個大致的設計思路。
    而那個面試官一個勁兒的問我用啥算法。那個題最后也沒答上,回來后比較郁悶,
    在網上搜了一下。這個答案還真不少。不過覺得有一種設計還比較靠譜。
    大概是這樣:
     * 先將整數與小數部分分開,計算小數部分,角分并保存
     * 整數部分長度不足12位,前面加0補足。
     * 將整數部分分割3部分。高4位代表億,中間的是萬,其余分別代表千,百,十,個
     * 定一個方法拼出每一部分串。
     * 最后整數與小數部分合成。

    自己實現了一下,以下是代碼。
    code :

    package com.kangdy.test;
    /**
     * 數字金額轉化成大寫
     * 先將整數與小數部分分開,計算小數部分,角分并保存
     * 整數部分長度不足12位,前面加0補足。
     * 將整數部分分割3部分。高4位代表億,中間的是萬,其余分別代表千,百,十,個
     * 定一個方法拼出每一部分串。
     * 最后整數與小數部分合成。
     * @author dkang
     *
     */
    public class NumberToString {

     String numberStr;

     public static final String unit[] = { "", "十", "百", "千", "萬", "億" };

     public static final String unit2[] = { "元", "角", "分" };

     public static final String numStr[] = { "零", "壹", "貳", "叁", "肆", "伍", "陸",
       "柒", "捌", "玖" };

     /**
      * 字符串長度不足12位用0補足
      *
      * @param str
      * @return
      */
     private String additionalZero(String str) {
      StringBuffer strb = new StringBuffer();
      if (str.length() < 12) {
       int size = 12 - str.length();
       for (int i = 0; i < size; i++) {
        strb.append("0");
       }
      }
      return strb.append(str).toString();
     }

     /**
      * 遞歸拆分數字成字符串
      *
      * @param value
      * @param strBuffer
      * @return
      */
     private String decomposeNumberToString(int value, StringBuffer strBuffer) {
      int quotient = 0;
      quotient = value / 10;
      if (quotient != 0) {
       decomposeNumberToString(quotient, strBuffer);
      }
      int remaider = value % 10;
      strBuffer.append(remaider + ",");
      return strBuffer.toString().substring(0,
        strBuffer.toString().length() - 1);
     }

     /**
      * 使用循環拆分數字成字符串
      *
      * @param value
      * @return
      */
     private String decomposeNumberToString2(int value) {
      StringBuilder strBuilder = new StringBuilder();
      int quotient = value;
      int remaider = 0;
      while (quotient != 0) {
       remaider = quotient % 10;
       strBuilder.append(remaider + ",");
       quotient = quotient / 10;
      }
      strBuilder.deleteCharAt(strBuilder.lastIndexOf(","));
      return strBuilder.reverse().toString();
     }

     /**
      * 添加單位
      *
      * @param temp
      * @return
      */
     private String addUnits(String temp) {
      StringBuffer sb = new StringBuffer();
      String str[] = temp.split(",");
      String tempStr = temp.replace(",", "");
      if (tempStr.contains("000")) {
       return sb.append(resplaceNumToStr(str[0]) + unit[3]).toString();
      } else if (tempStr.contains("00")) {
       if (tempStr.charAt(3) == '0') {
        return sb.append(resplaceNumToStr(str[0]) + unit[3]).append(
          resplaceNumToStr(str[1]) + unit[2]).toString();
       } else {
        return sb.append(resplaceNumToStr(str[0]) + unit[3]).append(
          numStr[0]).append(resplaceNumToStr(str[3])).toString();
       }
      } else {
       for (int i = 0; i < str.length; i++) {
        sb.append(resplaceNumToStr(str[i]));
        if (!str[i].equals("0")) {
         sb.append(unit[str.length - (i + 1)]);
        }
       }
      }
      return sb.toString();
     }

     /**
      * 數字替換
      *
      * @param str
      * @return
      */
     private String resplaceNumToStr(String str) {
      try {
       int num = Integer.parseInt(str);
       return numStr[num];
      } catch (Exception e) {
       e.printStackTrace();
      }
      return "";
     }

     /**
      * 把4位長度的數字轉化成字符串
      *
      * @param number
      * @param i
      * @return
      */
     private String transformNumberToString(String number, int i) {
      StringBuffer strBuffer = new StringBuffer();
      StringBuilder strBuilder = new StringBuilder();
      try {
       int num = Integer.parseInt(number);
       if (num != 0) {
        String s1 = decomposeNumberToString(num, strBuffer);
        strBuilder.append(addUnits(s1));
        if (i == 1) {
         strBuilder.append(unit[5]);
        } else if (i == 2)
         strBuilder.append(unit[4]);
       }
      } catch (Exception e) {
       e.printStackTrace();
      }
      return strBuilder.toString();
     }

     /**
      * 得到最終結果
      *
      * @param str
      * @return
      */
     public String IntegrationResultString(String str) {
      StringBuffer strBuffer = new StringBuffer();
      String numStr[] = null;
      if (str.indexOf(".") != -1) {
       numStr = str.split("\\.");
      } else {
       return strBuffer.append(createIntegerPartsResult(str)).toString();
      }
      String fractionalStr = createFractionalPartsResult(numStr[1]);
      String integerStr = createIntegerPartsResult(numStr[0]);
      return strBuffer.append(integerStr).append(fractionalStr).toString();
     }

     private String createIntegerPartsResult(String integer) {
      StringBuffer strBuffer = new StringBuffer();
      String temp = additionalZero(integer);
      String str1 = temp.substring(0, 4);
      strBuffer.append(transformNumberToString(str1, 1));
      String str2 = temp.substring(4, 8);
      strBuffer.append(transformNumberToString(str2, 2));
      String str3 = temp.substring(8, temp.length());
      strBuffer.append(transformNumberToString(str3, 3) + unit2[0]);
      return strBuffer.toString();
     }

     private String createFractionalPartsResult(String fractionalStr) {
      StringBuilder strB = new StringBuilder();
      String s1 = fractionalStr.substring(0, 1);
      String s2 = fractionalStr.substring(1, fractionalStr.length());
      if (!s1.equals("0")) {
       strB.append(resplaceNumToStr(s1) + unit2[1]);
      }
      if (!s2.equals("0")) {
       strB.append(resplaceNumToStr(s2) + unit2[2]);
      }
      return strB.toString();
     }

     public static void main(String args[]) {
      NumberToString test = new NumberToString();
      String str = "200123004054.11";
      System.out.println(test.IntegrationResultString(str));
     }
    }



    posted @ 2010-11-02 14:59 AK47 閱讀(611) | 評論 (0)編輯 收藏

    類和對象的初始化

    類的生命周期:分為裝載,鏈接,初始化
    如圖:


    1)裝載:查找并裝載類型的二進制數據
    2)連接:執行驗證,準備,和解析(可選)
             a) 驗證:確保導入類型正確
             b) 準備:為類變量分配內存,并將其初始化為默認值
             c) 解析:把類型中的符號引用轉換成直接引用
    3)初始化:把類變量初始化為默認初值


          隨著Java虛擬機裝載了一個類,并執行了一些它選擇進行的驗證之后,類就可以進入準備階
    段了。在準備階段,Java虛擬機為類變量分配內存,設置默認初始值:但在到達初始化階段之前,
    類變量都沒有被初始化為真正的初始值。(在準備階段是不會執行Java代碼的。)在準備階段,虛
    擬機把給類變量新分配的內存根據類型設置為默認值。

     為了準備讓一個類或者接口被"首次主動"使用,最后一個步驟就是初始化,也就是為類變量      
    賦予正確的初始值。這里的”正確”初始值指的是程序員希望這個類變量所具備的起始值。正
    確的初始值是和在準備階段賦予的默認初始值對比而言的。前面說過,根據類型的不同,類變
    量已經被賦予了默認初始值。而正確的初始值是根據程序員制定的主觀計劃面生成的。


    在Java代碼中,一個正確的初始值是通過類變量初始化語句或者靜態初始化語句給出的。
     1)一個類變量初始化語句是變量聲明后面的等號和表達式:
     2)靜態初始化語句是一個以static開頭的程序塊
     example : 
        public class Example1 {
         
         // 類變量初始化語句
         static int value = (int) (Math.random()*6.0);
         
         // 靜態初始化語句
         static{
          System.out.println("this is example");
         }
        }
    所有的類變量初始化語句和類型的靜態初始化器都被Java編譯器收集在—起,放到——個特殊
    的方法中。對于類來說,這個方法被稱作類初始化方法;對于接口來說,它被稱為接口初始化
    方法。在類和接口的Javaclass文件中,這個方法被稱為”<clinit>”。通常的Java程序方法是無法
    調用這個<clinit>方法的。這種方法只能被Java虛擬機調用

    clinit>()方法
        前面說過,Java編譯器把類變量初始化語句和靜態初始化浯句的代碼都放到class文件的
    <clinit>()方法中,順序就按照它們在類或者接門聲明中出現的順序。
     example:
      public class Example1 {
        static int width;
        static int height = (int) (Math.random()*6.0);

        static{
         width = (int) (Math.random()*3.0);
        }
     }
    java 編譯器生成下面<clinit>方法:
    0 invokestatic java.lang.Math.random
    3 ldc2_w 6.0 (double)
    6 dmul
    7 d2i
    8 putstatic Example1.height
    11 invokestatic java.lang.Math.random
    14 ldc2_w 3.0 (double) 17 dmul
    18 d2i
    19 putstatic Example1.width
    22 return

    clinit 方法首先執行唯一的類變量初始化語句初始化heght,然后在靜態初始化語句中
    初始化width(雖然它聲明在height之前,但那僅僅是聲明了類變量而不是類變量初始化語句).

     

    除接口以外,初始化一個類之前必須保證其直接超類已被初始化,并且該初始化過程是由 Jvm 保證線程安全的。
    另外,并非所有的類都會擁有一個 <clinit>() 方法。
    1)如果類沒有聲明任何類變量,也沒有靜態初始化語句,那么它不會有<clinit>()方法。
    2)如果聲明了類變量但是沒有使用類變量初始化語句或者靜態初始化語句初始它們,那么類不會有<clinit>()方法。 
       example:
          public class example{
           static int val;
          }
        
    3)如果類僅包含靜態 final 變量的類變量初始化語句,并且類變量初始化語句是編譯時常量表達式,類不會有<clinit>()方法。
        example:
        public class Example {
         static final String str ="abc";
         static final int value = 100;
        }
    這種情況java編譯器把 str 和 value 被看做是常量,jvm會直接使用該類的常量池或者在字節碼中直接存放常量值。該類不會被加載。
     
    如果接口不包含在編譯時解析成常量的字段初始化語句,接口中就包含一個<clinit>()方法。
    example:
     interface Example{
      int i =5;
      int hoursOfSleep = (int) (Math.random()*3.0);
      
     }
    字段hoursOfSleep會被放在<clinit>()方法中(比較詭異???它被看作類變量了),而字段i被看作是編譯時常量特殊處理(JAVA語法規定,接口中的變量默認自動隱含是public static final)。
     java 編譯器生成下面<clinit>方法:
    0 invokestatic java.lang.Math.random
    3 ldc2_w 3.0 (double)
    6 dmul
    7 d2i
    8 putstatic Example.hoursOfSleep
    11 return

    主動使用和被動使用
        在前面講過,Java虛擬機在首次主動使用類型時初始化它們。只有6種活動被認為是主動使
    用:
     1)創建類的新實例,
     2)調用類中聲明的靜態方法,
     3)操作類或者接口中聲明的非常量靜態字段,
     4)調用JavaAPI中特定的反射方法
     5)初始化一個類的子類;
     6)以及指定一個類作為Java虛擬機啟動時的初始化類。
     
       使用一個非常量的靜態字段只有當類或者接口的確聲明了這個字段時才是主動使用、比如,
    類中聲明的字段可能會被子類引用;接口中聲明的字段可能會被子接口或者實現了這個接口的
    類引用。對于子類、子接口和實現接口的類來說.這就是被動使用(使用它們并不會觸發
    它們的初始化)。下面的例子說明了這個原理:

    class NewParement{
     static int hoursOfSleep = (int) (Math.random()*3.0);
     
     static{
      System.out.println("new parement is initialized.");
     }
    }

    class NewbornBaby extends NewParement{
     static int hoursOfCry = (int) (Math.random()*2.0);
     
     static{
      System.out.println("new bornBaby is initialized.");
     }
    }


    public class Example1 {
     
     public static void main(String[] args){
      int hours = NewbornBaby.hoursOfSleep;
      System.out.println(hours);
     }
     static{
      System.out.println("example1 is initialized.");
     }
     
    }
    運行結果:
    example1 is initialized.
    new parement is initialized.
    0
    NewbornBaby 沒有被初始化,也沒有被加載。


    對象的生命周期

            當java虛擬機創建一個新的類實例時不管明確的還是隱含的,首先要在堆中為保存對象的實例變量分配內存,包含所有在對象類中和它超類中
    聲明的變量(包括隱藏的實例變量)都要分配內存。其次賦默認初值,最后賦予正確的初始值。

    java編譯器為每個類都至少生成一個實例初始化方法 "<init>()"與構造方法相對應。

    如果構造方法調用同一個類中的另一個構造方法(構造方法重載),它對應的init<>():
    1)一個同類init<>()調用。
    2)對應構造方法體代碼的調用。
    如果構造方法不是通過this()調用開始,且對象不是Object 它對應的init<>():
    1)一個超類init<>()調用。
    2)任意實例變量初始化代碼調用。
    3)對應構造方法體代碼的調用。
    如果上述對象是Object,則去掉第一條。如果構造方法明確使用super()首先調用對應超類init<>()其余不變。
    下面的例子詳細說明了實例變量初始化(摘自Java Language Specification)
    class Point{
     int x,y;
     Point(){x=1;y=1;}
    }
    class ColoredPoint extends Point{
     int color = OxFF00FF;
    }
    class Test{
     public static void main(String[] args){
      ColoredPoint cp = new ColoredPoint();
      System.out.println(cp.color);
     }
    }
    首先,為新的ColoredPoint實例分配內存空間,以存儲實例變量x,y和color;然后將這些變量初始化成默認值
    在這個例子中都是0。
    接下來調用無參數的ColoredPoint(),由于ColorPoint沒有聲明構造方法,java編譯器會自動提供如下的構造方
    法:ColoredPoint(){super();}。
    該構造方法然后調用無參數的Point(),而Point()沒有顯示的超類,編譯器會提供一個對其無參數的構造方法的
    隱式調用:Point(){super();x=1;y=1}。
    因此將會調用到Object();Object類沒有超類,至此遞歸調用會終止。接下來會調用Object任何實例初始化語句
    及任何實例變量初始化語句。
    接著執行Object()由于Object類中未聲明這樣的構造方法。因此編譯器會提供默認的構造方法object(){}。
    但是執行該構造方法不會產生任何影響,然后返回。
    接下來執行Point類實例變量初始化語句。當這個過程發生時,x,y的聲明沒有提供任何初始化表達式,因此這個
    步驟未采取任何動作(x,y 仍為0);
    接下來執行Point構造方法體,將x,y賦值為1。
    接下來會執行類ColoredPoint的實例變量初始化語句。把color賦值0xFF00FF,最后執行ColoredPoint構造方法體
    余下的部分(super()調用之后的部分),碰巧沒有任何語句,因此不需要進一步的動作,初始化完成。

    與C++不同的是,在創建新的類實例期間,java編程語言不會為方法分派來指定變更的規則。如果調用的方法在被
    初始化對象的子類中重寫,那么就是用重寫的方法。甚至新對象被完全初始化前也是如此。編譯和運行下面的例子
    class Super{
     Super(){printThree();}
     void printThree{System.out.println("Three");}
    }
    class Test extends Super{
     int three = (int)Math.PI; // That is 3
     public static void main(String args[]){
      Test t = new Test();
      t.printThree();
     }
     void printThree(){System.out.println(three);}
    }
    輸出:
    0
    3
    這表明Super類中的printThree()沒有被執行。而是調用的Test中的printThree()。

     

     
     

    posted @ 2010-07-14 16:18 AK47 閱讀(895) | 評論 (0)編輯 收藏

    Java虛擬機體系結構

    Java虛擬機體系結構


    方法區
             在Java虛擬機中,被裝載類型的信息存儲在一個邏輯上被稱為方法區的內存中。
     當虛擬機裝載某個類型時,它使用類裝載器定位相應的class文件,-->讀入這個class文件(一個線性的二進制流)->將它傳入虛擬機-->
     虛擬機提取類型信息,并將信息存入方法區,類型中的類(靜態)變量也存儲在方法區.
     方法區特點:
     1)所有線程共享方法區。它是線程安全的。
     2)方法區大小不是固定的。虛擬機根據需要自行調整。
     3)方法區可以被垃圾回收。
     對于每個被裝載的類型,虛擬機會在方法區中存儲以下信息。
     
     1)類型的基本信息;
         a)類型的全限定名
         b)類型的直接超類全限定名(除非這個類型是java.lang.Objet,它沒超類)。
         c)類型是類類型還是接口類型(就是說是一個類還是一個接口)。
         d)類型的訪問修飾符(public ,abstract或final的某個子類)
         e)任何直接超接口的全限定名的有序列表。
         
     2)該類型的常量池
       虛擬機必須為每個被裝載的類型維護一個常量池。常量池就是該類型所用常量的一個有序集合,
       包括直接常量(string,integer,floating point常量)和對其他類型、字段和方法的符號引用。
       池中的數據項就像數組一樣是通過索引訪問的。因為常量池存儲了相應類型所用到的所有類型、
       字段和方法的符號引用,所以它在Java程序的動態連接中起著核心的作用。
       
     3)字段信息
       類型中聲明的每一個字段,方法區中必須保存下面的信息,字段在類或接口中聲明的順序也必須保存。
       字段名,字段類型,字段修飾符(public private protected static final 等)
       
     4)方法信息
       類型中聲明的每一個方法,方法區中必須保存下面的信息,方法在類或接口中聲明的順序也必須保存。
       方法名,返回值類型,參數數量和類型(按聲明順序),方法修飾符(public private protected static final 等)
       如果方法不是抽象的或本地的還必須保存:方法字節碼,操作數棧和該方法在棧針中局部變量的大小,異常表。
       
     5)除了常量以外的所有類(靜態)變量
       這里主要說下編譯時常量:就是那些用final聲明以及編譯時已知的值初始化的類變量(例如:static final int val =5)
       每個編譯時常量的類型都會復制它所有常量到它自己的常量池中或者它的字節碼流中(通常情況下編譯時直接替換字節碼)。

       
     6)一個到類classLoader的引用
       指向ClassLoader類的引用  每個類型被裝載的時候,虛擬機必須跟蹤它是由啟動類裝載器
       還是由用戶自定義類裝載器裝載的。如果是用戶自定義類裝載器裝載的,那么虛擬機必須在類
       型信息中存儲對該裝載器的引用:這是作為方法表中的類型數據的一部分保存的。
       虛擬機會在動態連按期間使用這個信息。當某個類型引用另一個類型的時候,虛擬機會請求裝載
       發起引用類型的類裝載器來裝載被引用的類型。這個動態連接的過程,對于虛擬機分離命名空間
       的方式也是至關重要的。為了能夠正確地執行動態連接以及維護多個命名空間,虛擬機需要在方
       法表中得知每個類都是由哪個類裝載器裝載的。
       
     7)一個到Class類的引用
        指向Class類的引用  對于每一個被裝載的類型(不管是類還是接口),虛擬機都會相應地為
        它創建一個java.lang.Class類的實例(Class實例放在內存中的堆區),
    而且虛擬機還必須以某種方式把這個實例的引用存儲在方法區
        
           為了盡可能提高訪問效率,設計者必須仔細設計存儲在方法區中的類型信息的數據結構,因此,
    除了以上時論的原始類型信息,實現中還可能包括其他數據結構以加快訪問原始數據的速度,比如方法表。
    虛擬機對每個裝載的非抽象類,都生成一個方法表,把它作為類信息的一部分保存在方法區。方法表是一個數組,
    它的元素是所有它的實例可能被調用的實例方法的直接引用,包括那些從超類繼承過來的實例方法:(對于抽象類和接口,方法表沒有什么幫
    助,因為程序決不會生成它們的實例。)運行時可以通過方法表快速搜尋在對象中調用的實例方法。
     
    方法區使用的例子

     class Lava{
      private int speed = 5;
     
      void flow(){
      
      }
     
     }

     public class Volcano {
      
      public static void main(String args[]){
       
       Lava lava = new Lava();
       
       lava.flow();
      }
     }

      1)虛擬機在方法區查找Volcano這個名字,未果,載入volcano.class文件,并提取相應信息
       存入方法區。
      2)虛擬機開始執行Volcano類中main()方法的字節碼的時候,盡管Lava類還沒被裝載,
      但是和大多數(也許所有)虛擬機實現一樣,它不會等到把程序中用到的所有類都裝載后才開
      始運行程序。恰好相反,它只在需要時才裝載相應的類。
      3)main()的第一條指令告知虛擬機為列在常量池第一項的類分配足夠的內存。所以虛擬機
      使用指向Volcano常量池的指針找到第一項,發現它是一個對Lava類的符號引用,然后它就檢查
      方法區,看Lava類是否已經被裝載了。
      4)當虛擬機發現還沒有裝載過名為"Lava"的類時,它就開始查找并裝載文件“Lava.class”,
      并把從讀入的二進制數據中提取的類型信息放在方法區中。
      5)虛擬機以一個直接指向方法區Lava類數據的指針來替換常量池第—項(就是那個
      字符串“Lava”)——以后就可以用這個指針來快速地訪問Lava類了。這個替換過程稱為常量池
      解析,即把常量池中的符號引用替換為直接引用:這是通過在方法區中搜索被引用的元素實現
      的,在這期間可能又需要裝載其他類。在這里,我們替換掉符號引用的“直接引用”是一個本
      地指針。
      6)虛擬機準備為一個新的Lava對象分配內存。此時,它又需要方法區中的信息。還記
      得剛剛放到Volcano類常量池第——項的指針嗎?現在虛擬機用它來訪問Lava類型信息(此前剛放
      到方法區中的),找出其中記錄的這樣一個信息:一個Lava對象需要分配多少堆空間。
      7)虛擬機確定一個Lava對象大小后,就在堆上分配空間,并把這個對象實例變量speed初始化為默認初始值0
      8)當把新生成的Lava對象的引用壓到棧中,main()方法的第一條指令也完成了,指令通過這個引用
      調用Java代碼(該代碼把speed變量初始化為正確初始值5).另外用這個引用調用Lava對象引用的flow()方法。


            每個java虛擬機實例都有一個方法區以及一個堆,一個java程序獨占一個java虛擬機實例,而每個java程序都有自己的堆空間,它們不會彼此干擾,但同一個java程序的多個線程共享一個堆空間。這種情況下要考慮多線程訪問同步問題。
     
    Java棧
            一個新線程被創建時,都會得到自己的PC寄存器和一個java棧,虛擬機為每個線程開辟內存區。這些內存區是私有的,任何線程不能訪問其他線程的PC寄存器和java棧。java棧總是存儲該線程中java方法的調用狀態。包括它的局部變量,被調用時傳進來的參數,它的返回值,以及運算的中間結果等。java棧是由許多棧幀或者說幀組成,一個棧幀包含一個java方法的調用狀態,當線程調用java方法時,虛擬機壓入一個新的棧幀到該線程的java棧中。當方法返回時,這個棧幀被從java棧中彈出并拋棄。
    .本地方法棧
             任何本地方法接口都會使用某種本地方法餞。當線程調用Java方法時,虛擬機會創建一個新的棧幀井壓人Java棧。
    然而當它調用的是本地方法時,虛擬機會保持Java棧不變,不再在線程的Java棧中壓人新的幀,虛擬機只是簡單地動態連接
    并直接調用指定的本地方法。可以把這看做是虛擬機利用本地方法來動態擴展自己。

    posted @ 2010-07-06 13:47 AK47 閱讀(377) | 評論 (0)編輯 收藏

    Eclipse 內置webservice瀏覽器問題

    最近在使用eclipse 內置webservice 瀏覽器遇到了些問題,無法點開WSDL Main 如下圖:


    大家遇到過類似的情況沒有,目前我只能先使用外部瀏覽器了。

    posted @ 2010-06-10 14:17 AK47 閱讀(452) | 評論 (0)編輯 收藏

    eclipse 無法啟動 JVM terminated. Exit code=-1 的解決辦法

    轉貼 :

    這兩天,突然無法啟動我的MyEclipse6.5了,不知道為什么,提示錯誤: JVM   terminated. Exit   code=-1。

    昨天,我以為是機器運行時間太長,重啟一下,果然好了。但是今天又來了。看了一下錯誤提示,我以為是JVM有問題,就在啟動Eclipse里加個JVM的參數,結果還是不行。

    后來在網上找了一下,有人說是JAVA環境配置的問題,我想這不可能,因為以前一直用的好好的。有人說是JVM的問題,這個我剛剛換了一個,也不是這個問題,后來看來有人說是:eclipse.ini中內存設置過大的問題,雖然我不以為然,還是試了一下,以前我修改過內存設置,一直都好好的,之前eclipse.ini的配置如下:

    -showsplash
    com.genuitec.myeclipse.product
    --launcher.XXMaxPermSize
    512m
    -vmargs
    -Xms256m
    -Xmx512m
    -Duser.language=en
    -XX:PermSize=256M
    -XX:MaxPermSize=512M

    現在修改了一下,-Xms256m改成-Xms128m,把Xmx512m  改為 Xmx256m,結果還真的好了,沒想到居然是這樣的小問題引起來的。

    轉載自:巴士飛揚-技術BLOG : 鏈接地址:http://www.busfly.cn/post/eclipse-JVM-terminated-Exit-code-1.html

    posted @ 2010-03-05 12:10 AK47 閱讀(261) | 評論 (0)編輯 收藏

    從追MM談Java的23種設計模式(轉)

    這樣學習設計模式肯定便于理解:
    http://hi.baidu.com/xghzlg/blog/item/3288de589071d7202934f06f.html

    引用:

     

    從追MM談Java的23種設計模式
    設計模式做為程序員的“內功心法”,越來越受到.net 社區的重視,這種變化是很可喜的,Java社區走在了我們的前面,但這種狀況也許有一天會發生改變。

      從追MM談Java的23種設計模式

      1、FACTORY—追MM少不了請吃飯了,麥當勞的雞翅和肯德基的雞翅都是MM愛吃的東西,雖然口味有所不同,但不管你帶MM去麥當勞或肯 德基,只管向服務員說“來四個雞翅”就行了。麥當勞和肯德基就是生產雞翅的Factory.

        工廠模式:客戶類和工廠類分開。消費者任何時候需要某種產品,只需向工廠請求即可。消費者無須修改就可以接納新產品。缺點 是當產品修改時,工廠類也要做相應的修改。如:如何創建及如何向客戶端提供。

      程序代碼

      以下是引用片段:

    以下是引用片段:
    public class Factory{
    public String Boy = "boy" ;
    public String Girl = "girl" ;
    public People getPeople (String people){
    if (people.equals("boy")){
    return new Boy();
    }else if(people.equals("girl")){
    return new Girl();
    }
    }
    }


    2、BUILDER—MM最愛聽的就是“我愛你”這句話了,見到不同地方的MM,要能夠用她們的方言跟她說這句話哦,我有一個多種語言翻譯機,上面每種語言都有一個按鍵,見到MM我只要按對應的鍵,它就能夠用相應的語言說出“我愛你”這句話了,國外的MM也可以輕松搞掂,這就是我的“我愛你”builder。(這一定比美軍在伊拉克用的翻譯機好賣)

       建造模式:將產品的內部表象和產品的生成過程分割開來,從而使一個建造過程生成具有不同的內部表象的產品對象。建造模式使得 產品內部表象可以獨立的變化,客戶不必知道產品內部組成的細節。建造模式可以強制實行一種分步驟進行的建造過程。

      3、FACTORY METHOD—請MM去麥當勞吃漢堡,不同的MM有不同的口味,要每個都記住是一件煩人的事情,我一般采用Factory Method模 式,帶著MM到服務員那兒,說“要一個漢堡”,具體要什么樣的漢堡呢,讓MM直接跟服務員說就行了。

        工廠方法模式:核心工廠類不再負責所有產品的創建,而是將具體創建的工作交給子類去做,成為一個抽象工廠角色,僅負責給出 具體工廠類必須實現的接口,而不接觸哪一個產品類應當被實例化這種細節。

      4、PROTOTYPE—跟MM用QQ聊天,一定要說些深情的話語了,我搜集了好多肉麻的情話,需要時只要copy出來放到QQ里面就行了,這就是 我的情話prototype了。(100塊錢一份,你要不要)

      原始模型模式:通過給出一個原型對象來指明所要創建的對象的類型,然后用復制這個原型對象的方法創建出更多同類型的對象。原始模型模式允許動態的增加或減少產品類,產品類不需要非得有任何事先確定的等級結構,原始模型模式適用于任何的等級結構。缺點是每一個類都必須配備一個克隆方法。

            5、SINGLETON—俺有6個漂亮的老婆,她們的老公都是我,我就是我們家里的老公Sigleton,她們只要說道“老公”,都是指的同一個 人,那就是我(剛才做了個夢啦,哪有這么好的事)

        單例模式:單例模式確保某一個類只有一個實例,而且自行實例化并向整個系統提供這個實例單例模式。單例模式只應在有真正的 “單一實例”的需求時才可使用。

      以下是引用片段:

    以下是引用片段:
    public class SingLeton{
    private static SingLeton instance = new SingLeton();
    public static SingLeton getInstance(){
    return instance;
    }
    }


    6、ADAPTER—在朋友聚會上碰到了一個美女Sarah,從香港來的,可我不會說粵語,她不會說普通話,只好求助于我的朋友kent了,他 作為我和Sarah之間的Adapter,讓我和Sarah可以相互交談了(也不知道他會不會耍我)

        適配器(變壓器)模式:把一個類的接口變換成客戶端所期待的另一種接口,從而使原本因接口原因不匹配而無法一起工作的兩個類 能夠一起工作。適配類可以根據參數返還一個合適的實例給客戶端。

      7、BRIDGE—早上碰到MM,要說早上好,晚上碰到MM,要說晚上好; 碰到MM穿了件新衣服,要說你的衣服好漂亮哦,碰到MM新做的發型, 要說你的頭發好漂亮哦。不要問我“早上碰到MM新做了個發型怎么說”這種問題,自己用BRIDGE組合一下不就行了

      橋梁模式:將抽象化與實現化脫耦,使得二者可以獨立的變化,也就是說將他們之間的強關聯變成弱關聯,也就是指在一個軟件系統的 抽象化和實現化之間使用組合/聚合關系而不是繼承關系,從而使兩者可以獨立的變化。

      8、COMPOSITE—Mary今天過生日。“我過生日,你要送我一件禮物。”“嗯,好吧,去商店,你自己挑。”“這件T恤挺漂亮,買,這條裙子好看,買,這個包也不錯,買。”“喂,買了三件了呀,我只答應送一件禮物的哦。”“什么呀,T恤加裙子加包包,正好配成一套呀,小姐,麻煩你包起來。”“……”,MM都會用Composite模式了,你會了沒有?

        合成模式:合成模式將對象組織到樹結構中,可以用來描述整體與部分的關系。合成模式就是一個處理對象的樹結構的模式。合成 模式把部分與整體的關系用樹結構表示出來。合成模式使得客戶端把一個個單獨的成分對象和由他們復合而成的合成對象同等看待。

      9、DECORATOR—Mary過完輪到Sarly過生日,還是不要叫她自己挑了,不然這個月伙食費肯定玩完,拿出我去年在華山頂上照的照片,在背面寫上“最好的的禮物,就是愛你的Fita”,再到街上禮品店買了個像框(賣禮品的MM也很漂亮哦),再找隔壁搞美術設計的Mike設計了一個漂亮的盒子裝起來……,我們都是Decorator,最終都在修飾我這個人呀,怎么樣,看懂了嗎?

        裝飾模式:裝飾模式以對客戶端透明的方式擴展對象的功能,是繼承關系的一個替代方案,提供比繼承更多的靈活性。動態給一個 對象增加功能,這些功能可以再動態的撤消。增加由一些基本功能的排列組合而產生的非常大量的功能。

            10、FA?ADE—我有一個專業的Nikon相機,我就喜歡自己手動調光圈、快門,這樣照出來的照片才專業,但MM可不懂這些,教了半天也不會。幸好相機有Fa?ade設計模式,把相機調整到自動檔,只要對準目標按快門就行了,一切由相機自動調整,這樣MM也可以用這個相機給我拍張照片了。

        門面模式:外部與一個子系統的通信必須通過一個統一的門面對象進行。門面模式提供一個高層次的接口,使得子系統更易于使用 。每一個子系統只有一個門面類,而且此門面類只有一個實例,也就是說它是一個單例模式。但整個系統可以有多個門面類。

      11、FLYWEIGHT—每天跟MM發短信,手指都累死了,最近買了個新手機,可以把一些常用的句子存在手機里,要用的時候,直接拿出來,在前面加上MM的名字就可以發送了,再不用一個字一個字敲了。共享的句子就是Flyweight,MM的名字就是提取出來的外部特征,根據上下文情況使用。

        享元模式:FLYWEIGHT在拳擊比賽中指最輕量級。享元模式以共享的方式高效的支持大量的細粒度對象。享元模式能做到共享的關鍵是區分內蘊狀態和外蘊狀態。內蘊狀態存儲在享元內部,不會隨環境的改變而有所不同。外蘊狀態是隨環境的改變而改變的。外蘊狀態不能影響內蘊狀態,它們是相互獨立的。將可以共享的狀態和不可以共享的狀態從常規類中區分開來,將不可以共享的狀態從類里剔除出去。客戶端不可以直接創建被共享的對象,而應當使用一個工廠對象負責創建被共享的對象。享元模式大幅度的降低內存中對象的數量。

      12、PROXY—跟MM在網上聊天,一開頭總是“hi,你好”,“你從哪兒來呀?”“你多大了?”“身高多少呀?”這些話,真煩人,寫個程序 做為我的Proxy吧,凡是接收到這些話都設置好了自動的回答,接收到其他的話時再通知我回答,怎么樣,酷吧。

        代理模式:代理模式給某一個對象提供一個代理對象,并由代理對象控制對源對象的引用。代理就是一個人或一個機構代表另一個人或者一個機構采取行動。某些情況下,客戶不想或者不能夠直接引用一個對象,代理對象可以在客戶和目標對象直接起到中介的作用。客戶端分辨不出代理主題對象與真實主題對象。代理模式可以并不知道真正的被代理對象,而僅僅持有一個被代理對象的接口,這時候代理對象不能夠創建被代理對象,被代理對象必須有系統的其他角色代為創建并傳入。

    以下是引用片段:
    public interface FactoryProxy{
    public People createBoy();
    public People creteGirl();
    }


    13、CHAIN OF RESPONSIBLEITY—晚上去上英語課,為了好開溜坐到了最后一排,哇,前面坐了好幾個漂亮的MM哎,找張紙條,寫上 “Hi,可以做我的女朋友嗎?如果不愿意請向前傳”,紙條就一個接一個的傳上去了,糟糕,傳到第一排的MM把紙條傳給老師了,聽說是個老處女呀,快跑!

        責任鏈模式:在責任鏈模式中,很多對象由每一個對象對其下家的引用而接

        起來形成一條鏈。請求在這個鏈上傳遞,直到鏈上的某一個對象決定處理此請求。客戶并不知道鏈上的哪一個對象最終處理這個請求,系統可以在不影響客戶端的情況下動態的重新組織鏈和分配責任。處理者有兩個選擇:承擔責任或者把責任推給下家。一個請求可以最終不被任何接收端對象所接受。

      14、COMMAND—俺有一個MM家里管得特別嚴,沒法見面,只好借助于她弟弟在我們倆之間傳送信息,她對我有什么指示,就寫一張紙條讓她弟弟帶給我。這不,她弟弟又傳送過來一個COMMAND,為了感謝他,我請他吃了碗雜醬面,哪知道他說:“我同時給我姐姐三個男朋友送 COMMAND,就數你最小氣,才請我吃面。”,

        命令模式:命令模式把一個請求或者操作封裝到一個對象中。命令模式把發出命令的責任和執行命令的責任分割開,委派給不同的對象。命令模式允許請求的一方和發送的一方獨立開來,使得請求的一方不必知道接收請求的一方的接口,更不必知道請求是怎么被接收,以及操作是否執行,何時被執行以及是怎么被執行的。系統支持命令的撤消。


            15、INTERPRETER—俺有一個《泡MM真經》,上面有各種泡MM的攻略,比如說去吃西餐的步驟、去看電影的方法等等,跟MM約會時,只 要做一個Interpreter,照著上面的腳本執行就可以了。

        解釋器模式:給定一個語言后,解釋器模式可以定義出其文法的一種表示,并同時提供一個解釋器。客戶端可以使用這個解釋器來解釋這個語言中的句子。解釋器模式將描述怎樣在有了一個簡單的文法后,使用模式設計解釋這些語句。在解釋器模式里面提到的語言是指任何解釋器對象能夠解釋的任何組合。在解釋器模式中需要定義一個代表文法的命令類的等級結構,也就是一系列的組合規則。每一個命令對象都有一個解釋方法,代表對命令對象的解釋。命令對象的等級結構中的對象的任何排列組合都是一個語言。

      16、ITERATOR—我愛上了Mary,不顧一切的向她求婚。

        Mary:“想要我跟你結婚,得答應我的條件”

        我:“什么條件我都答應,你說吧”

        Mary:“我看上了那個一克拉的鉆石”

        我:“我買,我買,還有嗎?”

        Mary:“我看上了湖邊的那棟別墅”

        我:“我買,我買,還有嗎?”

        Mary:“我看上那輛法拉利跑車”

        我腦袋嗡的一聲,坐在椅子上,一咬牙:“我買,我買,還有嗎?”

        ……

        迭代子模式:迭代子模式可以順序訪問一個聚集中的元素而不必暴露聚集的內部表象。多個對象聚在一起形成的總體稱之為聚集,聚集對象是能夠包容一組對象的容器對象。迭代子模式將迭代邏輯封裝到一個獨立的子對象中,從而與聚集本身隔開。迭代子模式簡化了聚集的界面。每一個聚集對象都可以有一個或一個以上的迭代子對象,每一個迭代子的迭代狀態可以是彼此獨立的。迭代算法可以獨立于聚集角色 變化。

      17、MEDIATOR—四個MM打麻將,相互之間誰應該給誰多少錢算不清楚了,幸虧當時我在旁邊,按照各自的籌碼數算錢,賺了錢的從我這 里拿,賠了錢的也付給我,一切就OK啦,俺得到了四個MM的電話。

        調停者模式:調停者模式包裝了一系列對象相互作用的方式,使得這些對象不必相互明顯作用。從而使他們可以松散偶合。當某些對象之間的作用發生改變時,不會立即影響其他的一些對象之間的作用。保證這些作用可以彼此獨立的變化。調停者模式將多對多的相互作用轉化為一對多的相互作用。調停者模式將對象的行為和協作抽象化,把對象在小尺度的行為上與其他對象的相互作用分開處理。

      18、MEMENTO—同時跟幾個MM聊天時,一定要記清楚剛才跟MM說了些什么話,不然MM發現了會不高興的哦,幸虧我有個備忘錄,剛才與 哪個MM說了什么話我都拷貝一份放到備忘錄里面保存,這樣可以隨時察看以前的記錄啦。

        備忘錄模式:備忘錄對象是一個用來存儲另外一個對象內部狀態的快照的對象。備忘錄模式的用意是在不破壞封裝的條件下,將一 個對象的狀態捉住,并外部化,存儲起來,從而可以在將來合適的時候把這個對象還原到存儲起來的狀態。

      19、OBSERVER—想知道咱們公司最新MM情報嗎?加入公司的MM情報郵件組就行了,tom負責搜集情報,他發現的新情報不用一個一個通知 我們,直接發布給郵件組,我們作為訂閱者(觀察者)就可以及時收到情報啦

      觀察者模式:觀察者模式定義了一種一隊多的依賴關系,讓多個觀察者對象同時監聽某一個主題對象。這個主題對象在狀態上發生 變化時,會通知所有觀察者對象,使他們能夠自動更新自己。

             20、STATE—跟MM交往時,一定要注意她的狀態哦,在不同的狀態時她的行為會有不同,比如你約她今天晚上去看電影,對你沒興趣的 MM就會說“有事情啦”,對你不討厭但還沒喜歡上的MM就會說“好啊,不過可以帶上我同事么?”,已經喜歡上你的MM就會說“幾點鐘?看完電影再去泡吧怎么樣?”,當然你看電影過程中表現良好的話,也可以把MM的狀態從不討厭不喜歡變成喜歡哦。

        狀態模式:狀態模式允許一個對象在其內部狀態改變的時候改變行為。這個對象看上去象是改變了它的類一樣。狀態模式把所研究的對象的行為包裝在不同的狀態對象里,每一個狀態對象都屬于一個抽象狀態類的一個子類。狀態模式的意圖是讓一個對象在其內部狀態改變的時候,其行為也隨之改變。狀態模式需要對每一個系統可能取得的狀態創立一個狀態類的子類。當系統的狀態變化時,系統便改變所選的子 類。

      21、STRATEGY—跟不同類型的MM約會,要用不同的策略,有的請電影比較好,有的則去吃小吃效果不錯,有的去海邊浪漫最合適,單目 的都是為了得到MM的芳心,我的追MM錦囊中有好多Strategy哦。

        策略模式:策略模式針對一組算法,將每一個算法封裝到具有共同接口的獨立的類中,從而使得它們可以相互替換。策略模式使得算法可以在不影響到客戶端的情況下發生變化。策略模式把行為和環境分開。環境類負責維持和查詢行為類,各種算法在具體的策略類中提供。由于算法和環境獨立開來,算法的增減,修改都不會影響到環境和客戶端。

      22、TEMPLATE METHOD——看過《如何說服女生上床》這部經典文章嗎?女生從認識到上床的不變的步驟分為巧遇、打破僵局、展開追求、接吻、前戲、動手、愛撫、進去八大步驟(Template method),但每個步驟針對不同的情況,都有不一樣的做法,這就要看你隨機應變啦(具體實現);

        模板方法模式:模板方法模式準備一個抽象類,將部分邏輯以具體方法以及具體構造子的形式實現,然后聲明一些抽象方法來迫使子類實現剩余的邏輯。不同的子類可以以不同的方式實現這些抽象方法,從而對剩余的邏輯有不同的實現。先制定一個頂級邏輯框架,而將邏輯的細節留給具體的子類去實現。

      23、VISITOR—情人節到了,要給每個MM送一束鮮花和一張卡片,可是每個MM送的花都要針對她個人的特點,每張卡片也要根據個人的特點來挑,我一個人哪搞得清楚,還是找花店老板和禮品店老板做一下Visitor,讓花店老板根據MM的特點選一束花,讓禮品店老板也根據每個人特點選一張卡,這樣就輕松多了;  

        訪問者模式:訪問者模式的目的是封裝一些施加于某種數據結構元素之上的操作。一旦這些操作需要修改的話,接受這個操作的數據結構可以保持不變。訪問者模式適用于數據結構相對未定的系統,它把數據結構和作用于結構上的操作之間的耦合解脫開,使得操作集合可以相對自由的演化。訪問者模式使得增加新的操作變的很容易,就是增加一個新的訪問者類。訪問者模式將有關的行為集中到一個訪問者對象中,而不是分散到一個個的節點類中。當使用訪問者模式時,要將盡可能多的對象瀏覽邏輯放在訪問者類中,而不是放到它的子類中。訪問者模式可以跨過幾個類的等級結構訪問屬于不同的等級結構的成員類。

     

    posted @ 2010-01-04 16:48 AK47 閱讀(250) | 評論 (0)編輯 收藏

    <2010年1月>
    272829303112
    3456789
    10111213141516
    17181920212223
    24252627282930
    31123456

    導航

    統計

    常用鏈接

    留言簿

    隨筆分類

    隨筆檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 精品国产亚洲男女在线线电影| 亚洲成AⅤ人影院在线观看| 亚洲一卡二卡三卡四卡无卡麻豆| a高清免费毛片久久| 亚洲Av无码乱码在线播放| 在线观看亚洲网站| 国产男女猛烈无遮挡免费视频| 亚洲夂夂婷婷色拍WW47| 免费可以在线看A∨网站| 激情亚洲一区国产精品| 大地资源免费更新在线播放| 在线亚洲高清揄拍自拍一品区| 国产精品成人免费一区二区 | 亚洲欧好州第一的日产suv| 久久久www成人免费毛片| 亚洲熟妇无码AV不卡在线播放| 成年人免费视频观看| 亚洲国产精品无码久久久秋霞1| 日本一道高清不卡免费| 国产亚洲精品美女| 亚洲中久无码不卡永久在线观看| 日韩在线一区二区三区免费视频| 亚洲综合色在线观看亚洲| eeuss影院www天堂免费| 亚洲国产精品无码中文字| 久久精品免费观看国产| 国产白丝无码免费视频| 日本h在线精品免费观看| 亚洲人成高清在线播放| 成人免费无毒在线观看网站 | 欧洲精品免费一区二区三区| 在线观看亚洲专区| 亚洲无码精品浪潮| 日本高清免费观看| 亚洲女人18毛片水真多| 岛国片在线免费观看| 免费国产在线精品一区 | 久久免费精品视频| 亚洲欧洲日韩国产| 国内自产拍自a免费毛片| 人人爽人人爽人人片A免费|