IDE和JDK5.0新特性(中):JavaSE加强

时间:2022-12-25 15:23:07

JavaSE加强

其实在JavaSE的学习中我们发现JDK的版本一直在不断的更新。那么每次的更新都会引入一些新的技术进来。如果一个开发人员可以数量的掌握这些新的技术,那么就可以在后期的企业开发中如虎添翼。

在本章节中主要给大家讲解一些JDK5.0的新特性。方便提高代码的运行效率和安全性。

主要的讲解的内容如下:

u  静态导入

导入技术其实在java中是为了方便的使用其他人写好的类。

importjava.lang.*|类名

在原来的导包语句中发现只能导入类。如果需要导入的是一些静态的方法或者属性那么就无能为力。

举例1:求一个任意半径的圆形的面积?

// 求一个任意半径的圆形的面积

    publicstaticvoid getArea(){

       // 1. 求一个随机的半径

       double= Math.ceil(Math.random()*10);

       // 2. 计算面积

       double area = 0.0;

       area = Math.PI*r*r;

       // 3. 打印面积

       System.out.println("半径是"+r+"的圆形的面积是:"+area);

}

发现以上的代码中大量的出现了一些静态的成员。

那么可以使用静态导入的方式简化代码的书写。

语法:

importstatic java.lang.*|静态成员

 

实战:

importstatic java.lang.Math.PI;

importstatic java.lang.System.out;

importstatic java.lang.Math.random;

importstatic java.lang.Math.ceil;

publicclass Demo4 {

    // 求一个任意半径的圆形的面积

    publicstaticvoid getArea(){

       // 1. 求一个随机的半径

       double= ceil(random()*10);

       // 2. 计算面积

       double area = 0.0;

       area = PI*r*r;

       // 3. 打印面积

       out.println("半径是"+r+"的圆形的面积是:"+area);

    }

}

如果代码中使用到了一个类的多个静态成员那么可以直接使用* 进行全部的导入。

importstatic java.lang.Math.*;

u  可变参数

思考:如果开发者现在要定义一个函数(方法),那么不知道参数的个数的时候应该如何指定形参。

语法:定义函数的语法

修饰符返回值类型方法名(参数类型变量名 ) 异常的声明{

    // 函数体

    return;

}

J多学一招:学习可变参数的本质

1.       可变参数其实是一个可变的数组

2.       可变参数在方法的声明中只能出现在参数列表的最后一个位置

3.       可变参数只能在参数列表中出现一次

举例1:求任意个整数的累加和?

// 求任意个整数的累加和?

publicstaticlong getSum(int... is){

      long sum = 0;

      for (int i = 0; i < is.length; i++) {

         sum +=is[i];

      }

      return sum;

}

举例2SUNAPI中用的可变参数。

static<T> List<T> asList(T... a) 返回一个受指定数组支持的固定大小的列表。

u  包装类

其实在java中有四型八种的基本数据类型。如果所有的基本数据类型不是对象的话那么java

语言就不是正真的OOP语言。

Wrapper Class即包装类。在包装类中SUN封转了开发者常用的一些属性和方法,可以进行快速的编程。

包装类

基本数据类型

Byte

byte

Short

short

Integer

int

Long

long

Boolean

boolean

Character

char

Float

float

Double

double

举例1:体验Integer类提供的属性。

// 体验Integr类的属性

    publicstaticvoid getField() {

       System.out.println(Integer.MIN_VALUE);   // -2147483648

       System.out.println(Integer.MAX_VALUE);   // 2147483647

    }

阅读以下的代码,分析代码的错误原因:

long date = 12345678910;   // 报错

12345678910 

2147483647

举例2:体验Integer类提供的方法。

主要学习的是整数到字符串之间的转换的方法。

// 体验Integr类的方法

    publicstaticvoid getMethod() {

      // 创建类对象

      Integer in1 = new Integer(123);

      int i1 = in1.intValue();

      System.out.println(i1+1);

      // 转换为字符串

      String str1 = in1.toString();

      System.out.println(str1+1);

    }

其实在这里没有必要转型为String的时候进行基本的toString()调用。

