Day01

01-javaee就业班课程介绍和编程方式

1.C/S,B/S

 

2.WEB涉及到的相关技术

3.如何编程

l在软件工程中,对编程有个很精辟的描述:编程就是把一个大问题,分解成若干小问题。编程即问题的分解过程(Decomposition )。
 
l在实际编程中,我们也总是从一个大问题开始,逐步分解,分解成或干个小问题,最终翻译成原语(Primitives),从而使用计算机完成对问题的求解。
 
l程序的两种设计思路:
•Top down design(大多数情况下应采用此种方式)
•Bottom up design
 
lDecomposition的几个基本原则:
•每个方法解决一个问题
•大部分方法行数不超过1-20行
•为每一个方法取一个好名字,让它更接近人类自然语言,程序能够供人们轻松阅读,往往比计算机能够正确执行更为重要。
•为每一个方法尽可能添加详尽的注释。
下面我们写一个将文件从一个地方复制到另外一个地方的程序来说明编程方式
package cn.itcast;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

public class Demo2 {

    /**
     * 自顶向下的程序设计
     * @param args
     */
    public static void main(String[] args) {

        String src = "c:\\1.jpg";
        String dest = "d:\\1.jpg";
        try {
            copy(src,dest);
            System.out.println("拷贝成功!!");
        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        }catch (IOException e) {
            System.out.println("由于未知的原因,导致文件读写失败!!");
        }
    }

    /**
     * 拷贝目标资源到文件中
     * @param src : 指定目标资源
     * @param dest :指定需要写入的文件
     * @throws IOException  : 如果文件读取过程中,出现了未知错误,则会抛出IOException
     */
    private static void copy(String src, String dest) throws IOException {
        InputStream in = readFile(src);
        writeToFile(in,dest);
    }
    
    /**
     * 读取文件,并使用InputStream关联需要读取的文件
     * @param src : 指定需要读取的文件
     * @return: 返回与文件相关联的流
     * @throws FileNotFoundException
     */
    private static InputStream readFile(String src) throws FileNotFoundException {
        
        //1.检测文件是否存在
        if(!existFile(src)){
            throw new FileNotFoundException("指定目标资源不存在!!");
        }
        //2.读取文件
        FileInputStream in = new FileInputStream(src);
        return in;
    }

    /**
     * 判断文件是否存在
     * @param src : 需要判断的文件
     * @return :如果存在则返回true,否则false
     */
    private static boolean existFile(String src) {
        
        File file = new File(src);
        if(file.exists()){
            return true;
        }
        return false;
    }

    /**
     * 
     * @param in
     * @param dest
     * @throws IOException
     */
    private static void writeToFile(InputStream in, String dest) throws IOException {
        
        if(!existFile(dest)){
            File file = new File(dest);
            file.createNewFile();
        }
        
        FileOutputStream out = new FileOutputStream(dest);
        inToOut(in,out);
        
    }

    /**
     * 
     * @param in
     * @param out
     * @throws IOException
     */
    private static void inToOut(InputStream in, FileOutputStream out) throws IOException {
        try{
            int len = 0;
            byte buffer[] = new byte[1024];
            while((len=in.read( buffer))>0){
                out.write(buffer,0,len);
            }
        }finally{
            if(in!=null){
                in.close();
            }
            if(out!=null){
                out.close();
            }
        }
        
    }
}

02-eclipse的使用与junit框架

1.Eclipse的断点调试运行

f5:step into 跳入,就是跳入到某个方法中去


f6: step over 步进,就是执行下一步


f7: step return 跳回,调回之前的断点

drop to frame : 跳到当前方法第一行

resume : 跳到下一个断点,当在只有一个断点时点它会执行完整个程序,如果有多个断点则会跳到下一个断点

watch : 查看变量或表达式的值,注意有的时候需要查看到一个表达式的返回值,所以可以在整个表达式上查看watch

 

2.MyEclipse中常用的快捷键

•内容提示:Alt + /  我们可以在proferences中输入keys就可以修改Content Assist(内容助理)的快捷键,在默认安装的myeclipse中是没有配置快捷键的
•快速修复:Ctrl + 1  在将来我们开发中只有看见错误就按这个快捷键
•导包:Ctrl + shift + O
•格式化代码块:ctrl + shift + F
•向前向后:Alt + 方向键
•添加注释 Ctrl+Shift+/    
•除去注释 Ctrl+Shift+\     
•Ctrl+/ 注释当前行,再按则取消注释

•查看方法说明:F2

•重置透视图Window->Reset Perspective

•更改为大写 Ctrl+Shift+X

•更改为小写 Ctrl+Shift+Y

•复制行 Ctrl+Alt+向下键(有些不能用)

•Ctrl+D,删除当前行

•查看当前类的层次结构:Ctrl+T

•查看源代码:

1、在要查看的类上Ctrl+鼠标左键

2、ctrl+shift+T,这个可以任意的查看想看的类的源码,只要按这个快捷键,然后输入想查看的类就可以查看它的源码

•罗列出所有快捷键:Ctrl+Shift+l

 还有一个关联源码

 

如果你的源码是以文件存在的则点击Extral File,如果你的文件是以目录存在的则点击Exteral Folder

 

3.Junit

在我们实际开发中,写完一个功能必须要先测试,junit就是这么一个测试框架

Person.java

package cn.itcast;

public class Person {
    
    public void run(){
        System.out.println("run!!!!");
        throw new RuntimeException();
    }
    
    public void eat(){
        System.out.println("eat!!!");
    }
    
}

一般我们有一个习惯,我们会把测试类放在一个单独的包里面

PersonTest.java

package junit.test;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import cn.itcast.Person;

public class PersonTest {

    
    @BeforeClass      //你如果希望Junit框架在加载测试类的时候就初始化资源,我们就有必要将初始化资源代码写入到这个方法里面去,由于在加载之前,所以必须是静态的
    public static void beforeClass(){        //必须静态
        System.out.println("beforeClass");
    }
    
