目录
静态导入
- 静态导入用于简化程序对类静态属性和方法的调用。
- 语法:
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();
}
- 枚举类具有如下特性:
- 枚举类也是一种特殊形式的Java类。
- 枚举类中声明的每一个枚举值代表枚举类的一个实例对象。
- 与java中的普通类一样,在声明枚举类时,也可以声明属性、方法和构造函数,但枚举类的构造函数必须为私有的。
- 枚举类也可以实现接口或继承抽象类。
- JDK5中扩展了switch语句,它除了可以接收int, byte, char, short外,还可以接收一个枚举类型。
- 若枚举类只有一个枚举值,则可以当作单例设计模式使用。
- 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对象的方式:
- 类名.class,如Person.class;
- 对象.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属性的两种方式:
- 通过
PropertyDescriptor
类操作Bean的属性; - 通过
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中的泛型允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)。
- 泛型的注意事项:
- 使用泛型时的几个常见问题:
- 使用泛型时,泛型类型须为引用类型,不能是基本数据类型;
ArrayList<Object> list = new ArrayList<String>();
是错误的。ArrayList<String> list = new ArrayList<Object>();
是错误的。ArrayList<String> list = new ArrayList();
是正确的。ArrayList list = new ArrayList<String>();
是正确的,但是在添加数据时编译器木有对类型进行校验。
- 泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛型的java程序后,生成的class文件中将不再带有泛型信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
- 泛型的基本术语,以
ArrayList<E>
为例:<>
念为typeof
ArrayList<E>
中的E称为类型参数变量;ArrayList<Integer>
中的Integer称为实际类型参数;- 整个称为
ArrayList<E>
泛型类型; - 整个
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) {}
}
- 注意,静态方法不能使用类定义的泛型,而应单独定义泛型。