1 什么是JavaBean?有何特征?
1)符合特定规则的类
2)JavaBean分二类:
a)侠义的JavaBean
.私有的字段(Field)
.对私有字段提供存取方法(读写方法)
b)广义的JavaBean
.私有的字段(Field)
.对私有字段提供存取方法(读写方法)
.数量任意的业务方法
2 内省API(SUN公司开发)站在反射角度
1)在操作JavaBean时,即对JavaBean进入setter和getter操作时
2)属性和getXxxxx()有关,同时必须有返回值
3)任何一个JavaBean都有一个class属性,来自于Object类。
3 访问JavaBean属性的两种方式:
1)直接调用bean的setXXX或getXXX方法。
2)通过内省技术访问(java.beans包提供了内省的API),内省技术访问也提供了两种方式。
·通过PropertyDescriptor类操作Bean的属性
·通过Introspector类获得Bean对象的 BeanInfo,然后通过 BeanInfo 来获取属性的描述器( PropertyDescriptor ),通过这个属性描述器就可以获取某个属性对应的 getter/setter 方法,然后通过反射机制来调用这些方法。
Apache组织开发了一套用于操作JavaBean的API,这套API考虑到了很多实际开发中的应用场景,因此在实际开发中很多程序员使用这套API操作JavaBean,以简化程序代码的编写。
Beanutils工具包的常用类:
BeanUtils
ConvertUtils.register(Converter convert, Class clazz)
自定义转换器
内置转换器
//用SUN提供内省API操作JavaBean属性 public class Demo1 extends Object{ @Test public void test1() throws Exception{ Student s = new Student(); //pd引用Student的name属性 PropertyDescriptor pd = new PropertyDescriptor("name",Student.class); //m = setName() Method m = pd.getWriteMethod(); //s.setName("berry") m.invoke(s,"berry"); //s.getName() m = pd.getReadMethod(); String returnValue = (String) m.invoke(s,null); System.out.println("returnValue="+returnValue); } @Test public void test2() throws Exception{ //BeanInfo表示该Student对象所有的属性情况 BeanInfo bi = Introspector.getBeanInfo(Student.class); //取得Student对象所有属性集合,属性和get 有关系 PropertyDescriptor[] pds = bi.getPropertyDescriptors(); for(PropertyDescriptor pd : pds){ System.out.println(pd.getName()); } } }
package cn.itcast.java.introspector; //侠义JavaBean
public class Student { private String name; public void setName(String name) { this.name = name; } public String getName() { return name; } public int getAge() { return 31; } public String getWC(){ return "WC"; } }
*3 BeanUtils框架/工具(APACHE开源组织开发)
1)BeanUtils框架能够完成内省的一切功能,而且优化
2)BeanUtils框架能够对String<->基本类型自动转化
3)BeanUtils框架自定义转换器: ConvertUtils.register( 转换规则 ,目标对象的Class)
4)向BeanUtils框架注册自定义转换器必须放在bu.setProperty()代码之前
5)使用BeanUtils内置String->Date的转换器: ConvertUtils.register(new DateLocaleConverter(),java.util.Date.class);
//用APACHE提供Bean工具API操作JavaBean类属性 public class Demo1 { @Test public void test1() throws Exception{ Student s = new Student(); BeanUtils bu = new BeanUtils(); /* //向BeanUtils框架注册自定义的转换器(String->java.util.Date) ConvertUtils.register(new Converter(){ public Object convert(Class clazz, Object type) { //参数一:java.util.Date.class(目标类型) //参数二:是传入的参数类型,即java.lang.String String strBirthday = (String) type; SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); try { return sdf.parse(strBirthday); } catch (ParseException e) { e.printStackTrace(); return null; } } },java.util.Date.class); */ ConvertUtils.register(new DateLocaleConverter(),java.util.Date.class); bu.setProperty(s,"name","张三"); bu.setProperty(s,"age","31"); bu.setProperty(s,"birthday","2011-10-09"); String name = bu.getProperty(s,"name"); String age = bu.getProperty(s,"age"); String birthday = bu.getProperty(s,"birthday"); System.out.println("name="+name); System.out.println("age="+age); System.out.println("birthday="+new Date(birthday).toLocaleString()); } } //侠义JavaBean public class Student { private String name; private int age; private Date birthday; public Student(){} 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 Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } }
*4 泛型
1)在编译时,由编译器约束放入集合中的类型
2)在运行时,编译器会擦除原泛型类型
3)泛型二边要么都不使用约束,要么二边约束一致类型,同时二边必须使用引用类型
4)为了与JDK1.4兼容,泛型可以一边有约束,一边无约束
思考:不利用中间变量,将二个数交互
5)当一个类中出大量的泛型方式或属性/字段,此时可以将该类作成泛型类
6)如果使用泛型通配符,只能获取与泛型具体类型无关的信息,例如:长度。
7)有二个类,初学者一定要注意:Collections和Arrays
泛型(Generic) —泛形的作用
JDK5中的泛形允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛形的java程后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
泛形的基本术语,以ArrayList<E>为例:<>念着typeof
ArrayList<E>中的E称为类型参数变量
ArrayList<Integer>中的Integer称为实际类型参数
整个称为ArrayList<E>泛型类型
整个ArrayList<Integer>称为参数化的类型ParameterizedType
Java程序中的普通方法、构造方法和静态方法中都可以使用泛型。方法使用泛形前,必须对泛形进行声明,语法:<T> ,T可以是任意字母,但通常必须要大写。<T>通常需放在方法的返回值声明之前。例如:
public static <T> void doxx(T t);
注意:
只有对象类型才能作为泛型方法的实际参数。
在泛型中可以同时有多个类型,例如:
public static <K,V> V getValue(K key) { return map.get(key);} public void show(Double money){ System.out.println("苹果单价:" + money); } public void show(Integer money){ System.out.println("苹果数量:" + money); } public <T> void show(T info){ System.out.println("苹果信息:" + info); }
自定义泛形——泛型类
如果一个类多处都要用到同一个泛型,这时可以把泛形定义在类上(即类级别的泛型),语法格式如下:
public class BaseDao<T> { private T field1; public void save(T obj){} public T getId(int id){} }
注意,静态方法不能使用类定义的泛形,而应单独定义泛形。
泛形的典型应用:BaseDao和反射泛型(Java基础加强下讲)
定义一个方法,接收一个集合,并打印出集合中的所有元素,如下所示:
void print (Collection<String> c) { for (String e : c) { System.out.println(e); } }
问题:该方法只能打印保存了Object对象的集合,不能打印其它集合。通配符用于解决此类问题,方法的定义可改写为如下形式:
void print (Collection<?> c) { //Collection<?>(发音为:"collection of unknown") for (Object e : c) { System.out.println(e); } }
此种形式下需要注意的是:由于print方法c参数的类型为Collection<?>,即表示一种不确定的类型,因此在方法体内不能调用与类型相关的方法,例如add()方法。
总结:使用?通配符主要用于引用对象,使用了?通配符,就只能调对象与类型无关的方法,不能调用对象与类型有关的方法。
限定通配符的上边界:
正确:Vector<? extends Number> x = new Vector<Integer>();
错误:Vector<? extends Number> x = new Vector<String>();
限定通配符的下边界:
正确:Vector<? super Integer> x = new Vector<Number>();
错误:Vector<? super Integer> x = new Vector<Byte>();
//传统方式下运行时对集合内容安全检查,统计各类型变量的数量 public class Demo1 { public static void main(String[] args) { List<Boolean> list = new ArrayList<Boolean>(); list.add(true); list.add(false); for(Boolean b : list){ System.out.println(b); } /* int stringNum = 0,integerNum=0,booleanNum = 0; List list = new ArrayList(); list.add("jack"); list.add("marry"); list.add("sisi"); list.add(100); list.add(200); list.add(true); Iterator it = list.iterator(); while(it.hasNext()){ Object obj = it.next(); if(obj instanceof String){ stringNum++; }else if(obj instanceof Integer){ integerNum++; }else if(obj instanceof Boolean){ booleanNum++; } } System.out.println("stringNum="+stringNum); System.out.println("integerNum="+integerNum); System.out.println("booleanNum="+booleanNum); */ } }
//自定义泛型方法,类 public class Demo2 { //JDK5.0 public static void main(String[] args) { List<String> stringList = new ArrayList<String>(); stringList.add("tom"); stringList.add("haha"); show(stringList); } //JDK1.4 public static void show(List list) { for(Object obj : list){ String s = (String) obj; System.out.print(s+" "); } } }
//使用泛型方法交换二元素 public class Demo3 { public static void main(String[] args) { Boolean numA = false; Boolean numB = true; System.out.println("numA" + numA); System.out.println("numB" + numB); swap(numA,numB); } //泛型方法-通用性 public static <T> void swap(T numA,T numB) { T temp = numA; numA = numB; numB = temp; System.out.println("numA" + numA); System.out.println("numB" + numB); } }
//泛型通配符 public class Demo4 { public static void main(String[] args) { /* Apple a1 = new Apple(); a1.buy(10); a1.buy(5.5); */ Apple<Integer> a1 = new Apple<Integer>(); a1.buy(10); Apple<Double> a2 = new Apple<Double>(); a2.buy(5.5); } }
package cn.itcast.java.generic; public class Apple<T> { /* public void buy(Integer num){ System.out.println("苹果:" + num + "个"); } public void buy(Double price){ System.out.println("苹果:" + price + "元"); } */ //泛型方式 public void buy(T t){ System.out.println("苹果:" + t + "信息"); } }
//有限制的通配符 public class Demo5 { public static void main(String[] args) { List<Boolean> booleanList = new ArrayList<Boolean>(); booleanList.add(true); booleanList.add(false); show(booleanList); } public static void show(List<?> list) { System.out.println("集合长度为:" + list.size()); for(Object o : list){ System.out.println(o); } } }
//将集合中的元素倒序后输出 public class Demo6 { public static void main(String[] args) { List<String> stringList = new ArrayList<String>(); stringList.add("one"); stringList.add("two"); stringList.add("three"); System.out.println("倒序前:"); for(String s : stringList){ System.out.print(s+" "); } reverse(stringList); System.out.println(" 倒序后:"); for(String s : stringList){ System.out.print(s+" "); } } //倒序集合 public static void reverse(List<String> stringList) { //集合非空且至少有2个值 if(stringList!=null && stringList.size()>=2){ Collections.reverse(stringList); } } }
5 什么是xml?为什么使用xml?常见应用?
1)允许用户按照w3c组件的规定去定义无数个自定义标签
2)需要使用XML技述通知计算机程序去处理关系数据
3)保存XML文件时,一定要确保XML文件保存的编码和encoding声明的编码方式一致或兼容
4)XML可以用来描述关系结构的数据,还可以作配置文件,当作一个小型的数据库或数据载体
5)在一个软件系统中,为提高系统的灵活性,它所启动的模块通常由其配置文件决定。
*6 xml文件的语法
1)文档声明
<?xml version="1.0" 指明XML文件的版本号,XML解析器就会采用对应的版本进行解析
encoding="UTF-8" 指明XML文件中的中文采用UTF-8编码,在IDE工具中,指明该文件的保存编码方式。standalone="yes或no" 指明XML文件需要初其它文件DTD约束的话,就是no,如果单独的XML文件,就是yes>
各浏览器中的XML解析器只对XML文件的语法检测
2)元素
1)通常元素都有开始和结束标签,但也可以使用空标签,即<a></a>=<a/>
2)XML中标签嵌入顺序必须一致,且字符大小写不一致
3)程序会将标签内的空白字符当作有效字符对待
3)属性(附加信息的描述)
1)属性由属性名和属性值组成,属性值由定界符""或'组合
2)当一个事务必须与对象绑定在一起,没有该对象,该事务就没有意义,此时该事务就应成为对象的属性。
4)注释(不能随意嵌套)
1)给程序员看的
2)不能嵌套使用
5)CDATA区 、特殊字符
1)Character Data(字符数据区/段)
2)CDATA段中的数据不会被XML解析器所解析
3)不能嵌套使用
4)XML内置5种转义字符
< > & " '
5)其它字符:
★
6)处理指令(processing instruction)
1)可以使用CSS装饰XML文件中的内容
2)CSS目前版本只能支持英文标签
<?xml version="1.0" encoding="GBK"?> <!-- 手工和工具方式编写XML配置文件演示中文乱码的原理和解决方案 --> <root> <country> <city> 北京 </city> <city> 上海 </city> <city> 广州 </city> </country> </root>
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <!-- 描述中国主要城市北上广三座城市别名 --> <root> <country> <city> <真实名>北京</真实名> <别名>首都</别名> </city> <city> <真实名>上海</真实名> <别名>金城</别名> </city> <city> <真实名>广州</真实名> <别名>羊城</别名> </city> </country> </root>
<?xml version="1.0" encoding="UTF-8"?> <!-- 描述一个家庭的编号,地址,邮编等相关信息 --> <root> <!-- XML的注释 --> <family id="2011100901"> <address>GZ</address> <zipcode><510520></zipcode> <price>★</price> </family> <!-- 以下代码不想让XML解析器解析 --> <![CDATA[ <family id="2011100902"> <address>BJ</address> <zipcode>110120</zipcode> </family> ]]> </root>
<?xml version="1.0" encoding="UTF-8"?> <!-- <h1>使用CSS控制XML文件内容样式</h1> --> <?xml-stylesheet type="text/css" href="pi.css"?> <root> <h1>使用CSS将字符样式</h1> </root> ------------------------------------------------------------------------------ @CHARSET "UTF-8"; h1{约束 color:red; font-size:66px }
*7 xml约束
1)类是对象的约束
2)DTD是XML文件的约束
3)浏览器对XML和DTD进行语法的检测
4)浏览器不会检测XML是否符合DTD规则
5)正确的XML和有效的XML文件
正确的XML文件是指语法正确,而有效的XML文件是指语法和规则都正确
6)XML中书写DTD有二种方式:
a)DTD和XML分离
b)XML中嵌入DTD
6)XML引用DTD有二种方式:
a)SYSTEM:个人或组织,小范围内使用
b)PUBLIC:大范围内使用,例如:struts框架。。。
7)EMPTY和ANY,项目中尽量使用EMPTY,少用ANY
8)在DTD中,必须将所有的标签全部都声明完才行
9)在DTD中,定义元素时,可以使用如下符号:
a)+:有且只能出现1次或N次
b)*:有且只能出现0次或N次
c)?:有且只能出现0次或1次
d)无:有且只能出现1次
注意:以上符号用在()里面
10)DTD属性的设置值情况有四种:
a)#REQURIED:该属性必须出现
b)#IMPLIED:该属性可有可无
c)#FIXED "固定值":该属性可有可无,如果有的话,必须是"固定值"
d)"默认值":该属性可有可无,如果没有的话,用默认值补充,如果有的话,用新值替代旧值
11)当页面出现多个相同的字符串,此时可以使用引用实体来解决,在DTD中定义,在XML中使用
12)当定义DTD时,出个相同的子元素,此时可以使用参数实体来解决,在DTD中定义,在DTD中使用,
使用%标识,通过%参数实体名;来引用
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root SYSTEM "class.dtd"> <!-- 描述班上所有学员的姓名和年龄信息 --> <root> <student> <name>张三</name> <age>30</age> </student> <student> <name>李四</name> <age>31</age> </student> </root> 用DTD语法约束上述XML文件 <?xml version="1.0" encoding="UTF-8"?> <!ELEMENT root (student+)> <!ELEMENT student (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <head> <title>自定义XML的检查器(语法+约束)</title> <!-- 使用XML检证器来验证XML的有效性 --> </head> <body> <script type="text/javascript"> //创建IE内置解析器 var xmldoc = new ActiveXObject("Microsoft.XMLDOM"); //开启xml校验 xmldoc.validateOnParse="true"; //加载需要检查的XML文件 xmldoc.load("arg_entity.xml"); //正确 if(xmldoc.parseError.reason.length==0){ window.alert("有效的XML文件(语法正确+DTD约束"); //出错 }else{ window.alert(xmldoc.parseError.reason); } </script> </body> </html>
<?xml version="1.0" encoding="UTF-8"?> <!-- 将上述XML和DTD内容写在同一个XML文件中 --> <!DOCTYPE root[ <!ELEMENT root (student+)> <!ELEMENT student (name,age)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (#PCDATA)> ]> <root> <student> <name>张三</name> <age>30</age> </student> <student> <name>李四</name> <age>31</age> </student> </root>
<?xml version="1.0" encoding="UTF-8"?> <!-- 声明元素 --> <!DOCTYPE root [ <!ELEMENT root (student)> <!ELEMENT student (name,age,alias)> <!ELEMENT name (#PCDATA)> <!ELEMENT age (real|virtual)> <!ELEMENT alias ANY> <!ELEMENT real (#PCDATA)> <!ELEMENT virtual (#PCDATA)> ]> <root> <student> <name>jack</name> <age> <virtual>11</virtual> </age> <alias/> </student> </root>
<?xml version="1.0" encoding="UTF-8"?> <!-- 声明属性 --> <!DOCTYPE root [ <!ELEMENT root (桌子+)> <!ELEMENT 桌子 EMPTY> <!ATTLIST 桌子 id ID #REQUIRED width CDATA #REQUIRED height (50|60|70) "60" make CDATA #IMPLIED color CDATA #FIXED "白色" weight CDATA "20"> ]> <root> <桌子 id="t2011100901" width="60" height="70" color="白色" weight="30" /> </root>
<?xml version="1.0" encoding="UTF-8"?> <!-- 声明实体 --> <!DOCTYPE root [ <!ELEMENT root (电视台+)> <!ELEMENT 电视台 (#PCDATA)> <!ENTITY CCTV "中国中央电视台"> ]> <root> <电视台> &CCTV; </电视台> <电视台> &CCTV; </电视台> </root>
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE root SYSTEM "arg_entity.dtd"> <root> <客户> <姓名>张三</姓名> </客户> <员工> <姓名>李四</姓名> </员工> </root> <!------------------------------------------------------------------> <?xml version="1.0" encoding="UTF-8"?> <!ENTITY % TIP "姓名"> <!ELEMENT root (客户,员工)> <!ELEMENT 客户 (%TIP;)> <!ELEMENT 员工 (%TIP;)> <!ELEMENT 姓名 (#PCDATA)>