    @Before           //这个用于在测试方法之前运行,当你在测试某个方法之前,想要服务器为你加载一些资源就用这个,这里的方法名可以改变
    public void before(){
        System.out.println("before!!!");
    }
    
    @Test
    public void testRun(){
        Person p = new Person();
        p.run();
    }
    
    
    @Test
    public void testEat(){
        Person p = new Person();
        p.eat();
      //断言,所谓断言就是判断条件是否成立,这里断言Assert的方法有很多方法,有不同的形式,但assertEquatls("期望的值","表达式返回的")这个最常用
   //如果你期望的值和你表达式返回的值是一样的则测试通过,反之测试失败 Assert.assertEquals("1", "2"); }    @After              //这个方法用于在测试方法之后,当你测试完某个方法之后想销毁某些资源就用这个方法,这里的方法名可以改变 public void after(){ System.out.println("after!!"); } @AfterClass      //如果你希望Junit框架在运行完整个测试类之后销毁这些资源就必须将销毁资源的代码写入到这个方法里面,由于是在销毁类之后,所以必须是静态的 public static void afterClass(){ //必须静态 System.out.println("afterClass"); } }

 小绿条向你招收就表示测试通过,小红条向你招收就表示测试不通过

03-jdk的新特性

1.静态导入

  静态导入用于简化程序对类静态属性和方法的调用。
  语法:
  •Import static 包名.类名.静态属性|静态方法|*
  例如:•import static java.lang.System.out
     •import static java.lang.Math.*
package cn.itcast;

import static java.lang.System.out;
import static java.lang.Math.*;

public class Demo5 {

    /**
     * 静态导入
     * @param args
     */
    public static void main(String[] args) {

        out.print("hahah");
        abs(112);
    }

}

2.自动装箱/拆箱

  自动装箱:指开发人员可以把一个基本数据类型直接赋给对应的包装类。
  自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型。
  典型应用:

    List list = new ArrayList();

    list.add(1);

    int j = (Integer)list.get(0);

package cn.itcast;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Demo6 {

    /**自动装箱和拆箱
     * @param args
     */
    public static void main(String[] args) {

        int i = 1;  //(Integer)
        Integer j = i;  //装箱
        int k = j;  //拆箱
        
        //常见应用
        List list = new ArrayList();
        list.add(1);      //在加1的时候其实是将int的1装换成Integer对象的1,然后在加入
        list.add(2);
        list.add(3);
        
        Iterator it = list.iterator();
        while(it.hasNext()){
            int m = (Integer)it.next();    //典型的拆箱
        }
    }

}

3.增强for循环

  引入增强for循环的原因:在JDK5以前的版本中,遍历数组或集合中的元素,需先获得数组的长度或集合的迭代器,比较麻烦!
  因此JDK5中定义了一种新的语法——增强for循环,以简化此类操作。增强for循环只能用在数组、或实现Iterable接口的集合类上
  也就是说不能直接循环Map,因为Map没有实现Interable这个接口
  语法格式:                                             
   for(变量类型 变量 :需迭代的数组或集合){

    }

package cn.itcast;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

import org.junit.Test;

public class Demo7 {

    /**
     * 增强for
     * @param args
     */
    
    @Test
    public void test(){
        //增强for注意的问题:增强for只适合取数据,不要用它去修改数组或集合中的数据
        int arr[] = {1,2};
        for(int num : arr){
            num = 3;      //这样改只是将num这个变量修改了,并没有修改掉数组中的值
        }
        System.out.println(arr[0]);
        
        List list = new ArrayList();
        list.add("1");
        list.add("2");
        
        for(Object obj : list){
            String str = (String) obj;
            str = "3";
        }
        
    }

    @Test
    public void testForeach() {
        //取集合的数据
        List list = new ArrayList();
        list.add("1");
        list.add("2");
        
        for(Object obj : list){
            String str = (String) obj;
            System.out.println(obj);
        }
        
        //数组的数据
        int arr[] = {1,2,3};
        for(int num : arr){
            System.out.println(num);
        }
        
        //取map
        Map map = new LinkedHashMap();    //由于HashMap的存取顺序不一致,所以用HashMap的儿子LinkedHashMap
        map.put("1", "aa");
        map.put("2", "bb");
        map.put("3", "cc");
        
        //传统方式1
        Set set = map.keySet();
        Iterator it = set.iterator();
        while(it.hasNext()){
            String key = (String) it.next();
            String value = (String) map.get(key);
            System.out.println(key + "=" + value);
        }
        
        //传统方式2:超级重要  jstl
        set = map.entrySet();  //[Map.entry,Map.entry,Map.entry]
        it = set.iterator();
        while(it.hasNext()){
            Map.Entry me = (Entry) it.next();
            String key = (String) me.getKey();
            String value = (String) me.getValue();
        }
        
        
        //用增强for迭代map
        for(Object obj : map.entrySet()){
            Map.Entry me = (Entry) obj;
            System.out.println(me.getKey() + "=" + me.getValue());
        }
    }

}
由于HashMap的存取顺序不一致,所以这里要用HashMap的崽儿,LinkedHashMap
在java中就必须要有这种思想,当一个类的功能不行我们就去找它的儿子类
for高级for循环的注意事项:增强for循环只适合取数据,不要用它去修改数组和集合中的数据
 

4.可变参数

  测试JDK中具有可变参数的类Arrays.asList()方法。分别传多个参、传数组,传数组又传参的情况。
  •注意:传入基本数据类型数组的问题。
  从JDK 5开始, Java 允许为方法定义长度可变的参数。语法:

    public void foo(int … args){

   }

  注意事项:
  •调用可变参数的方法时, 编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以在方法体中以  数组的形式访问可变参数
  •可变参数只能处于参数列表的最后, 所以一个方法最多只能有一个长度可变的参数
package cn.itcast;

import java.util.Arrays;
import java.util.List;

public class Demo8 {

    /**可变参数
     * @param args
     */
    public static void main(String[] args) {
        //sum(1,2,3,4,5,67,87);
        
        List list = Arrays.asList("1","2","3","4");
        System.out.println(list);  //list.toString()
        
        //注意的问题:可变参数在传的时候可以直接传数组
        String s[] = {"11","22"};
        list = Arrays.asList(s);
        System.out.println(list);
        
//注意的问题:传基本数据类型数组时要千万小心,这里它会将arr最为一个Object存入list,如果这里你将类型改为Integer则可以将1,2,3存入到list中
    //因为这里的asList(T...a)中传递的参数必须是一个对象类型的参数 int arr[] = {1,2,3}; //Integer arr[] = {1,2,3}; list = Arrays.asList(arr); System.out.println(list); //[[I@dc8569] } public static void sum(int ... nums){ //拿到可变参数,当成数组用即可 int sum = 0; for(int num : nums){ sum += num; } System.out.println(sum); } }
这个可变参数很有使用
在class中
在数组帮助类中Arrays
这个方法表示可以接受一个或则多个Object对象,然后将这些对象保存到list集合中返回给你
这个方法在开发中用的很多
 
在用可变参数的注意事项:在使用可变参数的时候可以直接传递数组

04-枚举

•一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,此类问题在JDK5以前采用自定义带有枚举功能的类解决,Java5以后可以直接使用枚举予以解决。
/day01/src/cn/itcast/enumeration/Student.java
package cn.itcast.enumeration;

public class Student {
    private String name;
    //我们这里必须要求grade的值为A B C D E中的某一个
    //在没有学习枚举之前我们都是通过正则表达是来赛选的
    private String grade;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getGrade() {
        return grade;
    }
    public void setGrade(String grade) {
        //在没有学习枚举之前我们需要通过正则来筛选我们要的值
        if(!grade.matches("[ABCDE]")){
            throw new RuntimeException("对不起,grade的值必须为A B C D E");
        }
        this.grade = grade;
    }        
    
    
}

 /day01/src/cn/itcast/enumeration/Demo1.java

package cn.itcast.enumeration;

public class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        //这种方式的赋值并不好,因为编译器不回报错,等你输入好数据之后却会抛异常,体验不好
        s.setGrade("A");

    }

}

 

在JDK1.5之前则会使用自定义带有枚举功能的类来解决

/day01/src/cn/itcast/enumeration2/Student.java

package cn.itcast.enumeration2;

public class Student {
    private String name;
    //在JDK1.5之前程序员都是采用自定义带有枚举功能的类来解决限定某个变量的固定范围的值
    private Grade grade;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Grade getGrade() {
        return grade;
    }
    public void setGrade(Grade grade) {
        this.grade = grade;
    }        
    
}
//自定义带枚举功能的类
class Grade{
    private Grade(){}
    public static Grade A = new Grade();
    public static Grade B = new Grade();
    public static Grade C = new Grade();
    public static Grade D = new Grade();
    public static Grade E = new Grade();
}

 

 /day01/src/cn/itcast/enumeration2/Demo1.java

package cn.itcast.enumeration2;

public class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        //
        s.setGrade(Grade.A);

    }

}

 

 但是这个中自定义的方式也很麻烦,所以在JDK1.5之后就有了枚举,但是这个自定义的带有枚举功能的类就是枚举的原理

