初识JavaBean
什么是JavaBean访问JavaBean的属性 反射
认识Class类通过反射创建对象
通过无参构造方法实例化对象通过有参构造方法实例化对象 通过反射访问属性通过反射调用方法 内省
什么是内省修改JavaBean属性读取JavaBean的属性 JSP标签访问JavaBean
< jsp:useBean>
单独使用class属性单独使用type属性beanName属性和type属性相结合使用 < jsp:setProperty>标签
property属性单独使用 < jsp:getProperty>标签
初识JavaBean 什么是JavaBeanJavaBean是Java开发语言中一个重复使用的软件组件,他本质是一个Java类。
JavaBean编码规范为:
(1)他必须具有一个公共的、无参的构造方法,这个方法可以是编译器自动产生的默认构造方法。
(2)它提供公共的setter方法和getter方法让外部程序设置和获取JavaBean的属性。
在JavaBean中属性和成员变量不是一个概念,它是以方法定义的形式出现的,这些方法必须遵循一定的命名规范。
例如:JavaBean中包含一个String类型的name属性,那么在JavaBean中必须至少包含getName()和setName()方法中的一个,这两个方法的声明如下所示:
public String getName(); public String setName(String name);
(1)getName()方法:
称为getter方法或者属性访问器,该方法以小写的get前缀开始,后跟属性名,属性名的第一个字母要大写。
(2)setName()方法
称为setter方法或者属性修改器该方法必须以小写的set前缀开始后跟属性名,属性名的第一个字母要大写。
如果一个属性只有getter方法,则该属性为只读属性,如果一个属性只有setter则该属性为只写属性,如果既有getter方法也有setter方法,则该属性为读写属性,通常来说在开发JavaBean时,其属性都定义为读写属性。
如果一个属性类型为Boolean,那么它的命名方式为is/get而不是set/get。
Java反射的源头是Class类,一般情况下需要先有一个类的完整路径引入后,才可以按照固定的格式产生示例化对象,但是在Java中允许通过一个水利化对象找到一个类的完整信息,这就是Class类的作用。
示例:
package cn.itcast.chapter04.servlet;
class X{}
public class Student {
public static void main(String[] args){
X x=new X();
System.out.println(x.getClass().getName());
}
}
程序输出了对象所在的完整的“包.类”的名称,对象x调用了getClass()方法,该方法是从Object类中继承来的,此方法的定义为:
public final Class>getClass()
该方法的返回值是一个Class类,Class类表示一个类的本身,同过Class可以完整地得到一个类中的结构,包括此类中的方法定义、属性定义等。Class类中常用的方法:
| 方法声明 | 功能描述 |
|---|---|
| static Class > forName(String className) | 返回与带有给定字符串名或类接口相关联的Class对象 |
| Constructor>[]getConstructors() | 返回一个包含某些Constructor对象的数组,这些对象反映此Class对象所表示类的所有公共构造方法 |
| Field[] getDeclaredField(String name) | 返回包含某些Field对象的数组,这些对象反映此Class对象所表示的类或接口所声明的所有字段。 |
| Field[] getFields() | 返回一个包含某些Field对象的数组,这些对象反映此Class对象所标识的类或借口的所有可访问公共字段,包括继承的公共字段 |
| Method[] getMethod() | 返回一个包含某些Method对象的数组,这些对象反映此Class对象锁表是的类或接口的公共成员方法。 |
| Method getMethod(String name,Class>…parameterTypes) | 返回一个Method对象,反映此Class对象所表示的类或接口实现的接口 |
| Class>[] getInterfaces() | 返回该类所实现的接口的一个数组,确定此对象所表示的类或接口实现的接口 |
| String getName() | 以String的形式返回次Class对象所标识的实体名称 |
| Package getPackage() | 获取此类的包 |
| Class super T> getsuperclass() | 返回此Class所表示的实体的超类的Class |
| T newInstance() | 创建此Class对象所表示类的一个新实例 |
| booleanisArray() | 判定此Class对象是否表示一个数组类 |
在Class类中本身没有定义非私有的构造方法,因此不能通过new直接创建Class类的实例,获得Class类的实例有3中方式:
(1)通过“对象.getClass()”方式获取该对象的Class实例。
(2)通过Class类的静态方法forName(),用类的全路径名获取一个Class实例。
(3)通过“类名.class”的方式来获取Class实例,对于基本数据类型的封装类,还可以采用.TYPE来获取相对应的基本数据类型的Class实例。
当时用构造方法创建对象时,构造方法可以是有参的也可以是无参的。
通过无参构造方法实例化对象如果想通过Class类本身实例化其他类的对象,那么可以使用newInstance()方法,但是必须要保证被实例化的类中存在一个无参构造方法。
例:
package cn.itcast.chapter04.servlet;
class Person{
private String name;
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
public String toString(){
return"姓名:"+this.name+",年龄:"+this.age;
}
}
public class ReflectDemo01 {
public static void main(String[] args)throws Exception{
Class clazz=Class.forName("cn.itcast.chapter04.servlet.Person");
Person p=(Person)clazz.newInstance();
p.setName("张三");
p.setAge(18);
System.out.print(p);
}
}
通过有参构造方法实例化对象
通过有参构造方法实例化对象有三个步骤:
(1)通过Class类的getConstructors()获取本类中的全部构造方法。
(2)向构造方法中传递一个对象数组进去,里面包含构造方法中所需的各个参数。
(3)通过Constructor类实例化对象。
Constructor常用的方法:
| 方法声明 | 功能描述 |
|---|---|
| int getModifiles() | 获取构造方法的修饰符 |
| String getName() | 获得构造方法的名称 |
| Class >[] getParameterTypes() | 获取构造方法中的参数类型 |
| T newInstance(Object…intargs) | 向构造方法中传递参数,实例化对象 |
示例:
package cn.itcast.chapter04.servlet;
import java.lang.reflect.Constructor;
class Person{
private String name;
private int age;
public Person(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
public String toString(){
return"姓名:"+this.name+",年龄:"+this.age;
}
}
public class ReflectDemo01 {
public static void main(String[] args)throws Exception{
Class clazz=Class.forName("cn.itcast.chapter04.servlet.Person");
Constructor cons[]=clazz.getConstructors();
Person p=(Person)cons[0].newInstance("张三",30);
System.out.print(p);
}
}
通过反射访问属性
通过反射不仅可以创建对象,还可以访问属性,在反射机制中,属性的操作是通过Filed类实现的,它提供的set()和get()方法分别作用与设置和获取属性,如果访问的属性时私有的,需要在使用set()和get()方法前,使用Filed类中的setAccessible()方法将需要操作的属性设置成可以被外界访问的。
示例:
package cn.itcast.chapter04.servlet;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
class Person{
private String name;
private int age;
public String toString(){
return"姓名:"+this.name+",年龄:"+this.age;
}
}
public class ReflectDemo01 {
public static void main(String[] args)throws Exception{
Class clazz=Class.forName("cn.itcast.chapter04.servlet.Person");
Object p=clazz.newInstance();
Field nameField=clazz.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(p, "李四");
Field ageField=clazz.getDeclaredField("age");
ageField.setAccessible(true);
ageField.set(p, 20);
System.out.print(p);
}
}
通过反射调用方法
当获得某个类对应的Class对象后,可以通过Class对象的getMethods()方法和getMethod()方法获取全部方法或者制定方法,getMethod方法返回值是Method对象,getMethods方法返回值是Method对象数组。在Method里包含一个invoke()方法,该方法定义为:
public Object invoke(Object obj,object args....);
上述方法中obj是该方法主要参数,args是一个相当于数组的可变参数,用来接收传入的实参。
示例:
package cn.itcast.chapter04.servlet;
import java.lang.reflect.Method;
class Person{
private String name;
private int age;
public String sayHello(String name,int age){
return "姓名:"+name+",年龄:"+age;
}
}
public class ReflectDemo01 {
public static void main(String[] args)throws Exception{
Class clazz=Class.forName("cn.itcast.chapter04.servlet.Person");
Method md=clazz.getMethod("sayHello", String.class,int.class);
String result=(String)md.invoke(clazz.newInstance(), "张三",35);
System.out.print(result);
}
}
内省
什么是内省
JDK提供了一套API用来访问某个属性的getter和setter方法,这就是内省。
内省访问JavaBean有两种方法:
(1)先通过java.beans包下的Instrospector类获得JavaBean对象的BeanInfo信息,再通过BeanInfo获取属性的描述器,然后通过这个属性描述器就可以获取某个属性对应的getter和setter方法,最后通过反射机制来调用这些方法。
(2)直接通过java.beans包下的PropertyDescriptor类来操作Bean对象。
示例:
Person.java
package JavaBean;
public class Person {
private String name;
private int age;
public String getName(){
return name;
}
public void setName(String name){
this.name=name;
}
public int getAge(){
return age;
}
public void setAge(int age){
this.age=age;
}
public String sayHello(){
return "姓名:"+this.name+",年龄:"+this.age;
}
}
Introspector01.java
package JavaBean;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import JavaBean.Person;
public class Introspector01 {
public static void main(String[] args)throws Exception{
Person beanObj=new Person();
BeanInfo bInfoObject=Introspector.getBeanInfo(beanObj.getClass());
beanObj.getClass().getSuperclass();
String str="内省成员属性:n";
PropertyDescriptor[] mPropertyArry=bInfoObject.getPropertyDescriptors();
for(int i=0;i
修改JavaBean属性
在java中,还可以通过内省来修改JavaBean属性
示例:
package JavaBean;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import JavaBean.Person;
public class Introspector01 {
public static void main(String[] args)throws Exception{
Person p=new Person();
PropertyDescriptor pd=new PropertyDescriptor("name",p.getClass());
Method methodName=pd.getWriteMethod();
methodName.invoke(p, "小明");
String val="20";
pd=new PropertyDescriptor("age",p.getClass());
Method methodAge=pd.getWriteMethod();
Class clazz=pd.getPropertyType();
if(clazz.equals(int.class)){
methodAge.invoke(p, Integer.valueOf(val));
}else{
methodAge.invoke(p, val);
}
System.out.println(p);
}
}
读取JavaBean的属性
使用PropertyDescriptor类的getWriteMethod()方法可以获取属性对应的setter方法,在JavaBean中属性getter和setter是成对出现的,因此java的内省也提供了读取JavaBean属性的方法,只要使用PropertyDescriptor类的getMethod()方法。
示例:
package JavaBean;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import JavaBean.Person;
public class Introspector01 {
public static void main(String[] args)throws Exception{
Person p=new Person();
p.setName("李芳");
p.setAge(18);
PropertyDescriptor pd=new PropertyDescriptor("name",p.getClass());
Method methodName=pd.getReadMethod();
Object o=methodName.invoke(p);
System.out.println("姓名"+o);
pd=new PropertyDescriptor("age",p.getClass());
Method methodAge=pd.getReadMethod();
o=methodAge.invoke(p);
System.out.println("年龄"+o);
}
}
JSP标签访问JavaBean
< jsp:useBean>
< jsp:useBean>标签用于在某个指定的域范围中查找一个指定名称的JavaBean对象,如果存在则直接返回JavaBean对象的引用,如果不存在则实例化一个新的JavaBean对象并将它按指定的名称存储在指定的域范围中,语法格式为:
[scope="{page | requst | session | application}]
{
|
type="package.class"|
type="package.class"|
beanName="{package.class|<%=expression>}" type="package.class"
} />
其中有5个属性:
(1)id:用于指定JavaBean实例对象的引用名称和其存储在域范围中的名称
(2)scope:用于指定JavaBean实例对象所存储的域范围,其取值只能是page、request、session、application中的一个,默认值是page。
(3)type:用于指定JavaBean实例对象的引用变量类型,必须是JavaBean对象的类名称、父类名称或将JavaBean实现的接口名称。type属性值默认值是class属性的设置值,当JSP容器将< jsp:useBean>标签翻译成Servlet程序时。他将使用type属性值作为JavaBean对象引入变量的类型。
(4)class:用于指定JavaBean的完整类名,JSP容器将使用这个类名来创建JavaBean的实例对象或作为查找到的JavaBean对象的类型。
(5)beanName:用于指定的JavaBean的名称,它的值是a.b.c,这既可以代表一个类的完整名称,也可以代表a/b/c.ser这样的资源文件。
单独使用class属性
示例:先创建两个JavaBean类Employee和Manager。
Employee:
package login;
public class Employee {
private String company;
public String getCompany(){
return company;
}
public void setCompany(String company){
this.company=company;
}
}
Manager:
package login;
public class Manager {
private double bonus;
public double geBonus(){
return bonus;
}
public void setBonus(double bonus){
this.bonus=bonus;
}
}
useBean.jsp:
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
Insert title here
翻译成的Servlet
单独使用type属性
将上面的< jsp:Bean>标签中的class改成type:
会出现
当只设置type属性时,JSP容器会在指定的域范围中查找以id属性值为名称的JavaBean对象,如果找不到就会抛出异常。
在< jsp:useBean>标签上面写一段JSP脚本片段,为pageContext多加一个域。
<%
pageContext.setAttribute("manager", new login.Manager());
%>
beanName属性和type属性相结合使用
将useBean.jsp中的JSP脚本去掉,对< jsp:useBean>标签进行修改。
翻译成的Servlet文件中的代码为:
< jsp:setProperty>标签
< jsp:setProperty>标签可以用来为JavaBean对象设置属性。语法格式为:
< jsp:setProperty name="beanInstanceName"{
property="propertyName" value="{string |<%=expression%>}"
property="propertyName" param="parameterName" |property="propertyName |*"
}/>
< jsp:setProperty>标签有四个属性。
(1)name:用于指定JavaBean实例对象名称,其值应该和< jsp:useBean>标签的id属性值相同。
(2)property:用于指定JavaBean实例对象的属性名
(3)param:用于指定请求消息中参数的名字
(4)用于指定为JavaBean实例对象的某个属性设置的值,其值可以是字符串也可以是实例对象。
property属性单独使用
(1)property的属性值为JavaBean的属性
当property属性值为JavaBean的一个属性名时,JSP容器会将请求消息中与property属性值同名的参数值赋给JavaBean对应的属性。
示例:
创建一个setProperty.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="GBK"
import="login.Manager"
%>
Insert title here
<%
manager=(Manager)pageContext.getAttribute("manager");
out.write("bonus属性的值为:"+manager.getBonus());
%>
可以看到请求中bonus的值赋给了JavaBean。
如果请求中没有bonus属性,bonus属性值为空字符串,那么JavaBean的值不会被改变。
(2)property的属性值为通配符时
property的属性值为通配符时,JSP容器会在请求消息中查找所有的请求参数,如果有参数和JavaBean对象属性名相同,JSP容器会将参数的值设置为JavaBean对象对应属性的值。
示例:
<%
manager=(Manager)pageContext.getAttribute("manager");
out.write("bonus属性的值为:"+manager.getBonus()+"
");
out.write("company属性的值为:"+manager.getCompany()+"
");
%>
访问http://localhost:9090/chapter05/setProperty.jsp?bonus=800.0&&company=itcast
< jsp:getProperty>标签
如果JavaBean的属性值是一个引用数据类型时,< jsp:getProperty>会调用该对象的toString()方法,如果JavaBean属性时null,< jsp:getProperty>会输出null。语法格式如下:
<< jsp:getProperty name="beanInstanceName" property="PropertyName" />
其中有两个属性:
(1)name用于指定JavaBean实例对象名称。
(2)property用于指定JavaBean的实例对象。
需要注意的是在使用< jsp:getProperty>时,name和property属性都不能省略。



