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>
将项目部署到Tomcat上
http://localhost:8080/TestWeb/input_do.jsp
可以看到服务器控制台会执行构造方法
反射的特点非常明显:它必须明确的写上包.类名。实例化操作的目的主要是为了接受请求参数
定义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
/* 输出结果:
sun.misc.Launcher$AppClassLoader@62b92dc2
sun.misc.Launcher$ExtClassLoader@6b6b4e30
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了。这一操作对于实际开发意义并不大。