其实枚举就相当于一个类

 /day01/src/cn/itcast/enumeration3/Student.java

package cn.itcast.enumeration3;

public class Student {
    private String name;
    //在JDK1.5之后就有了枚举
    private Grade grade;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Grade getGrade() {
        return grade;
    }
    public void setGrade(Grade grade) {
        this.grade = grade;
    }        
    
}
//其实这个枚举就相当于一个自定义的Grade的类,其中的A,B,C,D,E就相当于五个Grade对象
enum Grade{    
    A,B,C,D,E;
}

 

 /day01/src/cn/itcast/enumeration3/Demo1.java

package cn.itcast.enumeration3;

public class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        s.setGrade(Grade.A);

    }

}

 

 下面我们来讲解一些枚举的高深的东西,有时候我们希望这个枚举中的每个对象(A,B,C,D,E)封装更多的东西

这个时候我们就可以在创建对象的时候通过构造方法传递参数,这里就相当于在(A,B,C,D,E)这些对象中通过

构造方法传递参数,于是每个对象就有了更多的信息,不过这里要注意,由于这个枚举只限定了固定的值,不允许外界

new对象,所以这里的的构造方法必须是私有的,还有点,由于这些A,B,C,D,E中的数据要想取出来,就必须提供对应的

get方法

 /day01/src/cn/itcast/enumeration4/Student.java

package cn.itcast.enumeration4;

public class Student {
    private String name;
    private Grade grade;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Grade getGrade() {
        return grade;
    }
    public void setGrade(Grade grade) {
        this.grade = grade;
    }        
    
}
//枚举的高深运用,我们想在枚举中的每个对象放更多的数据就可以通过构造方法来实现,不过这里的构造方法
//必须私有,防止外面new对象,因为枚举的原则就是只提供固定个数的对象,防止外部创建对象
//还有点就是这里的对象的参数是为外部提供的,所以外面必须提供相应的get方法获取到对象中的数据
enum Grade{    
    A("100-90"),B("90-80"),C("80-70"),D("70-60"),E("60-50");
    private String value;
    private Grade(String value){
        this.value = value;
    }
    public String getValue() {
        return value;
    }
}

/day01/src/cn/itcast/enumeration4/Demo1.java

package cn.itcast.enumeration4;

public class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        s.setGrade(Grade.A); 
        Grade grade = s.getGrade();
        String value = grade.getValue();
        System.out.println(value);
    }

}

 

接下来我们要给枚举中的每个对象添加相同名称的方法,但是每个对象的方法体不同,这个时候我们就想到在枚举中创建一个抽象类