简化以上的代码:

// 体验Integr类的方法

    publicstaticvoid getMethod2() {

      // 创建类对象

      Integer in1 = new Integer(123);

      int i1 = in1;      // 自动拆箱

      System.out.println(i1+1);

      // 转换为字符串

      System.out.println(in1+""+1);

    }

J多学一招:什么是自动拆箱和自动装箱?

自动装箱: 如果将基本类型传递给包装类型。  Integer in1 = 12;

自动拆箱: 如果将包装类型传递给基本类型。  int i1 = in1

在泛型的时候比较有用:

集合:主要的用途是进行对象的存储。

list.add(1);    //自动装箱

思考:String str = “hello”;

u  增强for循环

如果要遍历一个指定的数,那么我们一般要使用传统的的for循环。

语法:

for( 条件的初始化语句; 条件表达式; 循环的增量 ){

   // 循环体 breakcontinue

}

这样写的话每次都会遇到一个下标越界的一个异常。

因此可以使用增强for循环进行快速的遍历(数组、集合以及实现了Iterable接口的类)

语法:

for(数据类型变量名:需要遍历的集合){

    // 循环体

}

举例1:遍历一个普通的数组。

// 遍历一个数组

    publicstatic  void printArray(int [] a){

       for(int temp:a){

           System.out.println(temp);

       }

    }

举例2:遍历一个List集合。

// 遍历一个list

    publicstaticvoid printList(List<String> list){

       for (String string : list) {

           System.out.println(string);

       }

    }

举例3:遍历一个Map集合。

 

// 遍历一个Map集合

    publicstaticvoid printMap(Map<Integer,String> map){

      // 想将其转换为实现了Iterable接口的Set

      Set<Map.Entry<Integer, String>> set = map.entrySet();

      // 遍历set集合

      for(Map.Entry<Integer, String> entry:set){

          // 获取entry对象的keyvalue

          Integer key = entry.getKey();

          String value = entry.getValue();

          System.out.println(key+"="+value+",");

      }

    }

思考:如果以上的集合没有使用泛型,那么在使用for循环的时候应该使用什么类型接收集合数据?  Object

J多学一招: 使用增强for循环是否可以改变集合中数据?

因为for循环在遍历的时候使用的是将值拷贝一份给临时变量。因此改变临时变量不会改变集合中的数据值。

J多学一招:使用增强for循环遍历集合的时候操作集合的问题?

    // 遍历一个list

    publicstaticvoid printList(List<String> list){

       for (String string : list) {

           list.add("eeee");    // 运行错误

           System.out.println(string);

       }

       System.out.println("遍历中: "+list);

    }

异常信息如下:

Exception in thread "main" java.util.ConcurrentModificationException

模拟基础班看过的场景:

    publicstaticvoid main(String[] args) {

       List<String> list = newArrayList<String>();

       list.add("aaaa");

       list.add("bbbb");

       list.add("cccc");

       list.add("dddd");

      

       Iterator<String> it =list.iterator();

       while(it.hasNext()){

           list.add("yyyy");

           String str = it.next();

           System.out.println(str);

       }

    }

运行异常:

Exception in thread "main" java.util.ConcurrentModificationException

总结;

在使用增强for循环进行集合的迭代的时候其实默认使用的是迭代器,因此在循环中不能使用集合的引用变量直接操作集合,避免导致多线程并发访问的安全性异常。

u  安全的枚举类

在实际的项目的开发中我们经常需要一类数据,这一类数据的值是特定范围的一组值。如:

性别:[男、女]

交通灯:[红、黄、绿]

星期几:[~]

以上的一组值可以定义为枚举数据类型。

语法:

修饰符 enum 枚举类名{

   // 定义枚举的一组值,多个值之间使用逗号进行分隔

}

实现:

publicenum Gender {

  MALE,FEMALE;

}

J多学一招: 枚举的本质是什么?

1.      枚举本质是一个类

2.      默认继承自Enum

3.      枚举值本质是枚举类的静态常量值

4.      枚举值都在静态代码块中进行初始化

