java-Web對於反射的支援+ClassLoader(三)-非重點
Web對於反射的支援
非重點:
在我們現在的開發之中,假設迴歸到模式一的時代,那麼這個過程裡面重點就是JSP+JavaBean的時代,那麼在這種模式下,使用者需要接受請求的引數,然後將其變成簡單java類,而這一過程JSP本身就已經做了優化。l在JSP裡面提供有三類標籤指令:
1.定義Bean操作(自動利用反射例項化物件):將自動呼叫無參構造例項化物件
<jsp:useBean id="物件名稱" scope="page|request|session|application" class="包.類"></jsp:useBean>
2.設定屬性:(反射呼叫setter)
自動根據引數名稱匹配屬性:
<jsp:setProperty name=""使用的Id名稱 property="*" />
設定指定的屬性內容:
<jsp:setProperty name=""使用的Id名稱 property="屬性" />
將指定的引數設定給指定屬性:
<jsp:setProperty name=""使用的Id名稱 property="屬性" param="引數名稱"/>
將指定的內容設定給指定屬性:
<jsp:setProperty name=""使用的Id名稱 property="屬性" value="內容"/>
3.取得屬性:(反射呼叫getter)
取得指定屬性內容並輸出:
<jsp:getProperty name=""使用的Id名稱 property="屬性名稱" />
- Bean的例項化與屬性設定
為了方便操作需要定義一個簡單java類
範例:
定義一個Emp.java類
@SuppressWarnings("serial")
public class Emp implements Serializable{
private Integer empno;
private String empname;
private double sal;
private Date hiredate;
public Emp(){
}
}
生成構造方法以觀察例項化輸出,同時準備出setter、getter方法
定義一個input_do.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<jsp:useBean id="emp" scope="page" class="com.csii.wanghaoxin.demo.Emp"></jsp:useBean>
<!-- 表示例項化物件 執行無參構造方法 -->
<html>
<head>
<title>javaBean操作</title>
</head>
<body>
</body>
</html>
可以看到伺服器控制檯會執行構造方法
反射的特點非常明顯:它必須明確的寫上包.類名。例項化操作的目的主要是為了接受請求引數
定義input.jsp頁面:
<form action="input_do.jsp" method="post">
編號:<input type="text" name= "empno" id="empno"value="7369"><br>
姓名:<input type="text" name= "empname" id="empname" value="wanghaoxin"><br>
工資:<input type="text" name= "sal" id="sal" value="800.0"><br>
日期:<input type="text" name= "hiredate" id="hiredate" value="1911-11-11"><br>
<input type="submit" value="提交">
<input type="submit" value="重置">
引數的名字和類中的屬性名字是一樣的,但是這不重要,因為可以根據引數名稱找到setter方法的名稱
對於接受頁面。使用自動處理
<jsp:useBean id="emp" scope="page" class="com.csii.wanghaoxin.demo.Emp"></jsp:useBean>
<!-- 表示例項化物件 執行無參構造方法 -->
<jsp:setProperty property="*" name="emp"/>
表示將引數的內容匹配到所有屬性
訪問input.jsp提交,則顯示
Emp [empno=7369, empname=wanghaoxin, sal=800.0, hiredate=null]
控制檯顯示
setEmpno 呼叫,引數為7369
setEmpname 呼叫,引數為wanghaoxin
這個時候的確可以自動賦值,但是其最終的問題也很明顯
1.不支援Date資料的輸入轉換操作
2.缺少中間的驗證環節
可以只給固定引數傳值 比如empname
<jsp:setProperty property="empname" name="emp"/>
把hiredate的值傳給empname
<jsp:setProperty property="empname" name="emp" param = "hiredate" />
設定固定值
<jsp:setProperty property="empname" name="emp" value = "wanghaoxin" />
這種方式已經不適合於現在的開發結構
- 取得屬性內容
如果要取得屬性內容使用的是getProperty();使用的是反射呼叫getter方法
input_do.jsp內容:
<body>
${emp.empno}<br>
<jsp:getProperty property="empname" name="emp"/>
</body>
如果把物件儲存在了屬性範圍之中,直接利用表示式語言就可以方便的進行操作了,這樣就沒必要使用了
總結
簡單java類從最初就已經存在於專案開發裡面。*ClassLoader
如果要說反射機制,肯定就是Class類,但是Class類有一個最大的侷限,就是它只能夠載入classPath中的類檔案。
如果現在你想編寫更加靈活的內容,例如:有些核心的類是在伺服器上,不在本地專案的classPath裡邊
實際上現在我們所使用的程式裡面也存在有ClassLoader,在咱們的Class類裡面,提供有ClassLoader的取得
取得ClassLoader類:public ClassLoader getClassLoader()
在ClassLoader裡面也可以得到父的類載入器:
public final ClassLoader getParent()
範例:觀察類載入器
package com.csii.wanghaoxin.demo;
class Student{
}
public class TestClassLoader {
public static void main(String[] args) throws Exception {
Class<?> cls = Class.forName("com.csii.wanghaoxin.demo.Student");
System.out.println(cls.getClassLoader());//取得ClassLoader
System.out.println(cls.getClassLoader().getParent());//取得Class 父類載入器
System.out.println(cls.getClassLoader().getParent().getParent());//null
/* 輸出結果:
[email protected]
[email protected]
null*/
}
}
通過此時的輸出可以發現,在任何類中都存在類載入器。
在java裡面類載入器一共有三種載入器:
Boot、系統類載入器(一般指的就是ClassPath)、擴充套件類載入器。
實際上擴充套件類載入器儲存的目錄(jdk安裝目下):D:\jdk-7-7u80\jre-1.7\lib\ext,如果現在將*.jar檔案儲存在此目錄中那麼也表示一個ClassPath,這個目錄下也可以載入箇中類檔案。
實際上ClassLoader給了使用者一個由任意位置的載入類權利。
在ClassLoader類裡面存在有一個方法,
public Class<?> loadClass(String name)
throws ClassNotFoundException
這個方法表示ClassPath載入類
public class MyClassLoader extends ClassLoader {
public Class<?> getClass(String className) throws Exception{
return super.loadClass(className);
}
}
測試類:
public class TestMyClassLoader {
public static void main(String[] args) throws Exception {
Class<?> cls = new MyClassLoader().getClass("java.util.Date");
System.out.println(cls.newInstance());
}
}
此時的載入方式使用的是系統的CLASSPATH完成的,但是現在的開發絕對不是我們所需要的。因為系統類的載入直接使用Class即可。
因為在我們ClassLoader裡面存在有一個方法:
載入類檔案:
protected final Class
public class TestMyClassLoader {
public static void main(String[] args) throws Exception {
Class<?> cls = new MyClassLoader().getClass("com.csii.wanghaoxin.demo.Student1");
System.out.println(cls.newInstance());
}
}
載入外部class類
package com.csii.wanghaoxin.demo;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
public class MyClassLoader extends ClassLoader {
public Class<?> getClass(String className) throws Exception{
/*return super.loadClass(className);*/
byte data[] = this.loadData();
return super.defineClass(className, data, 0, data.length);
}
public byte[] loadData() throws Exception{//描述的是載入指定的類檔案 用二進位制流的形式
ByteArrayOutputStream bos = new ByteArrayOutputStream();
String file = "D:"+File.separator+"Student1.class";
File fe = new File(file);
InputStream input = new FileInputStream(fe);
int len = 0;
byte[] data = new byte[1024];
while((len= input.read(data))!= -1){
bos.write(data,0,len);
}
byte[] returnData = bos.toByteArray();
input.close();
bos.close();
return returnData;
}
}
用本地檔案載入意義不大,最有意思的是可以通過網路載入。
比如將Student1.class放置在Tomcat D:\Tomcat\webapps\ROOT目錄下
新寫URL呼叫並進行呼叫
public byte[] loadURLData() throws Exception{//描述的是載入指定的類檔案 用二進位制流的形式 --網路
URL url = new URL("http://localhost:8080/Student1.class");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
InputStream input = url.openStream();
int len = 0;
byte[] data = new byte[1024];
while((len= input.read(data))!= -1){
bos.write(data,0,len);
}
byte[] returnData = bos.toByteArray();
input.close();
bos.close();
return returnData;
}
也就是說此時你可以任意編寫類,通過網路載入執行
網路不正常可能造成程式崩潰。
面試題:如果現在定義了一個java.lang.String會如何?會載入嗎?
如果自己定義了一個java.lang.String類,那麼這個類一定不會載入,因為在java中使用了雙親載入機制,如果是系統類一定都由系統類載入器完成,它只能夠載入java本身定義的類,還有一種自定義的類靠擴充套件類載入器進行載入。
為了安全性,所以不會載入。
- ClassLoader總結
ClassLoader給開發者最大的感受就是它的靈活性,不再受限於ClassPath了。這一操作對於實際開發意義並不大。