在进一步我们想到匿名内部类,当创建对象的时候就将抽象方法实现就可以为每个对象添加相同名称的方法,但是每个对象的对方法的

实现却是不相同的

/day01/src/cn/itcast/enumeration5/Student.java

package cn.itcast.enumeration5;

public class Student {
    private String name;
    private Grade grade;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Grade getGrade() {
        return grade;
    }
    public void setGrade(Grade grade) {
        this.grade = grade;
    }        
    
}
//这里外面要给枚举中的每个对象提供相同名称的方法,但是方法体是是实现都不同
//这里外面想到的抽象方法,更进一步外面想到匿名内部类,只要在枚举中创建对象
//的时候将抽象方法是实现就可以了
enum Grade{    
    A("100-90"){
        public String getLocalValue(){
            return "优!";
        }
    },
    B("90-80"){
        public String getLocalValue(){
            return "良!";
        }
    },
    C("80-70"){
        public String getLocalValue(){
            return "差!";
        }
    },
    D("70-60"){
        public String getLocalValue(){
            return "及格!";
        }
    },
    E("60-50"){
        public String getLocalValue(){
            return "不及格!";
        }
    };
    private String value;
    private Grade(String value){
        this.value = value;
    }
    public String getValue() {
        return value;
    }
    public  abstract String getLocalValue();
}

/day01/src/cn/itcast/enumeration5/Demo1.java

package cn.itcast.enumeration5;

public class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        s.setGrade(Grade.A); 
        Grade grade = s.getGrade();
        String value = grade.getValue();
        System.out.println(value);
        System.out.println(grade.getLocalValue());
    }

}
•枚举类也是一种特殊形式的Java类。
•枚举类中声明的每一个枚举值代表枚举类的一个实例对象。
•与java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但枚举类的构造函数必须为私有的(这点不难理解)。
•枚举类也可以实现接口、或继承抽象类。
•JDK5中扩展了swith语句,它除了可以接收int, byte, char, short外,还可以接收一个枚举类型。
•若枚举类只有一个枚举值,则可以当作单态设计模式使用。

 

lJava中声明的枚举类,均是java.lang.Enum类的孩子,它继承了Enum类的所有方法。常用方法:
•name()      //这个获取到枚举对象的名称
•ordinal()     //这个返回的是枚举对象在枚举中的排名位置
•valueof(Class enumClass, String name)    //这个方法可以将字符串转成枚举,也就是通过指定的枚举字符串名称获取到枚举的值
•values() 此方法虽然在JDK文档中查找不到,但每个枚举类都具有该方法,它遍历枚举类的所有枚举值非常方便。

 

 注意枚举还有一个values这个方法,这个方法在JDK中是查不到了,这个方法可以得到枚举中的所有值,返回的是一个枚举类型的数组

另外枚举的valueOf("Sting str")也是查不到这个方法的,这个方法和valueOf(Class<T> enumType,String name)是重载关系

 /day01/src/cn/itcast/enumeration6/Student.java

package cn.itcast.enumeration6;

public class Student {
    private String name;
    private Grade grade;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Grade getGrade() {
        return grade;
    }
    public void setGrade(Grade grade) {
        this.grade = grade;
    }        
    
}
//Java中申明的枚举都是Enum的子类,这个Enum提供了一些方法
enum Grade{    
    A("100-90"){
        public String getLocalValue(){
            return "优!";
        }
    },
    B("90-80"){
        public String getLocalValue(){
            return "良!";
        }
    },
    C("80-70"){
        public String getLocalValue(){
            return "差!";
        }
    },
    D("70-60"){
        public String getLocalValue(){
            return "及格!";
        }
    },
    E("60-50"){
        public String getLocalValue(){
            return "不及格!";
        }
    };
    private String value;
    private Grade(String value){
        this.value = value;
    }
    public String getValue() {
        return value;
    }
    public  abstract String getLocalValue();
}

 

/day01/src/cn/itcast/enumeration6/Demo1.java

package cn.itcast.enumeration6;

public class Demo1 {

    public static void main(String[] args) {
        Student s = new Student();
        s.setGrade(Grade.A); 
        Grade grade = s.getGrade();
        String value = grade.getValue();
        System.out.println(value);
        System.out.println(grade.getLocalValue());
        //Java中申明的枚举都是Enum的子类,这个Enum提供了一些方法
        //name()获取枚举的名称
        String name = grade.name();
        System.out.println(name);
        //ordinal()这个方法获取到枚举对象在枚举中的排位
        int order = grade.ordinal();
        System.out.println(order);
        //valueOf(Class<T> enumType,String name)这个方法获取到枚举的值
        //这个方法的重载形式是valueOf(String name)
        //这两个方法都是通过给定的字符串名称返回相应的枚举
        Grade g1 = Grade.valueOf(Grade.class, "A");
        Grade g2 = Grade.valueOf("A");
        System.out.println(g1);
        System.out.println(g2);
        //枚举还有一个在JDK中查找不到的方法values(),这个方法可以获取到枚举中所有的对象以枚举类型的数组形式返回
        //注意这个方法是静态的
        Grade grades[] = Grade.values();
        for(Grade g : grades){
            System.out.println(g.name());
        }
        
    }

}

 

05-反射概念和反射构造函数、方法

 今天最重要的知识点就是反射

一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分。

lClass对象提供了如下常用方法:

Public  Constructor  getConstructor(Class<?>... parameterTypes)

Public  Method  getMethod(String name, Class<?>... parameterTypes)

Public  Field  getField(String name)   public

 

public Constructor getDeclaredConstructor(Class... parameterTypes)

public Method getDeclaredMethod(String name,Class... parameterTypes)

public Field getDeclaredField(String name)  

加载类

Java中有一个Class类用于代表某一个类的字节码
得到一个类的字节码有三种方式
第一种通过class的静态方法forName(String className)获取到
第二种通过类.class获取到
第三种通过对象.getClass()获取到
/day01/src/cn/itcast/reflect/Person.java
package cn.itcast.reflect;