5.      枚举类的默认构造函数式有参数的且只能私有

6.      枚举是单例模式

J多学一招: 如何使用javap工具查看class文件?

使用以下的命令查看Genderclass文件

D:\>javapGender

Compiledfrom "Gender.java"

publicfinal class Gender extends java.lang.Enum{

    public static finalGender MALE;

    public static final Gender FEMALE;

    public static Gender[] values();

    public static GendervalueOf(java.lang.String);

    static {};

}

-c  反编译class文件

-l  输出行号

-private 显示所有的成员

既然枚举是一个普通类,那么我们开发人员就可以在类中定义类的成员(属性、构造函数、函数)

举例1:在枚举中定义属性。

publicenum TrafficLight {

   // 定义枚举值

   RED,GREEN,YELLOW

   // 定义成员属性

   public String info = "交通灯信息";

   publicstaticvoid main(String[] args) {

      System.out.println(TrafficLight.GREEN.info);

   }

}

举例2::在枚举中定义构造函数。

publicenum TrafficLight {

   // 定义枚举值

   RED("红灯"),GREEN("绿灯"),YELLOW("黄灯");

   // 定义成员属性

   public String info = "交通灯信息";

   // 提供构造函数进行属性的初始化

   private TrafficLight(String info){

      this.info = info;

   }

   publicstaticvoid main(String[] args) {

      System.out.println(TrafficLight.GREEN.info);

      System.out.println(TrafficLight.RED.info);

      System.out.println(TrafficLight.YELLOW.info);

   }

}

切记的是为了保证枚举是单例的那么构造函数全部要私有。

举例3:在枚举中定义函数。

publicenum TrafficLight {

    // 定义枚举值

    RED("红灯") {

       @Override

       publicvoid showMessage() {

             System.out.println("红灯停!");

       }

    },

    GREEN("绿灯") {

       @Override

       publicvoid showMessage() {

            System.out.println("绿灯行!");

       }

    },

    YELLOW("黄灯") {

       @Override

       publicvoid showMessage() {

           System.out.println("你自己看着办!");

       }

    };

    // 定义成员属性

    public String info = "交通灯信息";

    // 提供构造函数进行属性的初始化

    private TrafficLight(String info) {

       this.info = info;

    }

    // 提供一个表明灯的信息的方法

    publicabstractvoid showMessage();

    publicstaticvoid main(String[] args) {

       System.out.println(TrafficLight.GREEN.info);

       System.out.println(TrafficLight.RED.info);

       System.out.println(TrafficLight.YELLOW.info);

       TrafficLight.RED.showMessage();

    }

}

以上的代码可见在枚举类中可以定义抽象方法,但是不能将枚举类声明为抽象类,只能在声明枚举值的时候实现所有的抽象方法即(匿名内部类)

在实际的枚举中其实自定义的枚举类默认继承Enum类,那么我们的枚举类中就会有Enum类中的定义好的属性和方法。

常用方法

方法的描述

String name()

获取枚举值的名称

int ordinal()

返回枚举值定义的序号

valueOf(Class<T> enumType, String  name)

通过反射查找指定的类中的指定名的枚举值

values()

该方法在API中不可见但是可用

举例3:使用Enum类中常用的方法。

// 常用的方法体验

System.out.println(TrafficLight.YELLOW.name());  // YELLOW

System.out.println(TrafficLight.RED.ordinal()); // 0

System.out.println(TrafficLight.valueOf(TrafficLight.class,"GREEN"));

以上的方法都是在API中可见的方法,但是有一些方法是API中不可见但是内部其实定义了的方法。

举例4:遍历枚举值。

// 遍历枚举值

TrafficLight [] trans = TrafficLight.values();

for(TrafficLight temp:trans){

System.out.println(temp);

}

面试题:简单叙述以下以下三个关键字有什么区别?

Enum                    à枚举类默认继承的类

Enumeration        à早期的迭代器类型,主要用于Vector和顺序流

enum                    à定义一个类为枚举时候的关键字

u  泛型

问题:如果不使用泛型,那么请看下面的代码发生的转型异常?

