JDK5中的重要特性

来源:互联网 发布:微信会员卡源码下载 编辑:程序博客网 时间:2024/06/05 15:41

目录

  • 目录
  • 静态导入
  • 自动装箱拆箱
  • 增强for循环
  • 可变参数
  • 枚举类
  • 反射
    • 加载类
    • 解剖类
    • 利用Constructor创建对象
    • 利用Method执行方法
    • 反射字段
  • 内省Introspector
  • BeanUtils框架
  • 泛型Generic
    • 泛型的使用
    • 自定义泛型
      • 自定义泛型方法
      • 自定义泛型类

静态导入

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

   这样导入后可以在类中直接使用导入的静态属性和静态方法。

自动装箱/拆箱

  • 自动装箱:指开发人员可以把一个基本数据类型直接赋给对应的包装类。
Integer i = 1; // 装箱:实际上,是运行时jvm将基本数据类型包装为对应的类对象,再进行赋值
  • 自动拆箱:指开发人员可以把一个包装类对象直接赋给对应的基本数据类型。
int j = i; // 拆箱(i是上述例子中的一个对象)
  • 典型应用:
List list = new ArrayList();list.add(1); // list.add只能是加入对象int j = (Integer)list.get(0);
import java.util.ArrayList;import java.util.Iterator;import java.util.List;/** * Created by DreamBoy on 2017/4/23. */public class TestDemo {    public static void main(String[] args) {        List list = new ArrayList();        list.add(1);        list.add(2);        list.add(3);        Iterator it = list.iterator();        while (it.hasNext()) {            int j = (Integer) it.next(); // 拆箱            System.out.println(j);        }    }}

增强for循环

  • 增强for循环只能用在数组或实现Iterable接口的集合类上。
import org.junit.Test;import java.util.*;/** * Created by DreamBoy on 2017/4/23. *//** * 增强for */public class Demo01 {    @Test    public void test1() {        int arr[] = {1, 2, 3};        for (int num : arr) {            System.out.println(num);        }    }    @Test    public void test2() {        List list = new ArrayList();        list.add(1);        list.add(2);        list.add(3);        for (Object obj : list) {            int i = (Integer) obj;            System.out.println(i);        }    }    @Test    public void test3() {        //Map map = new HashMap();        Map<String, String> map = new LinkedHashMap<>();        map.put("1", "aaa");        map.put("2", "bbb");        map.put("3", "ccc");        // 方法1:        System.out.println("遍历Map——方法1:");        Set set1 = map.keySet();        Iterator it1 = set1.iterator();        while (it1.hasNext()) {            String key = (String) it1.next();            String value = map.get(key);            System.out.println(key + '=' + value);        }        // 增强for循环方法1:        System.out.println("遍历Map——增强for循环方法1:");        for (Object obj: map.keySet()) {            String key = (String) obj;            String value = map.get(key);            System.out.println(key + '=' + value);        }        // 方法2:        System.out.println("遍历Map——方法2:");        Set set2 = map.entrySet();        Iterator it2 = set2.iterator();        while (it2.hasNext()) {            Map.Entry entry = (Map.Entry) it2.next();            String key = (String) entry.getKey();            String value = (String) entry.getValue();            System.out.println(key + '=' + value);        }        // 增强for循环方法2:        System.out.println("遍历Map——增强for循环方法2:");        for (Object obj: map.entrySet()) {            Map.Entry entry = (Map.Entry) obj;            String key = (String) entry.getKey();            String value = (String) entry.getValue();            System.out.println(key + '=' + value);        }    }}
  • 注意点:增强for只适合取数据,要修改数组或集合中的数据,只能要传统的for方式。

可变参数

import org.junit.Test;import java.util.Arrays;import java.util.List;/** * Created by DreamBoy on 2017/4/23. */public class Demo02 {    @Test    public void testSum() {        sum(1, 2, 3, 4);        int[] arr = {1, 2, 3, 4};        sum(arr);    }    public int sum(int ...nums) { // 可变参数,我们可以将其看成是一个数组        int total = 0;        for (int i: nums) {            total += i;        }        System.out.println(total);        return total;    }    // 可变参数:public void other(int ...nums, int x) 这样写是错误的!    public void other(int x, int ...nums) {    }    @Test    public void test1() {        List list = Arrays.asList("1", "2", "3");        System.out.println(list);        String arr[] = {"1", "2", "3", "4"};        list = Arrays.asList(arr);        System.out.println(list);        int nums[] = {1, 2, 3, 4};        list = Arrays.asList(nums); // 注意:可变参数,接收的类型。Arrays.asList接收的是对象类型,这里会将整个数组看成是一个对象        System.out.println(list);        Integer iNums[] = {1, 2, 3, 4};        list = Arrays.asList(iNums);        System.out.println(list);    }}

  test1方法的运行结果如下:

[1, 2, 3][1, 2, 3, 4][[I@1b4fb997] // 数组中包含了一个数组[1, 2, 3, 4]

枚举类

  • 为什么需要枚举?
      一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,此类问题在JDK5以前采用自定义带有枚举功能的类解决,Java5以后可以直接使用枚举予以解决。
/** * Created by DreamBoy on 2017/4/23. */import org.junit.Test;/** * 枚举 */public class DemoEnum {    @Test    public void test() {        print(Grade.A);    }    public void print(Grade g) { // 限定为 A、B、C、D、E    }}/** * JDK5以前 *//*class Grade {    private Grade() {}    public static final Grade A = new Grade();    public static final Grade B = new Grade();    public static final Grade C = new Grade();    public static final Grade D = new Grade();    public static final Grade E = new Grade();}*//** * 枚举 */enum Grade {    A, B, C, D, E; // 枚举的值}
  • 一个枚举也可以有构造函数、字段和方法。
/** * Created by DreamBoy on 2017/4/23. */import org.junit.Test;/** * 枚举 */public class DemoEnum {    @Test    public void test() {        print(Grade.A);    }    public void print(Grade g) { // 限定为 A、B、C、D、E        System.out.println(g.getValue());    }}/** * JDK5以前 *//*class Grade {    private Grade() {}    public static final Grade A = new Grade();    public static final Grade B = new Grade();    public static final Grade C = new Grade();    public static final Grade D = new Grade();    public static final Grade E = new Grade();}*//** * 枚举 */enum Grade {    A("100-90"), B("89-80"), C("79-70"), D("69-60"), E("59-0"); // 枚举的每一个值    private String value; // 封装每个对象对应的分数    private Grade(String value) {        this.value = value;    }    public String getValue() {        return this.value;    }}
  • 带抽象方法的枚举
/** * Created by DreamBoy on 2017/4/23. */import org.junit.Test;/** * 枚举 */public class DemoAEnum {    @Test    public void test() {        print(AbstractGrade.A);    }    public void print(AbstractGrade g) { // 限定为 A、B、C、D、E        System.out.println(g.getValue());        System.out.println(g.localeValue());    }}/** * JDK5以前 *//*class Grade {    private Grade() {}    public static final Grade A = new Grade();    public static final Grade B = new Grade();    public static final Grade C = new Grade();    public static final Grade D = new Grade();    public static final Grade E = new Grade();}*//** * 带抽象方法的枚举 */enum AbstractGrade {    A("100-90") { // 这里相当于创建枚举对象,并实现抽象方法        public String localeValue() {            return "优";        }    },    B("89-80") {        public String localeValue() {            return "良";        }    },    C("79-70") {        public String localeValue() {            return "中";        }    },    D("69-60") {        public String localeValue() {            return "差";        }    },    E("59-0") {        public String localeValue() {            return "不及格";        }    }; // 枚举的每一个值    private String value; // 封装每个对象对应的分数    private AbstractGrade(String value) {        this.value = value;    }    public String getValue() {        return this.value;    }    public abstract String localeValue();}
  • 枚举类具有如下特性:
    1. 枚举类也是一种特殊形式的Java类
    2. 枚举类中声明的每一个枚举值代表枚举类的一个实例对象
    3. 与java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但枚举类的构造函数必须为私有的
    4. 枚举类也可以实现接口或继承抽象类。
    5. JDK5中扩展了switch语句,它除了可以接收int, byte, char, short外,还可以接收一个枚举类型。
    6. 若枚举类只有一个枚举值,则可以当作单例设计模式使用。
  • Java中声明的枚举类,均是java.lang.Enum类的子类,它继承了Enum类的所有方法。常用方法:name()ordinal()valueOf(Class enumClass, String name)values()(用于遍历枚举的所有枚举值)。其中valueOfvalues方法均为静态方法。
     /**     * 测试枚举的常用方法     */    @Test    public void test2() {        AbstractGrade g = AbstractGrade.C;        System.out.println(g.name());        System.out.println(g.ordinal());        String str = "B";        //g = AbstractGrade.valueOf(str);        g = AbstractGrade.valueOf(AbstractGrade.class, str);        System.out.println(g.name());        System.out.println(g.ordinal());        AbstractGrade[] gs = AbstractGrade.values();        for (AbstractGrade g2: gs) {            System.out.println(g2);        }    }

反射

  • 一个类有多个组成部分,例如:成员变量,方法,构造方法等。反射就是加载类,并解剖出类的各个组成部分。
  • Java中有一个Class类用于代表某一个类的字节码。

加载类

  • Class类即代表某个类的字节码,它提供加载某个类字节码的方法:forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装。
  • 另外两种得到class对象的方式:
    1. 类名.class,如Person.class;
    2. 对象.getClass(),如new Person().getClass()。

解剖类

  • Class对象提供了如下常用方法:
public Constructor getConstructor(Class<?>... parameterTypes)public Method getMethod(String name, Class<?>... parameterTypes)public Field getField(String name)

  以上方法只适用于获取类中public修饰符修饰的构造函数、方法或成员变量。
  如果需要获取private的,则使用如下方法:

public Constructor getDeclaredConstructor(Class... parameterTypes)public Method getDeclaredMethod(String name, Class... parameterTypes)public Field getDeclaredField(String name)

  这些方法分别用于从类中解剖出构造函数、方法和成员变量(属性)。解剖出的成员分别使用Constructor、Method、Field对象表示。

利用Constructor创建对象

  • Constructor类提供了如下方法,用于创建类的对象:
public Object newInstance(Object... initargs) // initargs用于指定构造函数接收的参数

示例:
Person.java

package com.wm103.reflect;import java.util.List;/** * Created by DreamBoy on 2017/4/23. */public class Person {    public String name = "DreamBoy";    public Person() {        System.out.println("Person");    }    public Person(String name) {        System.out.println("Person name: " + name);    }    public Person(String name, int password) {        System.out.println("Person name: " + name + ", Person password: " + password);    }    private Person(List list) {        System.out.println("list");    }}

Demo2.java

package com.wm103.reflect;/** * Created by DreamBoy on 2017/4/23. */import org.junit.Test;import java.lang.reflect.Constructor;import java.util.ArrayList;import java.util.List;/** * 反射类的构造函数,创建类的对象 */public class Demo2 {    /**     * 反射构造函数:public Person()     */    @Test    public void test1() throws Exception {        // 利用反射技术创建类的对象        Class cls = Class.forName("com.wm103.reflect.Person");        Constructor c = cls.getConstructor(null);        Person p = (Person) c.newInstance(null);        System.out.println(p.name);    }    /**     * 反射构造函数:public Person(String name)     */    @Test    public void test2() throws Exception {        // 利用反射技术创建类的对象        Class cls = Class.forName("com.wm103.reflect.Person");        Constructor c = cls.getConstructor(String.class);        Person p = (Person) c.newInstance("Dream Test2");        System.out.println(p.name);    }    /**     * 反射构造函数:public Person(String name, int password)     */    @Test    public void test3() throws Exception {        // 利用反射技术创建类的对象        Class cls = Class.forName("com.wm103.reflect.Person");        Constructor c = cls.getConstructor(String.class, int.class);        Person p = (Person) c.newInstance("Dream Test3", 123456);        System.out.println(p.name);    }    /**     * 反射构造函数:private Person(List list)     */    @Test    public void test4() throws Exception {        // 利用反射技术创建类的对象        Class cls = Class.forName("com.wm103.reflect.Person");        Constructor c = cls.getDeclaredConstructor(List.class);        // 暴力反射:如果一个类的构造方法是私有的,也就是private 修饰的,是不能在外部直接使用new 来创建对象。        // 这个时候你要是使用反射会出错,暴力反射正好解决这个问题。当然不只是构造方法,其他方法,属性等也同样。        c.setAccessible(true);        Person p = (Person) c.newInstance(new ArrayList());        System.out.println(p.name);    }    /**     * 通过反射class对象直接创建对象(根据类的无参构造方法创建)     */    @Test    public void test5() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Person p = (Person) cls.newInstance();        System.out.println(p.name);    }}

利用Method执行方法

  • Method对象提供了如下方法,用于执行它所代表的方法:
public Object invoke(Object obj, Object... args)
  • jdk1.4和jdk1.5的invoke方法的区别:
    jdk1.4
public Object invoke(Object obj, Object[] args)

jdk1.5

public Object invoke(Object obj, Object.. args)

示例:

package com.wm103.reflect;/** * Created by DreamBoy on 2017/4/23. */public class Person {    public String name = "DreamBoy";    public Person() {        System.out.println("Person");    }    public void method() {        System.out.println("Person method");    }    public void method(String name, int password) {        System.out.println("Person method");        System.out.println("Person name: " + name + ", Person password: " + password);    }    public Class[] method(String name, int[] password) {        return new Class[]{String.class};    }    private void method(String name) {        System.out.println(name);    }    public static void setNum(int num) {        System.out.println(num);    }    public static void main(String[] args) {        System.out.println("This is a main method. —— Person");    }}
package com.wm103.reflect;/** * Created by DreamBoy on 2017/4/23. */import org.junit.Test;import java.lang.reflect.Method;/** * 反射类的方法 */public class Demo3 {    /**     * 反射类的方法:public void method()     */    @Test    public void test1() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Object obj = cls.newInstance();        Method method = cls.getMethod("method", null); // 反射出方法        method.invoke(obj, null); // 参数:方法调用的对象,方法传入的参数    }    /**     * 反射类的方法:public void method(String name, int password)     */    @Test    public void test2() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Object obj = cls.newInstance();        Method method = cls.getMethod("method", String.class, int.class);        method.invoke(obj, "DreamBoy", 123456);    }    /**     * 反射类的方法:public Class[] method(String name, int[] password)     */    @Test    public void test3() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Object obj = cls.newInstance();        Method method = cls.getMethod("method", String.class, int[].class);        Class[] clss = (Class[]) method.invoke(obj, "DreamBoy", new int[]{1, 2, 3});        System.out.println(clss[0]);    }    /**     * 反射类的方法:private void method(String name)     */    @Test    public void test4() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Object obj = cls.newInstance();        Method method = cls.getDeclaredMethod("method", String.class);        method.setAccessible(true);        method.invoke(obj, "DreamBoy");    }    /**     * 反射类的方法:public static void setNum(int num)     */    @Test    public void test5() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Method method = cls.getMethod("setNum", int.class);        method.invoke(null, 123456);    }    /**     * 反射类的方法:public static void main(String[] args)     * 注意:反射方法时,调用的方法接收一个数组,这时就需要特别注意了!!!     */    @Test    public void test6() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Method method = cls.getMethod("main", String[].class);        //method.invoke(null, new Object[]{new String[]{"DreamBoy"}});        method.invoke(null, (Object) new String[]{"DreamBoy"});    }}

反射字段

示例:
Person.java

package com.wm103.reflect;import java.util.List;/** * Created by DreamBoy on 2017/4/23. */public class Person {    public String name = "DreamBoy";    private int password = 1234;    private static int age = 18;    public Person() {        System.out.println("Person");    }}

Demo4.java

package com.wm103.reflect;/** * Created by DreamBoy on 2017/4/24. */import org.junit.Test;import java.lang.reflect.Field;/** * 反射字段 */public class Demo4 {    /**     * 反射字段:public String name = "DreamBoy";     */    @Test    public void test1() throws Exception {        Person p = new Person();        Class cls = Class.forName("com.wm103.reflect.Person");        Field f = cls.getField("name");        /*String name = (String) f.get(p);        System.out.println(name);*/        Object value = f.get(p); // 获取字段的值        Class type = f.getType(); // 获取反射字段的类型        System.out.println(type);        if(type.equals(String.class)) {            String name = (String) value;            System.out.println(name);        }        f.set(p, "Moon"); // 设置字段的值        System.out.println(p.name);    }    /**     * 反射字段:private int password;     */    @Test    public void test2() throws Exception {        Person p = new Person();        Class cls = Class.forName("com.wm103.reflect.Person");        Field f = cls.getDeclaredField("password");        f.setAccessible(true); // 暴力反射        Object value = f.get(p); // 获取字段的值        Class type = f.getType(); // 获取反射字段的类型        System.out.println(type);        if(type.equals(int.class)) {            int password = (int) value;            System.out.println(password);        }        f.set(p, 1234567); // 设置字段的值        System.out.println(f.get(p));    }    /**     * 反射字段:private static int age = 18;     */    @Test    public void test3() throws Exception {        Class cls = Class.forName("com.wm103.reflect.Person");        Field f = cls.getDeclaredField("age");        f.setAccessible(true); // 暴力反射        Object value = f.get(null); // 获取字段的值        Class type = f.getType(); // 获取反射字段的类型        System.out.println(type);        if(type.equals(int.class)) {            int password = (int) value;            System.out.println(password);        }        f.set(null, 23); // 设置字段的值        System.out.println(f.get(null));    }}

内省(Introspector)

  • 开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性。
  • 什么是Java对象的属性和属性的读写方法?
      我们认为具有getter或setter方法的,称为Java对象的属性。如:这里的Person类具有5个属性,即ab、age、name、password,同时还有从父类Object中继承而来的class属性(因为父类Object中包含getClass方法)。
package com.wm103.introspector;/** * Created by DreamBoy on 2017/4/24. *//** * JavaBean */public class Person {    private String name;    private String password;    private int age;    public Object getAb() {        return null;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public int getAge() {        return age;    }    public void setAge(int age) {        this.age = age;    }}
  • 内省访问JavaBean属性的两种方式:
    1. 通过PropertyDescriptor类操作Bean的属性;
    2. 通过Introspector类获取Bean对象的BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter/setter方法,然后通过反射机制来调用这些方法。
  • 示例:
package com.wm103.introspector;/** * Created by DreamBoy on 2017/4/24. */import org.junit.Test;import java.beans.BeanInfo;import java.beans.Introspector;import java.beans.PropertyDescriptor;import java.lang.reflect.Method;/** * 使用内省API操作Bean的属性 */public class Demo1 {    /**     * 得到bean的所有属性     * @throws Exception     */    @Test    public void test1() throws Exception {        // 将对象的所有属性封装到BeanInfo里面去        BeanInfo info = Introspector.getBeanInfo(Person.class, Object.class); // 加入Object.class后,将只得到bean自身的属性,不包括从Object继承而来的属性        PropertyDescriptor[] pds = info.getPropertyDescriptors(); // 获取属性描述器        for (PropertyDescriptor pd: pds) {            System.out.println(pd.getName()); // 获取类中的属性名:ab、age、name、password。此外还包含了从Object继承而来的class属性。        }    }    /**     * 操作bean的指定属性:age     * @throws Exception     */    @Test    public void test2() throws Exception {        Person p = new Person();        PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);        // 得到属性的写方法,为属性赋值        Method mSet = pd.getWriteMethod();        mSet.invoke(p, 18);        System.out.println(p.getAge());        // 获取属性的值        Method mGet = pd.getReadMethod();        System.out.println(mGet.invoke(p));    }    /**     * 获取当前操作的属性的类型     * @throws Exception     */    @Test    public void test3() throws Exception {        PropertyDescriptor pd = new PropertyDescriptor("age", Person.class);        Class type = pd.getPropertyType();        if(type.equals(int.class)) {            System.out.println("Age is int Type");        }    }}

BeanUtils框架

  使用BeanUtils操作Bean的属性,需要我们在工程中导入 beanutils jar包,这里我导入commons-beanutils-1.8.0.jarcommons-logging-1.1.1.jar包。
  示例:
Person.java

package com.wm103.beanutils;/** * Created by DreamBoy on 2017/4/24. */import java.util.Date;/** * JavaBean */public class Person {    private String name;    private String password;    private int age;    private Date birthday;    public Object getAb() {        return null;    }    public String getName() {        return name;    }    public void setName(String name) {        this.name = name;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    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;    }}

Demo1.java

package com.wm103.beanutils;/** * Created by DreamBoy on 2017/4/24. */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;import java.lang.reflect.InvocationTargetException;import java.text.ParseException;import java.text.SimpleDateFormat;import java.util.Date;import java.util.HashMap;import java.util.Map;/** * 使用beanUtils操作bean的属性(第三方) */public class Demo1 {    /**     * 操作bean属性     * @throws Exception     */    @Test    public void test1() throws Exception {        Person p = new Person();        BeanUtils.setProperty(p, "name", "HaHa");        System.out.println(p.getName());    }    /**     * 操作bean属性     * @throws Exception     */    @Test    public void test2() throws Exception {        String name = "xiaoxiao";        String password = "123";        String age = "23";        Person p = new Person();        BeanUtils.setProperty(p, "name", name);        BeanUtils.setProperty(p, "password", password);        BeanUtils.setProperty(p, "age", age); // 这里BeanUtils将字符串转为int类型后赋值,BeanUtils默认只支持对8种基本数据类型进行转换,无法对复杂类型进行转换。        System.out.println(p.getName() + ' ' + p.getPassword() + ' ' + p.getAge());    }    /**     * 注册转换器     * @throws Exception     */    @Test    public void test3() throws Exception {        String name = "xiaoxiao";        String password = "123";        String age = "23";        String birthday = "2000-01-01";        // 为了让日期赋到bean的birthday属性上,我们给beanUtils注册一个日期转换器        ConvertUtils.register(new Converter() {            @Override            public Object convert(Class type, Object value) {                if(value == null) {                    return null;                }                if(!(value instanceof String)) {                    throw new ConversionException("只支持String类型的转换!");                }                String str = (String) value;                if(str.trim().equals("")) {                    return null;                }                SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");                try {                    return df.parse(str);                } catch (ParseException e) {                    throw new RuntimeException(e); // 异常链                }            }        }, Date.class);        Person p = new Person();        BeanUtils.setProperty(p, "name", name);        BeanUtils.setProperty(p, "password", password);        BeanUtils.setProperty(p, "age", age); // 这里BeanUtils将字符串转为int类型后赋值,BeanUtils默认只支持对8种基本数据类型进行转换,无法对复杂类型进行转换。        BeanUtils.setProperty(p, "birthday", birthday); // BeanUtils中无法帮我们完成从String到Date的转换,需要我们添加转换器        System.out.println(p.getName() + ' ' + p.getPassword() + ' ' + p.getAge() + ' ' + p.getBirthday());    }    /**     * 注册转换器     * @throws Exception     */    @Test    public void test4() throws Exception {        String name = "xiaoxiao";        String password = "123";        String age = "23";        String birthday = "2000-01-01";        //String birthday = ""; // 空字符串转换出异常!        ConvertUtils.register(new DateLocaleConverter(), Date.class); // BeanUtils提供了Date转换器        Person p = new Person();        BeanUtils.setProperty(p, "name", name);        BeanUtils.setProperty(p, "password", password);        BeanUtils.setProperty(p, "age", age); // 这里BeanUtils将字符串转为int类型后赋值,BeanUtils默认只支持对8种基本数据类型进行转换,无法对复杂类型进行转换。        BeanUtils.setProperty(p, "birthday", birthday); // BeanUtils中无法帮我们完成从String到Date的转换,需要我们添加转换器        System.out.println(p.getName() + ' ' + p.getPassword() + ' ' + p.getAge() + ' ' + p.getBirthday());    }    @Test    public void test5() throws InvocationTargetException, IllegalAccessException {        Map<String, String> map = new HashMap<>();        map.put("name", "WM");        map.put("password", "12345");        map.put("age", "23");        map.put("birthday", "2000-01-01");        Person bean = new Person();        ConvertUtils.register(new DateLocaleConverter(), Date.class); // 用Map集合中的值,填充bean的属性        BeanUtils.populate(bean, map);        System.out.println(bean.getName() + ' ' + bean.getPassword() + ' ' + bean.getAge() + ' ' + bean.getBirthday());    }}

泛型(Generic)

泛型的使用

  • JDK5以前,对象保存到集合中就会失去其特性,取出时通常要程序员手工进行类型的强制转换,这样不可避免就会引发程序的一些安全性问题。例如:
ArrayList list = new ArrayList();list.add("abc");Integer num = (Integer) list.get(0); // 运行时会出错,但编码时发现不了
  • JDK5中的泛型允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
  • 泛型的注意事项:
    • 使用泛型时的几个常见问题:
      1. 使用泛型时,泛型类型须为引用类型,不能是基本数据类型;
      2. ArrayList<Object> list = new ArrayList<String>(); 是错误的。
      3. ArrayList<String> list = new ArrayList<Object>(); 是错误的。
      4. ArrayList<String> list = new ArrayList(); 是正确的。
      5. ArrayList list = new ArrayList<String>(); 是正确的,但是在添加数据时编译器木有对类型进行校验。
    • 泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛型的java程序后,生成的class文件中将不再带有泛型信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
    • 泛型的基本术语,以ArrayList<E>为例:<>念为typeof
      1. ArrayList<E>中的E称为类型参数变量;
      2. ArrayList<Integer>中的Integer称为实际类型参数;
      3. 整个称为ArrayList<E>泛型类型;
      4. 整个ArrayList<Integer>称为参数化的类型(Parameterized Type)
  • 示例:
package com.wm103.generic;import org.junit.Test;import java.util.*;/** * Created by DreamBoy on 2017/4/25. */public class Demo1 {    @Test    public void test1() {        List<String> list = new ArrayList<>();        list.add("aa");        list.add("bb");        list.add("cc");        // 传统        Iterator<String> it = list.iterator();        while (it.hasNext()) {            String val = it.next();            System.out.println(val);        }        // 增强for        for (String val: list) {            System.out.println(val);        }        list.forEach(System.out::println);    }    @Test    public void test2() {        Map<Integer, String> map = new LinkedHashMap<>();        map.put(1, "aa");        map.put(2, "bb");        map.put(3, "cc");        // 传统 keySet entrySet        Set<Map.Entry<Integer, String>> set = map.entrySet();        Iterator<Map.Entry<Integer, String>> it = set.iterator();        while (it.hasNext()) {            Map.Entry<Integer, String> entry = it.next();            int key = entry.getKey();            String val = entry.getValue();            System.out.println(key + "=" + val);        }        // 增强for        for (Map.Entry<Integer, String> entry: map.entrySet()) {            int key = entry.getKey();            String val = entry.getValue();            System.out.println(key + "=" + val);        }    }}

自定义泛型

自定义泛型方法

  • Java程序中的普通方法、构造方法和静态方法中都可以使用泛型。方法使用泛型前,必须对泛型进行声明,语法:<T>,T可以是任意字幕,但通常必须要大写。<T>通常需放在方法的返回值声明之前。例如:
public static <T> void doXx(T t);
  • 注意:
    • 只有对象类型才能作为泛型方法的实际参数;
    • 在泛型中可以同时有多个类型,例如:
public static <K, V> V getValue(K key) { return map.get(key); }
  • 示例:
    Demo2.java
package com.wm103.generic;/** * Created by DreamBoy on 2017/4/25. *//** * 自定义带泛型的方法 */public class Demo2 {    public <T> T a(T t) { // 这里的 <T> 表示声明泛型,并作用在方法上        return t;    }    public <T, E, K> void b(T t, E e, K k) { // <T, E, K> 声明多个泛型    }    public void test1() {        a("aaa");    }}

Demo3.java

package com.wm103.generic;/** * Created by DreamBoy on 2017/4/25. *//** * 自定义类上的泛型 */public class Demo3<T> { // <T> 声明泛型,并作用于整个类,对于静态成员是无效的    public T a(T t) {        return t;    }    public <E, K> void b(T t, E e, K k) {    }    public static <T> void c(T t) {    }}

Demo4.java

package com.wm103.generic;import org.junit.Test;/** * Created by DreamBoy on 2017/4/25. */public class Demo4 {    /**     * 实现指定位置上的数组元素的交换     * @param arr     * @param pos1     * @param pos2     * @param <T>     */    public <T> void swap(T arr[], int pos1, int pos2) {        T temp = arr[pos1];        arr[pos1] = arr[pos2];        arr[pos2] = temp;    }    /**     * 接收一个任意数组,并颠倒数组中的所有元素     * @param arr     * @param <T>     */    public <T> void reverse(T arr[]) {        int start = 0;        int end = arr.length - 1;        while (start <= end) {            this.swap(arr, start, end);            start++;            end--;        }    }    @Test    public void test() {        Integer[] arr = {1, 2, 4, 8};        this.reverse(arr);        for (int val: arr) {            System.out.println(val);        }    }}

自定义泛型类

  • 如果一个类多处都要用到同一个泛型,这时可以把泛型定义在类上(即类级别的泛型),语法格式如下:
public class Demo<T> {    private T field;    public void save(T obj) {}    public T getId(int id) {}}
  • 注意,静态方法不能使用类定义的泛型,而应单独定义泛型。
0 0
原创粉丝点击