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();}
- 枚举类具有如下特性:
- 枚举类也是一种特殊形式的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) {}}
- 注意,静态方法不能使用类定义的泛型,而应单独定义泛型。
0 0
- JDK5中的重要特性
- jdk5.0中的新特性--可变参数
- jdk5特性
- Java中的(JDK5新特性)枚举10
- JDK5特性简介
- jdk5.0新特性
- jdk5.0新特性
- JDK5.0新特性
- JDK5.0新特性:
- jdk5.0新特性
- jDK5 的新特性
- jdk5新特性 实践
- JDK5.0 新特性
- jdk5.0新特性
- jdk5.0新特性
- JDK5的新特性
- JDK5.0特性
- JDK5.0新特性
- 二叉查找树(二叉搜索树)
- Servlet工作原理
- typescript
- ZOJ 3965 构造
- hdu 4799 进制转化(水)
- JDK5中的重要特性
- Python os.stat() 方法
- Swift字符串基本操作(三)
- 标准IO和文件IO
- HTTP权威指南读书笔记三:HTTP报文
- Python中垃圾回收机制的理解
- Machine learning
- my preaentation
- SVN恢复某个文件到特点版本