publicstaticvoid printList(List list){

       for(Object temp:list){

           String str =(String) temp;

           System.out.println(temp);

       }

    }

    publicstaticvoid main(String[] args) {

        List  list = new ArrayList();

        list.add("aaa");

        list.add(123);

        list.add("bbb");

        printList(list);

    }

因此我们在实际的开发环境中需要进行泛型的使用。通过使用泛型我们可以约束在集合中存储的对象的类型。

泛型其实就是给容器上贴一个标签而已,指定容器存放的数据类型。

泛型的有点其实就是将运行时候的异常前置在编译时解决。

泛型的使用

原则使用泛型的时候左右两边要一致!

 List  list = newArrayList<String>();     add提示的是Object

  List<String>  list = new ArrayList ();    add提示的是String

  List<String>  list = new ArrayList<String>();  add提示的是String

以上的语法全对,但是推荐使用第三种。

泛型的自定义

如果在定义一个类的时候成员的类型不明确,那么可以先使用泛型进行代替,直到创建该类的对象的时候可以使用具体的数据类型来替换泛型的类型。

举例1:定义一个方法返回任意数据类型的数据。

publicstatic <T> T returnType(T t){

       return t;

    }

如果一个类中很多地方都使用到了泛型,那么可以将泛型的定义放在类上。

public class Demo1<T>{

   // 非静态成员都可以直接使用T泛型

}

如果是静态成员那么不能使用类上定义好的泛型。如果需要的话需要单独的进行声明。

泛型的继承和实现

publicinterface List<E> extends Collection<E>

publicclass Person implements Comparable<Person>

compareTo(T o)

泛型的通配符

举例1: 实现一个方法可以打印输出任意集合数据?

  // 提供一个输出任意集合数据的方法

    // Collection<Object> coll = new ArrayList<String>()

    publicstaticvoid printCollection(Collection<?> coll){

       for(Object temp:coll){

           System.out.println(temp);

       }

    }

泛型的限定

在通配符的基础上可以对实际的类型进行基本的限制

? extends父类

? super 子类

举例2:实现数字集合的输出。

publicstaticvoid printCollection(Collection<? extends Number> coll){

       for(Object temp:coll){

           System.out.println(temp);

       }

    }

实战:

查看ListbooleanaddAll(Collection<? extends E> c) 方法

注意:

在给泛型传递实际的数据类型的时候必须是对象类型,如果是基本数据类型那么默认会自动的进行装箱操作。

u  反射(Reflect)

反射即将Class类中的所有的成员映射为相应的对象。

要学习反射那么需要先了解和掌握以下几个类:

描述

Class

描述所有的Class文件的共性

Filed

描述的是Class文件的中的属性的共性

Constructor

描述的是Class文件中的构造函数的共性

Method

描述的是Class文件中的函数的共性

1. 获取指定类的Class对象

方式一: 类名.class

方式二: 对象名.getClass()

方式三: forName(StringclassName) 该方法是Class类的静态方法   推荐

 

 

举例1:获取字符串类的Class对象。

  publicstaticvoid main(String[] args)throws Exception {

       // 使用不同的方式会过去Class对象

    Classclazz1 = String.class;

    Classclazz2 = new String("jnb").getClass();

    // 参数必须指定类的全名(类的全限定名)

    Classclazz3 = Class.forName("java.lang.String"); 

    // class文件时候独一无二的,那么Class对象也应该是单例的

    System.out.println(clazz1 ==clazz2);   // true

    System.out.println(clazz2 ==clazz3);   // true

    }

以上的方式都可以获取指定类的Class对象,在实际的开发中到底要使用哪一个?

一般的情况下我们都需要在不知道类名的情况下获取类的Class对象并进而获取类中包含的成员进行操作。

大家可以参考Tomcat的一个基本的server.xml文件

<Resourcename="UserDatabase" auth="Container"

             type="org.apache.catalina.UserDatabase"

              description="User databasethat can be updated and saved"

             factory="org.apache.catalina.users.MemoryUserDatabaseFactory" à类

             pathname="conf/tomcat-users.xml" />

