JDK5中的重要特性

目录

静态导入

  • 静态导入用于简化程序对类静态属性和方法的调用。
  • 语法:
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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值