0
点赞
收藏
分享

微信扫一扫

JDK5中的重要特性


目录

  • ​​目录​​
  • ​​静态导入​​
  • ​​自动装箱拆箱​​
  • ​​增强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()​​​(用于遍历枚举的所有枚举值)。其中​​valueOf​​​和​​values​​方法均为静态方法。

/**
* 测试枚举的常用方法
*/
@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.jar​​​和​​commons-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 条评论