2. Class对象中的属性进行反射为Filed对象

常用的获取属性字段的方法

方法

描述

Field[] getDeclaredFields()

获取所有声明的字段数组对象

Field[] getFields()

获取所有的声明的共有字段数组对象

Field getDeclaredField(String name)

获取指定名称的声明的字段对象

Field getField(String name)

获取指定名称的声明的共有字段对象

URL getResource(String name)

获取指定名的资源的URL对象

InputStream getResourceAsStream(String  name)

获取指定名的资源的输入流对象

举例1:获取所有的声明字段数组对象。

    publicstaticvoid main(String[] args)throws Exception {

       // 获取Shape类的Class对象

    Classclazz = Class.forName("cn.itcast.bean.Shape");

    // 获取所有的属性

    Field[] fs = clazz.getDeclaredFields();

    System.out.println(fs.length);   // 2

    // 获取所有共有的属性

    fs= clazz.getFields();

    System.out.println(fs.length);   // 1

     // 获取指定名字的私有的属性

    Fieldfield = clazz.getDeclaredField("x");

    System.out.println(field);

    // 获取指定名字的共有的属性

    field= clazz.getField("y");

    System.out.println(field);

    }

如果获取到了一个类中声明的属性字段,那么可以使用Field类提供的一些常用方法来操作这些属性。

方法

描述

String getName()

获取属性的名字

void set(Object obj, Object value)

给属性设置相应的值

Object get(Object obj)

获取属性的值

 

举例2:调用Field类的方法进行字段对象的操作。

 publicstaticvoid main(String[] args)throws Exception {

       // 获取Shape类的Class对象

    Classclazz = Class.forName("cn.itcast.bean.Shape");

    // 获取所有的属性

    Field[] fs = clazz.getDeclaredFields();

    System.out.println(fs.length);   // 2

    // 获取所有共有的属性

    fs= clazz.getFields();

    System.out.println(fs.length);   // 1

    Shapeshape = new Shape();   // 20

    // 获取指定名字的私有的属性

    Fieldfield = clazz.getDeclaredField("x");

    System.out.println(field);

    // 操作私有的属性x

    System.out.println("属性名: "+field.getName());

        // 获取x的属性值,需要暴力的反射

    field.setAccessible(true);

    System.out.println("设置之前的x值:"+field.get(shape));

    // 设置x的属性值

    field.set(shape, 20);

    System.out.println("设置之后的x值:"+field.get(shape));

    // 获取指定名字的共有的属性

    field= clazz.getField("y");

    System.out.println(field);

    // 给属性y进行设置值

    System.out.println("属性名: "+field.getName());

    // 获取设置属性值之前的值

    System.out.println("设置之前的y值:"+field.get(shape));  // 20

        field.set(shape,30);         // 30

    System.out.println("设置之后的y: "+shape.y);   // 30

}

以上的代码可以通过程序进行反射类中的属性字段并操作,但是没有进行静态属性的反射和操作。

举例3:反射静态的成员属性。

publicstaticvoid main(String[] args)throws Exception {

    // 获取Shape类的Class对象

    Classclazz = Class.forName("cn.itcast.bean.Shape");

    // 获取共有的静态属性

    Fieldfield = clazz.getField("z");

    System.out.println("设置之前的z: "+field.get(null));

    field.set(null, 40);

    System.out.println("设置之后的z: "+field.get(null));

}

3. Class对象中的方法进行反射为Method对象。

publicstaticvoid main(String[] args)throws Exception {

    // 获取Shape类的Class对象

    Classclazz = Class.forName("cn.itcast.bean.Shape");

    // 获取所有的声明的方法

    Method[] ths = clazz.getDeclaredMethods();

    System.out.println(ths.length); // 2

    // 获取私有的带参数的sayHello方法

    MethodsayHello = clazz.getDeclaredMethod("sayHello", String.class);

    System.out.println(sayHello);

    // 调用私有的方法

    sayHello.setAccessible(true);

    sayHello.invoke(new Shape(), "jnb");

    // 获取所有的共有的方法

    ths= clazz.getMethods();

    System.out.println(ths.length); // 10

    // 获取带参数的共有的方法

    Methodgreet = clazz.getDeclaredMethod("greet", String.class);

    System.out.println(greet);

    // 方法的调用

    greet.invoke(new Shape(), "焦宁波");

}

