一 Eclipse的使用和程序的断点调试
错误:Bad version number in .class file-编译器的版本过高,运行环境版本过低(如果编译器的版本是低的,而运行环境是高的,不会出问题)
解决方案,1 编译环境变低 2运行环境变高
改变运行环境:工程右键,选择属性(Properties)选择java Build Path->Libraries
改变编译环境:工程右键,选择属性(Properties)选择java Compiler
断点调试
在想要停顿的地方双击当前行的最前面
然后Debug As
快捷键:F5:跳入(step into)
F6:跳过(step over),跳过当前行代码
F7:跳出(step return)
观察变量或表达式的值,点击变量,选择Watch
drop to frame 回跳,跳到当前方法的最上面
resume 跳到下一个断点(如果没有下一个断点,则运行完整个程序)
清除所有断点:Breakpoints视图
二 eclipse常用快捷键
配置快捷键
windows->Prefernces->搜索框输入k->点击Keys
内容提示:Alt+/
快速修复:Ctrl+1
导包:Ctrl+shift+O
格式化代码块:Ctrl+shift+F
向前向后:Alt+方向键
添加注释:Ctrl+shift+/
除去注释:Ctrl+shift+\
F2:查看方法说明
重置透视图:windows->Reset Perspective
更改为大写:Ctrl+Shift+X
更改为小写:Ctrl+Shift+Y
复制行Ctrl+Alt+向下键(有些不能用)
查看类的继承关系:Ctrl+T
查看源代码
1
2 ctrl +shift+T
Ctrl+Shift+L查看所有快捷键
三 junit测试框架
public class Person {
public void run(){
System.out.println("跑");
}
public String eat(){
System.out.println("吃");
return "1";
}
}
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
public class PersonTest {
Person p;
// 提取测试方法所需要的外界资源
// before after 每个测试方法都运行
// beforeClass afterClass 在类加载的时候运行,只运行一边
@Before
public void before() {
p = new Person();
}
@BeforeClass
public static void beforeClass() {
System.out.println("beforeClass");
}
@Test
public void testRun() {
p.run();
}
// 释放外界资源
@After
public void after() {
System.out.println("after");
}
@AfterClass
public static void afterClass() {
System.out.println("afterClass");
}
}
import junit.framework.Assert;
import org.junit.Test;
public class PersonTest1 {
public void testRun() {
Person p=new Person();
p.run();
}
@Test
public void testEat() {
Person p=new Person();
//断言
//判断测试是否通过
//Assert.assertEquals("2", p.eat());
Assert.assertEquals(new int []{1,1}, new int[]{1,2});
}
}
四 java5的静态导入和自动装箱拆箱
静态导入用于简化程序对类静态属性和方法的调用
语法:import static 包名.类名.静态属性|静态方法|*
例:import static java.lang.System.out
import static java.lang.Math.*
自动装箱:指开发人员可以把一个基类数据类型直接赋值给对应的包装类
自动拆箱:指开发人员可以把一个包装类对象直接赋值给对应的进本数据类型
典型应用:
List list =new ArrayList();
list.add(1);
int j=(Interger)list.get(0);
五 增强for循环
引入增强for循环的原因,在JDK5以前的版本中,遍历数组或集合中的元素,需先获得数组的长度或集合的迭代器,比较麻烦
JDK5中定义了一种新的语法——增强for循环,以简化此类操作。增强for循环只能用在数组,或实现Iterable接口的集合类上。
语法格式:
for(变量类型 变量 :需迭代的数组或集合){
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import org.junit.Test;
/*
* 增强for
*/
public class StrongFor {
@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.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");
//传统方式1
Set set =map.keySet();
Iterator it=set.iterator();
while (it.hasNext()){
String key= (String) it.next();
String value=(String) map.get(key);
System.out.println(key+"="+value);
}
}
@Test
public void Test4() {
Map map=new LinkedHashMap();//LinkedHashMap()正序。常用语购物车
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");
//传统方式2
Set set =map.entrySet();
Iterator it=set.iterator();
while (it.hasNext()){
Map.Entry entry=(Entry)it.next();
String key=(String) entry.getKey();
String value=(String) entry.getValue();
System.out.println(key+"="+value);
}
}
@Test
public void Test5() {
Map map=new LinkedHashMap();//LinkedHashMap()正序。常用语购物车
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");
//增强for取Map的第一种方法
for(Object obj:map.keySet()){//把map集合转换成set集合
String key=(String)obj;
String value =(String) map.get(key);
System.out.println(key+"="+value);
}
}
@Test
public void Test6() {
Map map=new LinkedHashMap();//LinkedHashMap()正序。常用语购物车
map.put("1", "aaa");
map.put("2", "bbb");
map.put("3", "ccc");
//增强for取Map的第二种方法
for(Object obj :map.entrySet()){
Map.Entry entry=(Entry)obj;
String key=(String) entry.getKey();
String value=(String) entry.getValue();
System.out.println(key+"="+value);
}
Set set =map.entrySet();
}
//使用增强for需要注意的几个问题:增强for只适合取数据,要修改数组或集合中的数据,使用传统方式
@Test
public void Test7() {
int arr[]={1,2,3};
for(int i:arr){
i=10;
}
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
List list =new ArrayList();
list.add("1");
for(Object obj:list){
obj="10";
}
System.out.println(list.get(0));
}
}
六 可变参数
测试JDK中具有可变参数的类Array.asList().分别传多个参,传数组,传数组又传参的情况
注意:传入基本数类型数组的问题
从JDK5开始,java允许为方法定义长度可变的参数,
语法:public void foo(int...args){
}
注意事项:
调用可变参数的方法时,编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以在方法体中以数组的形式访问可变参数
可变参数只能处于参数列表的最后,所以一个方法最多只能有一个长度可变的参数。
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
public class ChangeableArgs {
@Test
public void testSum(){
int arr[]={1,2,3,4,5};
sum(arr);
sum(1,2,3,4,5,6);
}
public void sum(int...num){
//可变参数看成数组
int sum=0;
for(int i:num){
sum+=i;
}
System.out.println(sum);
}
@Test
public void testAa(){
aa(1,2,3,4,5);
}
public void aa(int ...nums){
}
@Test
public void bb(){
List list=Arrays.asList("a","b","c");
System.out.println(list);
String arr[]={"1","2","3","4"};
list =Arrays.asList(arr);
System.out.println(list);
//需要的是对象,所以把数组当成了对象,输出的结果不是预期的
int nums[]={1,2,3}; //把int改成Integer就可以
list=Arrays.asList(nums);
System.out.println(list);
}
}
七 什么是枚举类型和定义枚举
为什么需要枚举?
一些方法在运行时,它需要的数据不能是任意的,而必须是一定范围内的值,此类问题在JDK5以前采用自定义带有枚举功能的类解决,java5以后可以直接使用枚举予以解决
JDK5新增的enum关键字用于定义一个枚举类
八 定义枚举的构造函数,方法和字段
package cn.pack;
import org.junit.Test;
public class EnumerationTest {
@Test
public void test(){
print(Grade.B);
}
public void print(Grade g){ //输出成绩A,B,C,D,E
String value =g.getValue();
System.out.println(value);//89-80
}
}
/*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{ //class A 100-90 B 89-80 C 79-70 D 69-60
A("100-90"),B("89-80"),C("79-70"),D("69-60"),E("59-0");//Object单独写A,B,C,D,E;会报错,因为没有了默认的构造函数
private String value;//封装每个对象对应的分数
//声明了一个有参的构造函数,
private Grade(String value){
this.value=value;
}
public String getValue(){
return this.value;
}
}
九 定义抽象方法的枚举
import org.junit.Test;
public class AbstractEnumeration {
@Test
public void test() {
print(GradeToo.B);
}
public void print(GradeToo g) { // 输出成绩A,B,C,D,E
String value = g.getValue();
System.out.println(value);// 89-80
}
}
/*
* 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 GradeToo { // class A 100-90 B 89-80 C 79-70 D 69-60
A("100-90") {
public String localeVlaue() {
return "优";
}
},
B("89-80") {
public String localeVlaue() {
return "良";
}
},
C("79-70") {
public String localeVlaue() {
return "一般";
}
},
D("69-60") {
public String localeVlaue() {
return "差";
}
},
E("59-0") {
public String localeVlaue() {
return "不及格";
}
};// Object单独写A,B,C,D,E;会报错,因为没有了默认的构造函数
private String value;// 封装每个对象对应的分数
// 声明了一个有参的构造函数,
private GradeToo(String value) {
this.value = value;
}
public String getValue() {
return this.value;
}
public abstract String localeVlaue();
}
十 枚举的常用方法和其它细节
枚举类具有如下特性:
枚举类也是一种特殊形式的java类
枚举类中声明的每一个枚举值代表枚举类的一个实例对象
与java中的普通类一样,在声明枚举类时,也可以声明属性,方法和构造函数,但枚举类的构造函数必须为私有的(如果为公有的,别人就可以创建实例了)
枚举类也可以实现接口,或继承抽象类
JDK5中扩展了switch语句,他除了可以接收int ,byte,char,short外,它还可以接受一个枚举类型
若枚举类型只有一个枚举值,则可以当作单态设计模式(保存类对象在内存中始终只有一个)使用
java中声明的枚举类,均是java.lang.Enum类的孩子,他继承了Enum类的所有方法,常用方法:
name()
ordinal()
valueof(class enumClass,String name)
values()此方法虽然在JDK文档中查不到,但每个枚举类都具有该方法,它用于遍历枚举的所有枚举值
实际开发中,用户提交的大部分都是String类型,如果用户提交的数据正确,就能转换成枚举
//测试枚举类的常用方法
@Test
public void test1(){
System.out.println(Grade.C.name());
System.out.println(Grade.C.ordinal());
String str="B";
Grade g=Grade.valueOf(str);
System.out.println(g);
Grade gs[]=Grade.values();
for(Grade g1:gs){
System.out.println(g1);
}
}
十一 反射技术概述
(做框架必须会的技术)
反射就是加载类,并解剖出类的各个组成部分
编程时什么情况下才需要加载类,并解剖出类的各个组成部分呢?
加载类:
java中有一个Class类用于代表某一个类的字节码。
Class类既然代表某个类的字节码,它当然就要提供加载某个类字节码的方法:forName()。forName方法用于加载某个类的字节码到内存中,并使用class对象进行封装
另外两种得到class对象的方式:类名.class;对象.getClass()
Class对象提供了如下常用的方法,这些方法分别用于从类中解剖出构造函数,方法和成员变量(属性)。解剖出的成员分别使用Constructor,Method,Field对象表示
十二 反射类的构造函数
利用Constructor创建对象
Constructor类提供了如下方法,用于创建类的对象:
public Object newInstance(Object...initargs)
initargs 用于指定构造函数接收的参数
package cn.reflec;
import java.util.List;
/*
* 反射,加载类,获得类的字节码
*/
public class Person {
/*public static void main(String [] args){
//1
Class clazz=Class.forName("cn/reflec/Person");//加载Person类到内存,返回class对象,保存类的字节码
//2
Class clazz1=new Person().getClass();
//3
Class clazz2=Person.class;
}*/
public String name="aaaa";
public Person(){
System.out.println("person");
}
public Person(String name){
System.out.println("Person XXXX");
}
public Person(String name,int password){
System.out.println(name+" "+password);
}
private Person (List list){
System.out.println("list");
}
}
package cn.reflec; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; import org.junit.Test; //解剖(反射)类的构造函数,创建类的对象 public class ReflectConstructor { // 反射构造函数:public Person() @Test public void test1() throws Exception { Class clazz = Class.forName("cn.reflec.Person"); Constructor c = clazz.getConstructor(null); Person p = (Person) c.newInstance(null);// 创建实例 System.out.println(p.name); } // 反射构造函数public Person(String name) @Test public void test2() throws Exception { Class clazz = Class.forName("cn.reflec.Person"); Constructor c = clazz.getConstructor(String.class); Person p = (Person) c.newInstance("XXXX");// 创建实例 System.out.println(p.name); } // 反射构造函数 public Person(String name,int password) @Test public void test3() throws Exception { Class clazz = Class.forName("cn.reflec.Person"); Constructor c = clazz.getConstructor(String.class, int.class); Person p = (Person) c.newInstance("XXXX", 13);// 创建实例 System.out.println(p.name); } // 反射构造函数private Person (List list) @Test public void test4() throws Exception { Class clazz = Class.forName("cn.reflec.Person"); Constructor c = clazz.getDeclaredConstructor(List.class); c.setAccessible(true);// 暴力反射 Person p = (Person) c.newInstance(new ArrayList());// 创建实例 System.out.println(p.name); }// 私有的东西不能被外界访问,但是反射可以做到 @Test //另一种创建对象方法,要求类中必须有一个无参的构造函数 //以下代码=test1() public void test5() throws Exception { Class clazz = Class.forName("cn.reflec.Person"); Person p=(Person)clazz.newInstance(); System.out.println(p.name); } }
十三 反射类的方法
利用Method执行方法
Method对象提供了如下方法,用于执行它所代表的方法:public Object invoke(Object obj,Object...args)
jdk1.4和jdk1.5的invoke方法的区别:
jdk1.5:public Object invoke(Object obj,Object...args)
jdk1.4:public Object invoke(Object obj,Object[]args)
Person类
public void aa1(){ System.out.println("aa1"); } public void aa1(String name,int password){ System.out.println(name+" "+password); } public Class[] aa1(String name,int[] paaword){ return new Class[]{String.class}; } private void aa1(InputStream in){ System.out.println(in); } public static void aa1(int num){ System.out.println(num); }
package cn.reflec; import java.io.FileInputStream; import java.io.InputStream; import java.lang.reflect.Method; import org.junit.Test; //反射类的方法 public class ReflectMethod { // 反射类的方法public void aa1() @Test public void test1() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Method method = clazz.getMethod("aa1", null); method.invoke(p, null);// 指定谁的方法跑起来,指定一个对象 } // 反射类的方法public void aa1(String name,int password){v @Test public void test2() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Method method = clazz.getMethod("aa1", String.class, int.class); method.invoke(p, "ZXX", 38); } // 反射类的方法public Class[] aa1(String name,int[] paaword) @Test public void test3() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Method method = clazz.getMethod("aa1", String.class, int[].class); Class cs[] = (Class[]) method.invoke(p, "shuzu", new int[] { 1, 2, 3 }); System.out.println(cs[0]); } // 反射类的方法private void aa1(InputStream in) @Test public void test4() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Method method = clazz.getDeclaredMethod("aa1", InputStream.class); method.setAccessible(true); method.invoke(p, new FileInputStream("c:\\1.txt")); } // 反射类的方法private static void aa1(int num) @Test public void test5() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Method method = clazz.getMethod("aa1", int.class); method.invoke(null, 13);// 静态的方法在调用的时候不用对象 } }
十四 反射类的main方法
public static void main(String []args){ System.out.println("main!!!"); }
package cn.reflec; import java.lang.reflect.Method; import org.junit.Test; public class reflectMain { @Test //利用反射调用一个参数有数组的方法,为了保存向前(1.5->1.4)兼容 public void test1() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Method method = clazz.getMethod("main", String[].class); //method.invoke(null, new String[]{"aa","bb"});//main{String s1,String s2} //method.invoke(null, new Object[]{new String[]{"aa","bb"}});//第一种 method.invoke(null, (Object)new String[]{"aa","bb"}); } }
十五 反射类的字段
public String name="aaaa"; private int password=123; private static int age=23;
package cn.reflec; import java.io.File; import java.lang.reflect.Field; import org.junit.Test; //反射字段 public class ReflectValue { // 反射public String name="aaaa"; @Test public void test1() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Field f = clazz.getField("name"); String name = (String) f.get(p); System.out.println(name); Object value = f.get(p);// 获取字段的值 f.set(p, "XXXXXXXXXXXXX");// 设置字段的值 // Class type =f.getType();//在不知道字段的类型的情况下获取字段的类型 } // 反射private int password; @Test public void test2() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Field f = clazz.getDeclaredField("password"); f.setAccessible(true); System.out.println(f.get(p)); } // 反射private static int age=23; @Test public void test3() throws Exception { Person p = new Person(); Class clazz = Class.forName("cn.reflec.Person"); Field f = clazz.getDeclaredField("age"); f.setAccessible(true); System.out.println(f.get(p));//是静态方法,但是也需要传入一个对象进去 } }
十六 内省操作javabean的属性
内省(Introspector)
为什么要学内省?
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都是用反射技术完成此类操作过于麻烦,所以sun公司开发了一套API,专门用于操作java对象的属性
什么是java对象的属性和属性的读写方法?
内省访问javaBean属性的两种方式:
通过PropertyDescriptor类操作Bean的属性
通过Instrospecor类获得Bean对象的BeanInfo,然后通过BeanInfo来获取属性的描述器(PropertyDescriptor),通过这个属性描述器就可以获取某个属性对应的getter,setter方法,然后通过反射机制来调用这些方法。
package cn.introspector; public class PersonJavaBean {//操作 javabean的属性封装用户的数据 //默认有一个继承自Object的class属性 // 当字段对外提供了get或set方法时,叫属性 private String name;// 字段 private String password; private int age; 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 String getAe(){//也是一个属性 return null; } }
package cn.introspector; import java.beans.BeanInfo; import java.beans.Introspector; import java.beans.PropertyDescriptor; import java.lang.reflect.Method; import org.junit.Test; //使用内省api操作bean的属性 public class ApiOperateBean { // 得到bean的所有属性 @Test public void test1() throws Exception { BeanInfo info = Introspector.getBeanInfo(PersonJavaBean.class); // BeanInfo // info=Introspector.getBeanInfo(PersonJavaBean.class,Object.class);//得到bean自己的属性,去掉继承的属性 PropertyDescriptor[] pds = info.getPropertyDescriptors(); for (PropertyDescriptor pd : pds) { System.out.println(pd.getName()); } } // 操作bean指定的属性age @Test public void test2() throws Exception { PersonJavaBean p = new PersonJavaBean(); PropertyDescriptor pd = new PropertyDescriptor("age", PersonJavaBean.class); // 得到属性的写方法,为属性赋值 Method method = pd.getWriteMethod(); method.invoke(p, 28); System.out.println(p.getAge()); // 获取属性的值 method = pd.getReadMethod(); System.out.println(method.invoke(p, null)); } // 获取当前操作的属性的类型 @Test public void test3() throws Exception { PersonJavaBean p = new PersonJavaBean(); PropertyDescriptor pd = new PropertyDescriptor("age", PersonJavaBean.class); System.out.println(pd.getPropertyType()); } }
十七 使用beanUtils操纵javabean
package cn.beanutils; import java.util.Date; import javax.xml.crypto.Data; public class PersonJavaBean {//操作 javabean的属性封装用户的数据 //默认有一个继承自Object的class属性 // 当字段对外提供了get或set方法时,叫属性 private String name;// 字段 private String password; private int age; private Date birthday; public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } 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 String getAe(){//也是一个属性 return null; } }
package cn.beanutils; 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; import javax.xml.crypto.Data; 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; //使用beanUtils(第三方)操纵bean的属性 //第一步,把beanUtils的开发包集成到程序里来 //本例使用commons-beanutils-1.7.0.jar,commons-logging-1.1.1.jar public class BeanUtilsTest { @Test public void test1() throws IllegalAccessException, InvocationTargetException{ PersonJavaBean p=new PersonJavaBean(); BeanUtils.setProperty(p, "name", "XCC"); System.out.println(p.getName()); } //这个人的数据由用户提交,由于在表单里提交,在服务器接收全是String @Test public void test2() throws IllegalAccessException, InvocationTargetException{ String name="name"; String password="123"; String age="34"; String birthday="1995-10-20"; //拿到数据要将其放入对象 PersonJavaBean p=new PersonJavaBean(); BeanUtils.setProperty(p, "name", name); BeanUtils.setProperty(p, "password", password); BeanUtils.setProperty(p, "age", age);//自动转换,只支持8种基本数据类型 //BeanUtils.setProperty(p, "birthday", birthday);//默认不能支持,需要给beanutils注册转换器 System.out.println(p.getAge()+p.getName()+p.getPassword()); } //为了让日期赋到beanutils属性上,我们给beanutils注册一个日期转换器 @Test public void test3() throws IllegalAccessException, InvocationTargetException{ String name="name"; String password="123"; String age="34"; String birthday="1995-10-20"; ConvertUtils.register(new Converter(){//需导入源码 public Object convert(Class type,Object value){ //使用数据的时候,使用前一定要先检查 if(value==null){ return null; } if(!(value instanceof String)){ //System.out.println("数据类型不对,不转换");//需要告诉上一层程序 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); PersonJavaBean p=new PersonJavaBean(); BeanUtils.setProperty(p, "name", name); BeanUtils.setProperty(p, "password", password); BeanUtils.setProperty(p, "age", age);// BeanUtils.setProperty(p, "birthday", birthday); Date date =p.getBirthday(); System.out.println(p.getAge()+p.getName()+p.getPassword()+p.getBirthday()); } //Converter接口中已经写好了许多转换器 @Test public void test4() throws IllegalAccessException, InvocationTargetException{ String name="name"; String password="123"; String age="34"; String birthday=""; ConvertUtils.register(new DateLocaleConverter(),Date.class);//有bug,如果传入一个空的,如上面的birthday,没有检测这种情况 PersonJavaBean p=new PersonJavaBean(); BeanUtils.setProperty(p, "name", name); BeanUtils.setProperty(p, "password", password); BeanUtils.setProperty(p, "age", age);// BeanUtils.setProperty(p, "birthday", birthday); Date date =p.getBirthday(); System.out.println(p.getAge()+p.getName()+p.getPassword()+p.getBirthday()); } @Test public void test5() throws IllegalAccessException, InvocationTargetException{ //用Map封装 Map map=new HashMap(); map.put("name", "aaa"); map.put("password", "123"); map.put("age", "23"); map.put("birthday", "1995-10-20"); //需要将Map封装到bean上 ConvertUtils.register(new DateLocaleConverter(),Date.class);//有bug,如果传入一个空的,如上面的birthday,没有检测这种情况 PersonJavaBean bean=new PersonJavaBean(); BeanUtils.populate(bean, map);//用Map集合中的值填充bean的属性 System.out.println(bean.getAge()+bean.getName()+bean.getPassword()+bean.getBirthday()); } }
十八 泛型
泛型(Generic)的作用,在JDK5以前,对象保存到集合中就会失去其特性(任何类型传入,都会变成Object),取出时通常要程序员手工进行类型的强制转换,这样不可避免就会引起程序的一些安全性问题,例如:
ArrayList list =new ArrayList(); list.add("abc"); Integer num=(Integer)list.get[0];//运行时会出错,但编码时发现不了
JDK5中的泛型允许程序员在编写集合代码时,就限制集合的处理类型,从而把原来程序运行时可能发生问题,转变为编译时的问题,以此提高程序的可读性和稳定性(尤其在大型程序中更为突出)示例:
掌握泛型的基本应用package cn.generic; import java.util.ArrayList; import java.util.List; public class GenericTest { public static void main(String[]args){ //声明了一个变量,变量指向某一个集合处理类型为String List<String> list=new ArrayList<String>(); list.add("aaaaa"); String s=list.get(0); } }
掌握泛型集合的存取:
注意:泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛型的java程序后,生成的class文件中将不带有泛型信息。以此使程序运行效率不受到影响,这个过程称之为“擦除”。package cn.generic; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.junit.Test; public class Test2 { @Test // 带泛型的集合的存取 public void test1() { List<String> list = new ArrayList<String>(); list.add("aa"); list.add("bb"); list.add("cc"); // 传统 Iterator<String> it = list.iterator(); while (it.hasNext()) { String value = it.next(); System.out.println(value); } // 增强for for (String s : list) { System.out.println(s); } } @Test public void test2() { Map<Integer, String> map = new HashMap<Integer, String>();// Map变量指向的具体的类型必须是对象类型 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 value = entry.getValue(); System.out.println(key + "=" + value); } // 增强for不能对Map迭代,需转成Set for (Map.Entry<Integer, String> entry : map.entrySet()) { int key = entry.getKey(); String value = entry.getValue(); System.out.println(key + "=" + value); } } }
package cn.generic; import java.util.ArrayList; public class Test3 { ArrayList<String> list=new ArrayList<String>(); }
执行后的class文件内容是一样的package cn.generic; import java.util.ArrayList; public class Test4 { ArrayList<String> list=new ArrayList(); }
用泛型时,如果两边都使用泛型,两边必须都一样
但是ArrayList<String> list=new ArrayList();可以,为了兼容性
ArrayList list=new ArrayList<String>();//也是可以的,否则,现在的程序员调用不了原来的方法
public void bb(){ aa(new ArrayList());//如果上述ArrayList<String> list=new ArrayList();不可以,就无法调用 } public void aa(ArrayList<String>list){ }
十九 自定义泛型方法和泛型类
java程序中的普通方法,构造方法和静态方法都可以使用泛型,方法是用泛型前,必须对泛型进行声明,语法:<T>,T可以是任意字母,但通常必须大写。<T>通常放在方法的返回值声明之前:
public static <T>void doxx(T t);
注意:
只有对象类型才能作为泛型方法的参数
在泛型中可以同时有多个类型
如:public static <K,V> V getValue(K key){return map.get(key);}
package cn.generic; //自定义带泛型的方法 public class Test5 { public void test1(){ a("aaa"); } public <T> void a(T t){ //以前使用Object,就需要进行强转,泛型不需要 //传的什么类型,返回的就是什么类型 } public <T,E> void b(T t,E e){ //使用前需要先声明 } }
两个例子package cn.generic; public class Test6<T,E>{//类上面的泛型作用到整个类上,只作用在非静态成员上 //类里面的许多方法都使用同一个泛型 public T a(T t){//在类上声明泛型 return null; } public <K>void b(T t,E e,K k){ } public static <T> void c(T t){//需要自己定义 } }
package cn.generic; public class Test7 { // 编写一个泛型方法,实现指定位置上的数组元素的交换 public <T> void swap(T arr[], int post1, int post2) {// 将post1和post2交换 T temp = arr[post1]; arr[post1] = arr[post2]; arr[post2] = temp; } // 编写一个泛型方法,接收一个任意数组,并颠倒数组中的所有元素 public <T> void reverse(T arr[]) { int start = 0; int end = arr.length - 1; while (true) { if (start >= end) { break; } T temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; start++; end--; } } }