public class Person {
    
}

 /day01/src/cn/itcast/reflect/Demo1.java

package cn.itcast.reflect;

public class Demo1 {


    public static void main(String[] args) throws ClassNotFoundException {
        //第一种方式通过class的静态方法forName(String name)获取到Person类的字节码
        Class person1 = Class.forName("Person");
        //第二种方式通过类.class获取到Person类的字节码
        Class person2 = Person.class;
        //第三种方式通过对象.getClass()方法获取到Person类的字节码
        Class person3 = new Person().getClass();
    }

}

 

 解剖类

 得到了类的字节码之后我们就可以解剖类,从而得到类中属性,方法,构造方法等类成员,这里的成员包括私有的和共有的

我们先来反射构造方法,无论是私有的还是共有的,无论是无参数的,还是有参数的构造方法都可以反射

/day01/src/cn/itcast/reflect/Person.java

 

package cn.itcast.reflect;

import java.util.List;

public class Person {
    private String name="李四";
    
    public Person(){
        System.out.println("公共无参数构造方法");
    }
    
    public Person(String name){
        this.name = name;
        System.out.println("公共且有一个参数构造方法");
    }
    
    public Person(String name ,int[] arr,List list){
        System.out.println("公共且有三个参数的构造方法");
    }
    
    private Person(List[] list){
        System.out.println("私有且有一个参数的构造方法");
    }

    public String getName() {
        return name;
    }
    
}

 

 /day01/src/cn/itcast/reflect/Demo2.java

package cn.itcast.reflect;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class Demo2 {

    @Test
    //public Person()
    public  void test1() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //这里一定注意,forName(String str)参数要写完整路径
        Class clazz = Class.forName("cn.itcast.reflect.Person");
        //获取到无参数且公有的构造方法,如果没有参数就将参数写为null
        Constructor c = clazz.getConstructor(null);
        //更具构造方法创建一个实例对象
        Person p1 = (Person) c.newInstance(null);
        System.out.println( p1.getName());
    }
    @Test
    public  void test5() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //这里一定注意,forName(String str)参数要写完整路径
        Class clazz = Class.forName("cn.itcast.reflect.Person");
        //当构造方法没有参数时,可以直接通过字节码文件实例化一个对象
        Person p1 = (Person) clazz.newInstance();
        System.out.println( p1.getName());
    }
    
    
    @Test
    //public Person(String name)
    public  void test2() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //这里一定注意,forName(String str)参数要写完整路径
        Class clazz = Class.forName("cn.itcast.reflect.Person");
        //获取公共的且有一个参数的构造方法,这里传递的参数必须是参数的类型的字节码文件
        Constructor c = clazz.getConstructor(String.class);
        //更具构造方法创建一个实例对象,注意这里传递的参数要和构造方法中的参数对应
        Person p1 = (Person) c.newInstance("张三");
        System.out.println( p1.getName());
    }
    @Test
    //public Person(String name ,int[] arr,List list)
    public  void test3() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //这里一定注意,forName(String str)参数要写完整路径
        Class clazz = Class.forName("cn.itcast.reflect.Person");
        //获取公共的且有多个参数的构造方法,这里传递的参数必须是对应参数的类型的字节码文件
        Constructor c = clazz.getConstructor(String.class,int[].class,List.class);
        //更具构造方法创建一个实例对象,注意这里传递的参数要和构造方法中的参数对应
        Person p = (Person) c.newInstance("张三",new int[8],new ArrayList());
        System.out.println( p);
    }
    @Test
    //private Person(List[] list)
    public  void test4() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
        //这里一定注意,forName(String str)参数要写完整路径
        Class clazz = Class.forName("cn.itcast.reflect.Person");
        //获取私有的且有一个参数的构造方法,这里传递的参数必须是对应参数的类型的字节码文件
        //这里还要注意,在获取私有的构造方法的时候要用getDeclaredContructor
        Constructor c = clazz.getDeclaredConstructor(List[].class);
        //要访问私有的构造方法,就必须暴力反射
        c.setAccessible(true);
        //更具构造方法创建一个实例对象,注意这里传递的参数要和构造方法中的参数对应
        //注意这里,需要转化成Object,这里稍后讲解
        Person p = (Person) c.newInstance((Object)new ArrayList[5]);
        System.out.println( p);
    }
    

}

 下面我们来反射方法,这里的方法宝库有参数的,无参数的,私有的,共有的,静态的,已经主函数

/day01/src/cn/itcast/reflect1/Person.java

package cn.itcast.reflect1;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Person {
    private String name="李四";
    
    public String getName() {
        return name;
    }
    
    //公共且没有参数也没有返回值的的方法
    public void method(){
        System.out.println("公共且没有参数没有返回值的方法");
    }
    //公共且有一个参数,但没有返回值的方法
    public void method(String name){
        System.out.println("公共且有一个参数,但没有返回值的方法");
    }
    //公共且有多个参数,但没有返回值的方法
    public void method(String name,int[] arr){
        System.out.println("公共且有多个参数,但没有返回值的方法");
    }
    //公共且有多个参数且有返回值的方法
    public List method2(String name,List list){
        return list;
    }
    //私有且有多个参数且有返回值的方法
    private int[] method3(List list){
        return new int[]{1,2,3};
    }
    //公共且静态且有参数的方法
    public static void method4(Map map){
        System.out.println("公共且静态且有参数的方法");
    }

}

 

 /day01/src/cn/itcast/reflect1/Demo3.java

package cn.itcast.reflect1;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;

public class Demo3 {