4. Class对象中的构造函数进行反射为Constructor对象。

publicstaticvoid main(String[] args)throws Exception {

    // 获取Shape类的Class对象

    Classclazz = Class.forName("cn.itcast.bean.Shape");

    // 获取所有的声明的构造函数

    Constructor[] cons = clazz.getDeclaredConstructors();

    System.out.println(cons.length);  // 3

    // 获取带参数的私有的构造函数对象

    Constructorcon =

clazz.getDeclaredConstructor(int.class,int.class);

    System.out.println(con);

    // 暴力反射私有的构造函数创建对象

    con.setAccessible(true);

    Shapemyshape = (Shape) con.newInstance(400,500);

    System.out.println(myshape.getX()+","+myshape.y);

    // 获取所有的共有的构造函数

    cons= clazz.getConstructors();

    System.out.println(cons.length);  // 2

    con = clazz.getConstructor(int.class);

    System.out.println(con);

    // 调用构造函数创建对象

    Shape shape = (Shape) con.newInstance(100);

    System.out.println(shape.getX());

}

面试题:请简单的叙述出你所可以创建的对象的几种方式?

第一种:直接使用new关键字

第二种:Construnctor.newInstance

第三种:枚举

第四种:单例、工厂模式

u  内省(Introspect)

其实在以上的反射技术体验中我们发现其实反射的对象一般是一个具有特定功能的一个类。

引入一个基本的概念:JavaBean

如果一个类提供了封装好的属性、构造函数(无参数)、共有的getset方法以及简单的业务逻辑方法那么将这样的一个类称之为JavaBean类。

对于一个javaBean的操作无非就是给属性值进行操作或函数的调用。

使用反射比较繁琐,那么SUN就提供了内省的技术方便大家进行JavaBean类的操作。

描述

BeanInfo

JavaBean进行描述的接口

Introspector

描述所有的JavaBean的成员类

PropertyDescriptor

描述的是JavaBean的属性类

举例1:使用属性描述器类操作JavaBean属性。

创建一个Bookjavabean

publicclass Book {

    private String name;      //null

    private String author;        //null

    privatedoubleprice;     // 0.0

    private Date date;         // null

    public Book() {

       super();

    }

    public Book(String name, Stringauthor, double price, Date date) {

       super();

       this.name = name;

       this.author = author;

       this.price = price;

       this.date = date;

    }

    // 省略getset方法

}

使用内省技术进行简单的属性的操作。

publicstaticvoid main(String[] args) throws Exception{

        // 获取一个属性的描述器对象就相当于获取了属性的名、setget方法

       PropertyDescriptor pd = new

PropertyDescriptor("name",Book.class);

        // 获取set方法

       Method set = pd.getWriteMethod();

       // 调用该方法设置属性的值

       Book book = new Book();

       System.out.println("设置前获取name属性值:"+book.getName());

       set.invoke(book, "JavaSE进阶");

       System.out.println("设置后获取name属性值:"+book.getName());

       // 获取get方法

       Method get =pd.getReadMethod();

       System.out.println(get.invoke(book,null));

}

以上的代码每次都只能操作一个属性,这样就比较繁琐。可以使用其他的类直接获取所有的属性描述器通过循环来直接操作。

publicstaticvoid main(String[] args) throws Exception{

       // 获取指定的BeanInfo对象

      BeanInfo info = Introspector.getBeanInfo(Book.class);

      // 获取Book类中的所有的属性的描述器对象

      PropertyDescriptor[] pds = info.getPropertyDescriptors();

      // 输出长度

      System.out.println(pds.length);

      // 查看数组的第一个属性描述器是谁

      PropertyDescriptor pd = pds[0];

      // 作者

      System.out.println(pd.getName());

      Book book = new Book();

      // 给书设置作者信息

      pd.getWriteMethod().invoke(book, "焦宁波");

      System.out.println(pd.getReadMethod().invoke(book, null));

}

