初學(xué)者可能會想反射是什么,有什么作用。那我就以一個簡單的小需求開始。現(xiàn)在有
3個類,A,B,C. 現(xiàn)在我想要一個方法,根據(jù)輸入的字符串,獲取相應(yīng)的實例對象,即當(dāng)我給這個對象傳入“A”的時候,我要獲取一個A實例,傳入“B”的時候獲取一個B實例,有人說用if, 那么如果有1000個類,就用1000個if或者case么,而且,如果不事先知道有多少種情況呢?
要解決這個問題,我們先從基礎(chǔ)知識開始學(xué)習(xí)。
在Java程序執(zhí)行的時候,在這個進(jìn)程中,內(nèi)存分為代碼區(qū),靜態(tài)存儲區(qū),堆內(nèi)存和棧內(nèi)存。一些基本類型的變量和對象的引用變量都是在函數(shù)的棧內(nèi)存中分配。當(dāng)在一段代碼塊中定義一個變量時,java就在棧中為這個變量分配內(nèi)存空間,當(dāng)超過變量的作用域后,java會自動釋放掉為該變量分配的內(nèi)存空間,該內(nèi)存空間可以立刻被另作他用。堆內(nèi)存用于存放由new創(chuàng)建的對象和數(shù)組。在堆中分配的內(nèi)存,由java虛擬機(jī)自動垃圾回收器來管理。靜態(tài)存儲區(qū),主要是用來存儲字符串和類的靜態(tài)成員變量等。現(xiàn)在說到了對于反射來講很重要的一塊內(nèi)存,代碼區(qū)(CodeSegment)。代碼區(qū)主要存放的是加載到內(nèi)存的二進(jìn)制文件。注意,這不是對象實例,而是那些一個個還沒有被喚醒的.class文件。
從面相對象的角度來講,這些文件都是一類,都是Class類。至于如何理解.class文件對象和實例對象,我是這樣理解的。在代碼區(qū)的.class對象就像是下載視頻的種子,雖然它并不是一個實實在在的視頻,但是必須要通過這個種子才能獲得視頻文件,而且一個種子可以使用多次。相對應(yīng)的,在程序中.class文件對象,要通過這個對象來獲取需要的對象,而且能多次使用。
在Java虛擬機(jī)中,有一個很重要的搬運工的角色,就是ClassLoader,這是一大類Class,它們的作用就是把相應(yīng)的用到的二進(jìn)制的Class文件加載到內(nèi)存中。注意,這里有一個動態(tài)的加載機(jī)制,不是說,在程序啟動的時候,如果ClassPath下有100個.class文件,就會把所有的二進(jìn)制碼一下子加載到內(nèi)存中,而是剛剛開始的時候JVM使用ClassLoader把最初的幾個.class二進(jìn)制碼Load到內(nèi)存中,之后的是用到的時候才加載,慢慢的會有更多的加載到存中。當(dāng)然也可以通過代碼顯示的要求立即把相應(yīng)的二進(jìn)制類代碼加載到內(nèi)存,如JDBC驅(qū)動的加載 Class.forName("com.mysql.jdbc.Driver")
在這里有一個相關(guān)的知識點就是static靜態(tài)語句塊的問題。有人說,靜態(tài)語句塊是第一次new對象的時候執(zhí)行,這種說法是不準(zhǔn)確的,確切的說,是加載到內(nèi)存中的時候執(zhí)行。一般來講我們自己寫的類,是用的時候才加載到內(nèi)存,而我們用的方式,一般都是new一個對象,一般不會強(qiáng)制顯示的去加載,所以,大家就以為是第一次實例化的時候執(zhí)行。如果我們使用Class.Forname顯示的把它load到內(nèi)存,而并不new對象,可以發(fā)現(xiàn),此時靜態(tài)代碼塊也執(zhí)行了。
現(xiàn)在解決最初提出的那個問題,只需要一句代碼
String type = “A”;
Object o = Class.forName(type).newInstance();
下面是有關(guān)反射使用的一些常用的方法,包括獲取成員方法等。從面相對象的角度看,類中的一個個屬性或者方法都是對象,要讓其執(zhí)行,調(diào)用invoke就可以了。
minValue : 1,
xtype : 'numberfield',
regex: /^\d+$/,//驗證數(shù)字
目前Servlet2.4和JSP2.0總共有8個監(jiān)聽器接口和6個Event類,其中 HttpSessionAttributeListener與HttpSessionBindingListener皆使用 HttpSessionBindingEvent;HttpSessionListener和 HttpSessionActivationListener則都使用HttpSessionEvent;其余Listener對應(yīng)的Event如下所 示:
Listener接口 | Event類 |
ServletContextListener | ServletContextEvent |
ServletContextAttributeListener | ServletContextAttributeEvent |
HttpSessionListener | HttpSessionEvent |
HttpSessionActivationListener |
HttpSessionAttributeListener | HttpSessionBindingEvent |
HttpSessionBindingListener |
ServletRequestListener | ServletRequestEvent |
ServletRequestAttributeListener | ServletRequestAttributeEvent |
分別介紹:
一 ServletContext相關(guān)監(jiān)聽接口
補(bǔ)充知識:
通過ServletContext 的實例可以存取應(yīng)用程序的全局對象以及初始化階段的變量。
在JSP文件中,application 是 ServletContext 的實例,由JSP容器默認(rèn)創(chuàng)建。Servlet 中調(diào)用 getServletContext()方法得到 ServletContext 的實例。
注意:
全局對象即Application范圍對象,初始化階段的變量指在web.xml中,經(jīng)由<context-param>元素所設(shè)定的變量,它的范圍也是Application范圍,例如:
<context-param>
<param-name>Name</param-name>
<param-value>browser</param-value>
</context-param>
當(dāng)容器啟動時,會建立一個Application范圍的對象,若要在JSP網(wǎng)頁中取得此變量時:
String name = (String)application.getInitParameter("Name");
或者使用EL時:
${initPara.name}
若是在Servlet中,取得Name的值方法:
String name = (String)ServletContext.getInitParameter("Name");
1.ServletContextListener:
用于監(jiān)聽WEB 應(yīng)用啟動和銷毀的事件,監(jiān)聽器類需要實現(xiàn)javax.servlet.ServletContextListener 接口。
ServletContextListener 是 ServletContext 的監(jiān)聽者,如果 ServletContext 發(fā)生變化,如服務(wù)器啟動時 ServletContext 被創(chuàng)建,服務(wù)器關(guān)閉時 ServletContext 將要被銷毀。
ServletContextListener接口的方法:
void contextInitialized(ServletContextEvent sce)
通知正在接受的對象,應(yīng)用程序已經(jīng)被加載及初始化。
void contextDestroyed(ServletContextEvent sce)
通知正在接受的對象,應(yīng)用程序已經(jīng)被載出。
ServletContextEvent中的方法:
ServletContext getServletContext()
取得ServletContext對象
2.ServletContextAttributeListener:用于監(jiān)聽WEB應(yīng)用屬性改變的事件,包括:增加屬性、刪除屬性、修改屬性,監(jiān)聽器類需要實現(xiàn)javax.servlet.ServletContextAttributeListener接口。
ServletContextAttributeListener接口方法:
void attributeAdded(ServletContextAttributeEvent scab)
若有對象加入Application的范圍,通知正在收聽的對象
void attributeRemoved(ServletContextAttributeEvent scab)
若有對象從Application的范圍移除,通知正在收聽的對象
void attributeReplaced(ServletContextAttributeEvent scab)
若在Application的范圍中,有對象取代另一個對象時,通知正在收聽的對象
ServletContextAttributeEvent中的方法:
java.lang.String getName()
回傳屬性的名稱
java.lang.Object getValue()
回傳屬性的值
二、HttpSession相關(guān)監(jiān)聽接口
1.HttpSessionBindingListener接口
注意:HttpSessionBindingListener接口是唯一不需要再web.xml中設(shè)定的Listener
當(dāng)我們的類實現(xiàn)了HttpSessionBindingListener接口后,只要對象加入Session范圍 (即調(diào)用HttpSession對象的setAttribute方法的時候)或從Session范圍中移出(即調(diào)用HttpSession對象的 removeAttribute方法的時候或Session Time out的時候)時,容器分別會自動調(diào)用下列兩個方法:
void valueBound(HttpSessionBindingEvent event)
void valueUnbound(HttpSessionBindingEvent event)
思考:如何實現(xiàn)記錄網(wǎng)站的客戶登錄日志, 統(tǒng)計在線人數(shù)?
2.HttpSessionAttributeListener接口
HttpSessionAttributeListener監(jiān)聽HttpSession中的屬性的操作。
當(dāng)在Session增加一個屬性時,激發(fā)attributeAdded(HttpSessionBindingEvent se) 方法;當(dāng)在Session刪除一個屬性時,激發(fā)attributeRemoved(HttpSessionBindingEvent se)方法;當(dāng)在Session屬性被重新設(shè)置時,激發(fā)attributeReplaced(HttpSessionBindingEvent se) 方法。這和ServletContextAttributeListener比較類似。
3.HttpSessionListener接口
HttpSessionListener監(jiān)聽HttpSession的操作。當(dāng)創(chuàng)建一個Session時,激發(fā)session Created(HttpSessionEvent se)方法;當(dāng)銷毀一個Session時,激發(fā)sessionDestroyed (HttpSessionEvent se)方法。
4.HttpSessionActivationListener接口
主要用于同一個Session轉(zhuǎn)移至不同的JVM的情形。
四、ServletRequest監(jiān)聽接口
1.ServletRequestListener接口
和ServletContextListener接口類似的,這里由ServletContext改為ServletRequest
2.ServletRequestAttributeListener接口
和ServletContextListener接口類似的,這里由ServletContext改為ServletRequest
1.新建類繼承Thread,
2.把此類交給spring管理
<bean id="b" class="" init-method="start" />
當(dāng)系統(tǒng)啟動時就可以了
var url = window.location.href;
新建一個java類,實現(xiàn)
ServletContextListener
接口,在web.xml中配置
<listener>
<listener-class>類的完全限定名</listener-class>
</listener>
方法1.例如:
StringBuffer sql = new StringBuffer();
sql.append("from Book b where 1=1 ");
if(!"".equals(sum)&&sum!=null){
sql.append(" and b.sum ='"+sum+"'");
}
if(!"".equals(aut)&&aut!=null){
sql.append(" and b.author ='"+aut+"'");
}
if(!"".equals(pub)&&pub!=null){
sql.append(" and b.publish ='"+pub+"'");
}
if(!"".equals(rfid)&&rfid!=null){
sql.append(" and b.addRfidSum ='"+rfid+"'");
}
方法2.
StringBuffer sql = new StringBuffer();
sql.append("from Book b where ");
if(!"".equals(sum)&&sum!=null){
sql.append(" b.sum ='"+sum+"' and ");
}
if(!"".equals(aut)&&aut!=null){
sql.append(" b.author ='"+aut+"' and ");
}
if(!"".equals(pub)&&pub!=null){
sql.append(" b.publish ='"+pub+"' and ");
}
if(!"".equals(rfid)&&rfid!=null){
sql.append(" b.addRfidSum ='"+rfid+"' and ");
}
String s = sql.toString();
s=s.substring(0,s.lastIndexOf(" and ")>0? s.lastIndexOf(" and "):s.indexOf("where"));
System.out.println(s);
當(dāng)心在單引號和雙引號中間不要有空格,不然會出錯
WebContext context = WebContextManager.get();
HttpSession session = context.getSession();
ServletContext application = context.getServletContext();
context.getRequest();
context.getResponse();
String s = "2012-08-25";
SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd");
SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy年M月d日");
try {
System.out.println(sdf2.format(sdf1.parse(s)));
} catch (ParseException e) {
e.printStackTrace();
}
根據(jù)有道的API 先根據(jù)IP確定城市 在根據(jù)城市獲取天氣