    @Test
    //public void method()公共且没有参数也没有返回值的的方法
    public void test1() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException{
        //反射公共且没有参数也没有返回值的的方法
        Class<?> clazz = Class.forName("cn.itcast.reflect1.Person");
        //通过类字节码得到方法,这里有两个参数,一个是方法的名称,一个是方法的参数类型字节码,如果没有参数则写null
        Method method = clazz.getMethod("method", null);
        //方法要被调用才能起作用,而且一般的方法都是由对象调用的
        //所以这里先得到对象,另外如果没有参数则传入null
        Person p = (Person) clazz.newInstance();
        method.invoke(p, null);
    }
    @Test
    //public void method(String name)公共且有一个参数,但没有返回值的方法
    public void test2() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException{
        //反射公共且有一个参数,但没有返回值的方法
        Class<?> clazz = Class.forName("cn.itcast.reflect1.Person");
        //通过类字节码得到方法,这里有两个参数,一个是方法的名称,一个是方法的参数类型字节码,如果没有参数则写null
        Method method = clazz.getMethod("method", String.class);
        //方法要被调用才能起作用,而且一般的方法都是由对象调用的
        //所以这里先得到对象,另外如果没有参数则传入null
        Person p = (Person) clazz.newInstance();
        method.invoke(p, "李四");
    }
    @Test
    //public void method(String name,int[] arr)公共且有多个参数,但没有返回值的方法
    public void test3() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException{
        //反射公共且有多个参数,但没有返回值的方法
        Class<?> clazz = Class.forName("cn.itcast.reflect1.Person");
        //通过类字节码得到方法,这里有两个参数,一个是方法的名称,一个是方法的参数类型字节码,如果有多个参数则都要传递
        Method method = clazz.getMethod("method", String.class,int[].class);
        //方法要被调用才能起作用,而且一般的方法都是由对象调用的
        //所以这里先得到对象,另外如果没有参数则传入null
        Person p = (Person) clazz.newInstance();
        method.invoke(p, "李四",new int[]{1,3,4});
    }
    @Test
    //public List method2(String name,List list)公共且有多个参数且有返回值的方法
    public void test4() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException{
        //反射公共且有多个参数且有返回值的方法
        Class<?> clazz = Class.forName("cn.itcast.reflect1.Person");
        //通过类字节码得到方法,这里有两个参数,一个是方法的名称,一个是方法的参数类型字节码,如果有多个参数则都要传递
        Method method = clazz.getMethod("method2", String.class,List.class);
        //方法要被调用才能起作用,而且一般的方法都是由对象调用的
        //所以这里先得到对象,另外如果没有参数则传入null
        Person p = (Person) clazz.newInstance();
        //如果方法有返回值则需要接收打印
        List list =(List) method.invoke(p, "李四",new ArrayList());
        System.out.println(list);
    }
    @Test
    //private int[] method3(List list)私有且有多个参数且有返回值的方法
    public void test5() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException{
        //反射私有且有多个参数且有返回值的方法
        Class<?> clazz = Class.forName("cn.itcast.reflect1.Person");
        //私有方法要通过getDeclaredMethod方法获取字节码文件
        Method method = clazz.getDeclaredMethod("method3",List.class);
        //由于这里的方法是私有的,所以需要暴力反射
        method.setAccessible(true);
        //方法要被调用才能起作用,而且一般的方法都是由对象调用的
        //所以这里先得到对象,另外如果没有参数则传入null
        Person p = (Person) clazz.newInstance();
        //如果方法有返回值则需要接收打印
        int[] arr =(int[]) method.invoke(p,new ArrayList());
        System.out.println(arr);
    }
    @Test
    //public static void method4(Map map)公共且静态且有参数的方法
    public void test6() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException{
        //反射公共且静态且有参数的方法
        Class<?> clazz = Class.forName("cn.itcast.reflect1.Person");
        //私有方法要通过getDeclaredMethod方法获取字节码文件
        Method method = clazz.getDeclaredMethod("method4",Map.class);
        //这里由于是静态方法,所有调用时可以没有对象调用,当然也可以由对象调用
        //Person p = (Person) clazz.newInstance();
        method.invoke(null,new HashMap());
    }
    
}

对于反射主方法,我们需要特别注意要将String[] args包装成Object[]

/day01/src/cn/itcast/reflect2/Person.java

package cn.itcast.reflect2;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

public class Person {

    public static void main(String[] args){
        System.out.println("主方法反射");
    }

}

 

 /day01/src/cn/itcast/reflect2/Demo.java

package cn.itcast.reflect2;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;

public class Demo {
    @Test
    //反射主函数
    public void test() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
        Class clazz = Class.forName("cn.itcast.reflect2.Person");
        Method main = clazz.getMethod("main", String[].class);
        //反射主函数的时候需要注意,在传递参数时不能直接传递new String[]{"1","2","3"},需要将其包装成Object再传递
        //因为这个invoke这个方法中JDK1.5之前是传递到Object数组,JDK1.5之后传递的则是可变参数
        //public Object invoke(Object obj,Object... args)        //这个是JDK1.5之后的
        //public Object invoke(Object obj,Object[] args)        //这个是JDK1.4之前的
        //由于新的JDK要兼容旧的JDK,所以,所以在传递参数的时候会将new String[]{"1","2","3"}拆掉
        //所以这个main.invoke(null,new String[]{"1","2"})就会去找main("1","2")这个方法,由于
        //找不到所以要报错
        //我们这里提供了两种解决方案,都能将String[]{"1","2"}包装成Object[],从而避免错误
        main.invoke(null, new Object[]{new String[]{"1","2"}});
        main.invoke(null, (Object)new String[]{"1","2"});
        
    }
}

 

 下面讲解反射字段,我们得到字段都是为了封装数据的

所以在字段Field中有很多封装数据的方法,在封装数据要指明是封装到哪个对象上的,所以这里有两个参数

通常我们用set(Object obj,Object value)这个方法

 另外通过反射获取到字段之后可以得到字段中的值

通常我们用get()这个方法,但是为了避免强转,有时候我们用相应的方法

 另外一点字段在类中都是以私有方式体现的,所以这里我们只演示通过反射获取私有字段