总结:其实发现在使用内省进行属性操作的时候要结合反射一起使用。

面试题:一个JavaBean中为什么必须要提供一个无参数的构造函数?

原因一:为了可以做父类。

原因二:为了可以使用反射创建对象。

 

u  BeanUtils工具

在实际的开发中我们经常需要将用户的录入的数据进行封装为对象,那么如果使用反射和内省技术就会变得吃力。因此本节主要给大家讲解一个开源的操作JavaBean的一个工具即BeanUtils

下载:

http://www.apache.org

beanutils-1.8.0.zip

commons-logging.jar

包的引入:

在项目中创建一个文件夹如libs,然后将整个项目需要的第三方的jar包可以直接拷贝带该目录,随后打开该目录全选à右键àBuildpath à add path à看到奶瓶子即可

举例1:使用BeanUtils工具封装用户提交的数据。

publicstaticvoid main(String[] args)throws Exception {

       // 模拟用户的输入的数据如下

      String name = "XML基础";

      String author = "焦宁波";

      String price = "99.99";

      String date = "2013-01-04";

      Book book = new Book();

      // 任务是将以上的属性设置给指定的Book对象

      BeanUtils.setProperty(book, "name", name);

      BeanUtils.setProperty(book, "author", author);

      BeanUtils.setProperty(book, "price",price );

      // 查看属性是否封装好

      System.out.println(book);

}

发现使用上面的代码可以省略基本数据类型的转型的问题。进而提高代码的开发效率。

举例2:自定义一个类型转换器类。

publicstaticvoid main(String[] args)throws Exception {

       // 模拟用户的输入的数据如下

      String name = "XML基础";

      String author = "焦宁波";

      String price = "99.99";

      String date = "2013-01-04";

      

      Book book = new Book();

      

      // 注册一个自己的转换器

      /**

        *converter指定具体的转换器

        *clazz遇到什么类型调用上面的转换器

        */

      ConvertUtils.register(

              new Converter(){

              // 回调方法  

              @Override

              public Object convert(Classtype, Object value) {

                  if(value == null){

                     returnnull;

                  }

                  // 转换为String

                  Stringdata = (String)value;

                  // 将指定格式的字符串转换为Date

                  SimpleDateFormatformat = new SimpleDateFormat("yyyy-MM-dd");

                  Datedate  = null;

                  try {

                     date= format.parse(data);

                     return date;

                  }catch (ParseExceptione) {

                     e.printStackTrace();

                     returnnull;

                  }

              }

              },

              Date.class);

      // 任务是将以上的属性设置给指定的Book对象

      BeanUtils.setProperty(book, "name", name);

      BeanUtils.setProperty(book, "author", author);

      BeanUtils.setProperty(book, "price",price );

      BeanUtils.setProperty(book, "date",date );

      // 查看属性是否封装好

      System.out.println(book);

}

如果每次遇到一个复杂类型都需要自定义转换器,那样的话实在麻烦。大家看在开发的时候可以先查看该接口是否提供了有效的实现类。

ConvertUtils.register(newDateLocaleConverter(), Date.class);

其实真正的封装好的数据需要存储在数据库中,那么javabean的数据类型应该和数据库的数据类型保持一致,那么在声明持久化javabean的时候需要全部为数据库的基本数据类型。

因此大家在JavaBean中需要导入的是java.sql.Date类,这样就直接可以将日期自动转换了。

举例3:实现封装好的JavaBean对象的属性拷贝。

// 实现属性封装数据的一个拷贝

Book copy = new Book();

System.out.println(copy);

PropertyUtils.copyProperties(copy, book);

System.out.println(copy);

思考:如果使用BeanUtils封装用户的数据,那么也就是一个一个设置啊?岂不是也很麻烦?

其实在真是的环境中我们可以直接获取用户提交的所有的数据信息,只需要进行遍历即可,但是为了方便快速的设置,那么可以将javabean中的属性名和用户提交的数据名保持一致。