/day01/src/cn/itcast/reflect3/Person.java

 

package cn.itcast.reflect3;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

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;
    }


}

/day01/src/cn/itcast/reflect3/Demo.java

package cn.itcast.reflect3;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.junit.Test;

public class Demo {
    @Test
    //反射私有字段,得到私有字段之后然后为其赋值
    public void test1() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, InstantiationException{
        Class clazz = Class.forName("cn.itcast.reflect3.Person");
        //这里要获取私有的字段必须用getDeclaredField
        Field field = clazz.getDeclaredField("name");
        //暴力反射
        field.setAccessible(true);
        //为这个字段封装数据,我们一般得到字段都是为了向其封装数据,这里也不例外
        //在封装数据的时候我们要指定将其封装到哪个对象中,所以我们这里要得到对象
        Person p = (Person) clazz.newInstance();
        field.set(p, "张三");
        System.out.println(p.getName());
    }
    @Test
    //反射私有字段,并得到字段的数据
    public void test2() throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, NoSuchFieldException, InstantiationException{
        Class clazz = Class.forName("cn.itcast.reflect3.Person");
        //这里要获取私有的字段必须用getDeclaredField
        Person p = (Person) clazz.newInstance();
        //先为私有字段赋一个值
        p.setAge(20);
        Field field = clazz.getDeclaredField("age");
        //暴力反射
        field.setAccessible(true);
        //通过反射得到字段之后,我们需要将其中的数据取出来
        //这里要指明是要得到那个对象中的这个字段数据
            System.out.println(field.get(p));
        
    }
}

———————————————————————————————————————————————————————————————————————

 06-java内省api

 内省其实也是一种反射,只不过它反射的是JavaBean

 什么是JavaBean,什么是javaBean的属性

当一个对象中封装数据就是一个bean,并且可以通过get和set方法获取和设置,那么这个类就叫做bean,当bean中的字段有get和set方法时则这些字段叫做bean的属性,一个javaBean拥有什么属性其实是由get方法决定了,每个javaBean中都有一个隐藏的属性class,因为每个类都是Object的子类,Object中有一个getClass()方法

 内省技术就是用来操作javabean属性的

 在JDK API中就有这样一个类Introspector(内省类)发射javaBean的

通过它的getBeanInfo方法就可以将需要得到的javaBean反射到并封装到一个BeanInfo对象中

 但是这个BeanInfo却是一个接口,但是这个通过getBeanInfo方法返回到是一个BeanInfo的实例对象,

这个BeanInfo的实力对象中就封装了bean的所有属性

在BeanInfo这个实力对象中我们可以调用getPropertyDescriptors()方法就可以讲bean中的属性全部获取到

然后保存到一个PropertyDescriptor[]数组中,通过循环取出PropertyDescriptor[]中的每个PropertyDescriptor(属性描述器)

我们就可以通过ProperryDescriptor中的getReadMethod()和getWriteMethod()方法获取到属性的对应的get和set方法,

进而我们可以对javabean中的属性进行操作

当然如果我们还可以通过PropertyDescriptor中的构造方法去指定操作某个javabean对象的那个属性

 /day01/src/cn/itcast/introspector/Student.java

package cn.itcast.introspector;
//所谓的javabean就是一个类中的字段拥有get和set方法
//javabean中的字段不再成为字段,而是成为属性,javabean中的属性是由get方法决定了
//就像这个bean中的getXx()方法中的Xx也是这个bean中的属性
//另外每个javabean中都有一个隐藏的属性class,因为每个类都会从Object那里继承一个getClass()方法
public class Student {
    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 void getXx(){
        
    }
}

 

 /day01/src/cn/itcast/introspector/Demo.java

package cn.itcast.introspector;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.junit.Test;

//通过内省获取到javabean中的数据
public class Demo {
    
    @Test
    public void test1() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
        //通过getBeanInfo方法获取到指定的javabean中的数据并封装到一个BeanInfo的实例对象中(这个BeanInfo是一个接口)
        BeanInfo bean = Introspector.getBeanInfo(Student.class);
        //通过BeanInfo方法getPropertyDescriptors()方法获取到所有的属性描述
        PropertyDescriptor[] pd = bean.getPropertyDescriptors();
        //通过循环取出每个属性描述器
        for(PropertyDescriptor p : pd){
            //当这个属性的名称是name时,我们拿到它的set方法
            if("name".equals(p.getName())){
                Method method =p.getWriteMethod();
                //拿到它的set方法之后需要通过对象调用,所以我们这里new一个Student对象,还有我们需要传入参数
                Student s = new Student();
                method.invoke(s, "张三");
                //通过传统方式取出name
                System.out.println(s.getName());
            }
        }
    }
    @Test
    public void test2() throws IntrospectionException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
        //通过getBeanInfo方法获取到指定的javabean中的数据并封装到一个BeanInfo的实例对象中(这个BeanInfo是一个接口)
        BeanInfo bean = Introspector.getBeanInfo(Student.class);
        //我们这里不通过循环就可以拿到拿到想要的javabean中的属性,主要是通过PropertyDescriptor的构造方法
        PropertyDescriptor ps =new PropertyDescriptor("age",Student.class);
        //然后在通过属性描述器的方法获取到set方法设置age的值
        Method method = ps.getWriteMethod();
        Student s = new Student();
        method.invoke(s, 20);
        //通过传统方式获取到age的值
        System.out.println(s.getAge());
    
    }
}

 

 由于SUN公司开发的这套操作javabean对象的api很麻烦,于是有些开源组织就开发了beanutils框架来操作javabean对象

 

 ————————————————————————————————————————————————————————————————————————

07-beanutils框架

Sun公司的内省API过于繁琐,所以Apache组织结合很多实际开发中的应用场景开发了一套简单、易用的API操作Bean的属性——BeanUtils

 由于beanutils是第三方开发的,所以如果我们想要使用它就必须导入它的jar包

首先我们在工程项目下建立一个lib文件夹,将commons-beanutils-1.8.0.jar复制到lib下

 

将上面的commons-beanutils-1.8.0.jar复制到lib文件夹下

 然后我们要将整个jar包加入到我们工程的构建路径里面去,这样java虚拟机才能找到整个jar包

在这个jar包上鼠标右键-->Build Path-->Add to Build Path

需要注意的是这个apache开发的BeanUtils包依赖log4j这个包中的commons-beanutils-1.8.0.jar,

所以在用BeanUtils框架时记得要导入log4j这个包中的commons-beanutils-1.8.0.jar包

同样我们将commons-logging.jar复制到lib包中然后加载到构建路径中去

 BeanUtils的核心类就是BeanUtils,这个类可以直接获取和设置bean中属性的值

 

在为bean对象属性设置值的时候,还可以自动将字符串转换成相对应的类型,对于非八种基本类型的则需要自己注册一个转换器转换,比如

要给生日赋值时就需要自己写日期转换器,虽然框架中提供了已经写好的转换器但是并不完美,因为当数据是""这个的时候就会出错

我们自己写转换器要用到ConvertUtils这个类的register方法

这个方法中的Converter是一个接口,我们需要实现其方法convert,所以我们想到了匿名内部类

在转换的过程中,我们拿到数据需要多次判断,防止数据为空或者其它什么问题

另外还要注意一点,这个转换器是被别人调用的,在没有转换成功的时候向上抛异常,告诉调用者

而且这里抛的异常建议抛ConversionExceptioin

另外一点BeanUtils框架提供了很多转换器,但是对于日期的转换并不完美,因为当数据时""时就会报错

/day01/src/cn/itcast/beanutils/Student.java

package cn.itcast.beanutils;

import java.util.Date;

public class Student {
    private String name;
    private int age;
    private Date birthday;
    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;
    }
    
}

/day01/src/cn/itcast/beanutils/Demo.java

package cn.itcast.beanutils;

import java.lang.reflect.InvocationTargetException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.ConversionException;
import org.apache.commons.beanutils.ConvertUtils;
import org.apache.commons.beanutils.Converter;
import org.apache.commons.beanutils.locale.converters.DateLocaleConverter;
import org.junit.Test;

public class Demo {
    
    @Test
    //BeanUtils的核心类就是BeanUtils,这个类可以可以直接设置和获取bean对象的属性的值
    public void test1() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
        Student s = new Student();
        BeanUtils.setProperty(s, "name", "张三");
        String name = BeanUtils.getProperty(s, "name");
        System.out.println(name);
    }
    @Test
    //BeanUtils在设置bean对象属性的值的时候可以自动将字符串转换成相应类型的属性值(前提是只限于八种基本数据类型)
    public void test2() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
        Student s = new Student();
        //BeanUtils类在设置bean对象的属性值的时候可以自动将字符串转换相应的类型(前提是只限于八种基本数据类型)
        BeanUtils.setProperty(s, "age", "20");
        //得到的任何类型的属性值都是以字符串形式返回的
        String age = BeanUtils.getProperty(s, "age");
        System.out.println(age);
    }
    @Test
    //对于不是八种基本数据类型,BeanUtils框架中可以自定义转换器,比如这里我要为Student的birthday赋值
    //赋予的值是一个字符串时间,而实际上birthday需要的是一个Date
    public void test3() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
        Student s = new Student();
        //BeanUtils中对于不是八种基本数据类型的数据的转化则需要自定义转换器
        //我们用BeanUtils的public static void register(Converter converter,Class clazz)这个方法去注册一个转换器
        //这个方法中的Converter是一个接口需要实现它的Object convert(Class type,Object value)方法
        //当然这里已经有Converter的实现类,但是并不完美,稍后我们会谈论为什么
        ConvertUtils.register(new Converter(){
            
            public Object convert(Class type, Object value) {
                //得到数据首先就必须对其判断是否为空
                if(value==null){
                    return null;
                }
                //如果数据不为空还要判断是否数据是否为String
                //如果转换失败这里建议抛ConversionException异常
                if(!(value instanceof String)){
                    throw new ConversionException("支持字符串的转换");
                }
                String date = (String) value;
                //防止输入多个空格
                if(date.trim()==null){
                    return null;
                }
                SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
                try {
                    return sdf.parseObject(date);
                } catch (ParseException e) {
                    // 由于你这个转换器是给人家调用的,转换失败要提醒别人
                    //所以要向上抛一个异常,并且要将异常的信息抛给上级
                    //这里的e就包含了异常信息
                    throw new ConversionException(e);
                }
            }        
        }, Date.class);
        BeanUtils.setProperty(s, "birthday", "2000-01-01");
        //得到的任何类型的属性值都是以字符串形式返回的
        String birthday = BeanUtils.getProperty(s, "birthday");
        System.out.println(birthday);
    }
    
    @Test
    //BeanUtils在设置bean对象属性的值的时候可以自动将字符串转换成相应类型的属性值(前提是只限于八种基本数据类型)
    //并且BeanUtils框架提供了很多转换器,但是日期转换器并不完美,当数据时""时会报错
    public void test4() throws IllegalAccessException, InvocationTargetException, NoSuchMethodException{
        Student s = new Student();
        //BeanUtils类在设置bean对象的属性值的时候可以自动将字符串转换相应的类型(前提是只限于八种基本数据类型)
        Converter converter = new DateLocaleConverter();
        ConvertUtils.register(converter, Date.class);
        //当我这里的日期设置成""则会报错,所以这里的日期转换器不完美
        BeanUtils.setProperty(s, "birthday", "2011-12-25");
        //得到的任何类型的属性值都是以字符串形式返回的
        String birthday = BeanUtils.getProperty(s, "birthday");
        System.out.println(birthday);
    }
    
}

 

 

 

 

 

posted @ 2013-10-07 15:13  ysfox  阅读(227)  评论(1)    收藏  举报