Java Web学习指南【2】
2016-09-17 18:49
141 查看
[b]3 增强for循环[/b]
增强for循环是for的一种新用法!用来循环遍历数组和集合。
3.1 增强for的语法
for(元素类型
e : 数组或集合对象) {
}
例如:
int[] arr = {1,2,3};
for(int i : arr) {
System.out.println(i);
}
增强for的冒号左边是定义变量,右边必须是数组或集合类型。例如上例中循环遍历的主浊arr这个int数组,增强for内部会依次把arr中的元素赋给变量i。
3.2 增强for的优缺点
1) 只能从头到尾的遍历数组或集合,而不能只遍历部分;
2)在遍历List或数组时,不能获取当前元素下标;
3)增强for使用便简单,这是它唯一的优点了;
4)增强for比使用迭代器方便一点!
3.3 增强for原理
任何实现了Iterable接口的类,都有返回Iterator的方法。
其实增强for底层是迭代器,任何实现了Iterable接口的类都可以使用增强for来遍历!
其实增强for内部是使用迭代器完成的!也就是说,任何实现了Iterable接口的对象都可以被增强for循环遍历!这也是为什么增强for可以循环遍历集合的原因(Collection是Iterable的子接口)。
但要注意,Map并没有实现Iterable接口,所以你不能直接使用增强for来遍历它!
具有一个或多个类型变量的类称之为泛型类!
[b]1 泛型概述[/b]
泛型是JDK5.0新特性,它主要应用在集合类上。有了泛型之后,集合类与数组就越来越像了。例如:Object[] objs = new Object[10],可以用来存储任何类型的对象。String[]
strs = new String[10]只能用来存储String类型的对象。
ArrayList list = new ArrayList(),可以用来存储任何类型的对象。ArrayList<String> list = new ArrayList<String>()只有用来存储String类型的对象。
1.1 理解泛型类
泛型类具有一到多个泛型变量,在创建泛型类对象时,需要为泛型变量指定值。泛型变量只能赋值为引用类型,而不能是基本类型。例如ArrayList类中有一个泛型变量E,在创建ArrayList类的对象时需要为E这个泛型变量指定值。
list<String> list = new ArrayList<String>();,
其中String就是给List的泛型变量E赋值了。查阅ArrayList的API你会知道,泛型变量E出现在很多方法中:
boolean add(E e)
E get(int index)
因为我们在创建list对象时给泛型类型赋值为String,所以对于list对象而言,所有API中的E都会被String替换。
boolean add(String e)
String get(int index)
也就是说,在使用list.add()时,只能传递String类型的参数,而list.get()方法返回的一定是String类型。
list.add(“hello”);
String s = list.get(0);
1.2 使用泛型对象
创建泛型对象时,引用和new两端的泛型类型需要一致,例如上面的引用是List<String>,而new一端是new
ArrayList<String>,两端都是String类型!如果不一致就会出错:
List<Object> list = new ArrayList<String>();//编译失败!
Collection的addAll()方法中使用了通配符(这个概念在下一个基础加强中讲解),所以使用起来比较方便:
[b]2 泛型的好处[/b]
l 将运行期遇到的问题转移到了编译期;
l 泛型不可能去除所有类型转换,但可以减少了类型转换操作;
l 在循环遍历集合类时,方便了很多;
l 一定程度上提高了安全性。
[b]3 自定义泛型类的语法[/b]
3.1 自定义泛型类的语法
public class 类型<一到多个泛型变量的声明> {…}
例如:
public class A<T> {...}
A类中有一个泛型变量的声明(或称之为定义)。这就相当于创建了一个变量一样,然后就可以在类内使用它了。
3.2 泛型类内使用泛型变量
声明的泛型变量可以在类内使用,例如创建实例变量时使用泛型变量指定类型,可以在实例方法中指定参数类型或返回值类型,但不能在static变量或static方法中使用泛型变量。
public class A<T> {
private T bean;
public T getBean() {
return bean;
}
public void setBean(T bean) {
this.bean = bean;
}
}
[b]4 继承(或实现)泛型类(或接口)[/b]
在Java API中有很多类和接口是泛型的,如果我们需要继承或实现它们时,需要为父类或接口中的泛型变量指定值,例如Comparable就是一个泛型接口。
Comparable
该接口中有一个泛型变量T,在实现这个接口时需要为其指定值。一定为其指定值后,所有的T将使用指定的值来替换。
MyComparable
在继承(或实现)泛型类(或接口)时还有一种选择,如果当前类是泛型类,也可以把自己的泛型变量赋给父类(或接口)。
MyComparable2
[b]5 泛型方法定义[/b]
不只可以创建泛型类,还可以创建泛型方法。可能你会有个误区,下面的方法不是泛型方法:
上面fun()方法是泛型类中的方法,它不是泛型方法。
泛型方法是可以自己创建泛型变量,泛型方法中创建的泛型变量只能在本方法内使用。泛型方法可以是实例方法,也可以是静态方法。
public <T> T get(T[] ts, int index) {
return ts[index];
}
我们必须要区别开什么是创建泛型变量,什么是使用泛型变量。其中<T>是创建泛型变量,它必须在返回值前面给出。
泛型方法中的泛型变量只有两个可以使用的点:返回值和参数,而且所有有意义的泛型方法中都会在返回值和参数两个位置上使用泛型变量,但语法上没有强制的要求。
调用泛型方法,通常无需为泛型变量直接赋值,而是通过传递的参数类型间接为泛型变量赋值,例如:
String[] strs = {“hello”, “world”};
String s = get(strs, 0);
因为给T[] ts参数赋值为strs,而strs的变量为String[],所以等同与给get方法的泛型变量赋值为String类型。所以返回值类型T为String类型。
编译器会在适当的位置上给你添加强转!
[b]1 什么是枚举类型[/b]
我们学习过单例模式,即一个类只有一个实例。而枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如word文档的对齐方式有几种:左对齐、居中对齐、右对齐。开车的方向有几种:前、后、左、右!
我们称呼枚举类中实例为枚举项!一般一个枚举类的枚举项的个数不应该太多,如果一个枚举类有30个枚举项就太多了!
[b]2 定义枚举类型[/b]
定义枚举类型需要使用enum关键字,例如:
注意,定义枚举类的关键字是enum,而不是Enum,所有关键字都是小写的!
其中FRONT、BEHIND、LEFT、RIGHT都是枚举项,它们都是本类的实例,本类一共就只有四个实例对象。
在定义枚举项时,多个枚举项之间使用逗号分隔,最后一个枚举项后需要给出分号!但如果枚举类中只有枚举项(没有构造器、方法、实例变量),那么可以省略分号!建议不要省略分号!
不能使用new来创建枚举类的对象,因为枚举类中的实例就是类中的枚举项,所以在类外只能使用类名.枚举项。
[b]3 枚举与switch[/b]
枚举类型可以在switch中使用
注意,在switch中,不能使用枚举类名称,例如:“case Direction.FRONT:”这是错误的,因为编译器会根据switch中d的类型来判定每个枚举类型,在case中必须直接给出与d相同类型的枚举选项,而不能再有类型。
[b]4 所有枚举类都是Enum的子类[/b]
所有枚举类都默认是Enum类的子类,无需我们使用extends来继承。这说明Enum中的方法所有枚举类都拥有。
l int compareTo(E e):比较两个枚举常量谁大谁小,其实比较的就是枚举常量在枚举类中声明的顺序,例如FRONT的下标为0,BEHIND下标为1,那么FRONT小于BEHIND;
l boolean equals(Object o):比较两个枚举常量是否相等;
l int hashCode():返回枚举常量的hashCode;
l String name():返回枚举常量的名字;
l int ordinal():返回枚举常量在枚举类中声明的序号,第一个枚举常量序号为0;
l String toString():把枚举常量转换成字符串;
l static T valueOf(Class enumType, String name):把字符串转换成枚举常量。
[b]5 枚举类的构造器[/b]
枚举类也可以有构造器,构造器默认都是private修饰,而且只能是private。因为枚举类的实例不能让外界来创建!
其实创建枚举项就等同于调用本类的无参构造器,所以FRONT、BEHIND、LEFT、RIGHT四个枚举项等同于调用了四次无参构造器,所以你会看到四个hello输出。
[b]6 枚举类可以有成员[/b]
其实枚举类和正常的类一样,可以有实例变量,实例方法,静态方法等等,只不过它的实例个数是有限的,不能再创建实例而已。
因为Direction类只有唯一的构造器,并且是有参的构造器,所以在创建枚举项时,必须为构造器赋值:FRONT(“front”),其中”front”就是传递给构造器的参数。你不要鄙视这种语法,你应该做的是接受这种语法!
Direction类中还有一个实例域:String name,我们在构造器中为其赋值,而且本类还提供了getName()这个实例方法,它会返回name的值。
[b]7 枚举类中还可以有抽象方法(了解)[/b]
还可以在枚举类中给出抽象方法,然后在创建每个枚举项时使用“特殊”的语法来重复抽象方法。所谓“特殊”语法就是匿名内部类!也就是说每个枚举项都是一个匿名类的子类对象!
通常fun()方法应该定义为抽象的方法,因为每个枚举常量都会去重写它。
你无法把Direction声明为抽象类,但需要声明fun()方法为抽象方法。
[b]8 每个枚举类都有两个特殊方法[/b]
每个枚举类都有两个不用声明就可以调用的static方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方,下面是Direction类的特殊方法。
l static Direction[] values():返回本类所有枚举常量;
l static Direction valueOf(String name):通过枚举常量的名字返回Direction常量,注意,这个方法与Enum类中的valueOf()方法的参数个数不同。
增强for循环是for的一种新用法!用来循环遍历数组和集合。
3.1 增强for的语法
for(元素类型
e : 数组或集合对象) {
}
例如:
int[] arr = {1,2,3};
for(int i : arr) {
System.out.println(i);
}
增强for的冒号左边是定义变量,右边必须是数组或集合类型。例如上例中循环遍历的主浊arr这个int数组,增强for内部会依次把arr中的元素赋给变量i。
3.2 增强for的优缺点
1) 只能从头到尾的遍历数组或集合,而不能只遍历部分;
2)在遍历List或数组时,不能获取当前元素下标;
3)增强for使用便简单,这是它唯一的优点了;
4)增强for比使用迭代器方便一点!
3.3 增强for原理
任何实现了Iterable接口的类,都有返回Iterator的方法。
其实增强for底层是迭代器,任何实现了Iterable接口的类都可以使用增强for来遍历!
其实增强for内部是使用迭代器完成的!也就是说,任何实现了Iterable接口的对象都可以被增强for循环遍历!这也是为什么增强for可以循环遍历集合的原因(Collection是Iterable的子接口)。
但要注意,Map并没有实现Iterable接口,所以你不能直接使用增强for来遍历它!
Map<String, String> map = new HashMap<String,String>(); map.put("1", "one"); map.put("2", "two"); map.put("3", "three"); for(String key : map.keySet()) { String value = map.get(key); System.out.println(key + "=" + value); } |
泛型
具有一个或多个类型变量的类称之为泛型类!
[b]1 泛型概述[/b]
泛型是JDK5.0新特性,它主要应用在集合类上。有了泛型之后,集合类与数组就越来越像了。例如:Object[] objs = new Object[10],可以用来存储任何类型的对象。String[]
strs = new String[10]只能用来存储String类型的对象。
ArrayList list = new ArrayList(),可以用来存储任何类型的对象。ArrayList<String> list = new ArrayList<String>()只有用来存储String类型的对象。
1.1 理解泛型类
泛型类具有一到多个泛型变量,在创建泛型类对象时,需要为泛型变量指定值。泛型变量只能赋值为引用类型,而不能是基本类型。例如ArrayList类中有一个泛型变量E,在创建ArrayList类的对象时需要为E这个泛型变量指定值。
list<String> list = new ArrayList<String>();,
其中String就是给List的泛型变量E赋值了。查阅ArrayList的API你会知道,泛型变量E出现在很多方法中:
boolean add(E e)
E get(int index)
因为我们在创建list对象时给泛型类型赋值为String,所以对于list对象而言,所有API中的E都会被String替换。
boolean add(String e)
String get(int index)
也就是说,在使用list.add()时,只能传递String类型的参数,而list.get()方法返回的一定是String类型。
list.add(“hello”);
String s = list.get(0);
1.2 使用泛型对象
创建泛型对象时,引用和new两端的泛型类型需要一致,例如上面的引用是List<String>,而new一端是new
ArrayList<String>,两端都是String类型!如果不一致就会出错:
List<Object> list = new ArrayList<String>();//编译失败!
Collection的addAll()方法中使用了通配符(这个概念在下一个基础加强中讲解),所以使用起来比较方便:
List<Object> list = new ArrayList<Object>(); List<String> list1 = new ArrayList<String>(); List<Integer> list2 = new ArrayList<Integer>(); list.addAll(list1); list.addAll(list2); |
[b]2 泛型的好处[/b]
l 将运行期遇到的问题转移到了编译期;
l 泛型不可能去除所有类型转换,但可以减少了类型转换操作;
l 在循环遍历集合类时,方便了很多;
l 一定程度上提高了安全性。
[b]3 自定义泛型类的语法[/b]
3.1 自定义泛型类的语法
public class 类型<一到多个泛型变量的声明> {…}
例如:
public class A<T> {...}
A类中有一个泛型变量的声明(或称之为定义)。这就相当于创建了一个变量一样,然后就可以在类内使用它了。
3.2 泛型类内使用泛型变量
声明的泛型变量可以在类内使用,例如创建实例变量时使用泛型变量指定类型,可以在实例方法中指定参数类型或返回值类型,但不能在static变量或static方法中使用泛型变量。
public class A<T> {
private T bean;
public T getBean() {
return bean;
}
public void setBean(T bean) {
this.bean = bean;
}
}
[b]4 继承(或实现)泛型类(或接口)[/b]
在Java API中有很多类和接口是泛型的,如果我们需要继承或实现它们时,需要为父类或接口中的泛型变量指定值,例如Comparable就是一个泛型接口。
Comparable
public interface Comparable<T> { public int compareTo(T o); } |
该接口中有一个泛型变量T,在实现这个接口时需要为其指定值。一定为其指定值后,所有的T将使用指定的值来替换。
MyComparable
public class MyComparable implements Comparable<String> { public int compareTo(String o) { return 0; } } |
在继承(或实现)泛型类(或接口)时还有一种选择,如果当前类是泛型类,也可以把自己的泛型变量赋给父类(或接口)。
MyComparable2
public class MyComparable2<X> implements Comparable<X> { public int compareTo(X o) { return 0; } } |
MyComparable2<Integer> c = new MyComparable2<Integer>(); |
[b]5 泛型方法定义[/b]
不只可以创建泛型类,还可以创建泛型方法。可能你会有个误区,下面的方法不是泛型方法:
class A<T> { public void fun(T t) {…} } |
上面fun()方法是泛型类中的方法,它不是泛型方法。
泛型方法是可以自己创建泛型变量,泛型方法中创建的泛型变量只能在本方法内使用。泛型方法可以是实例方法,也可以是静态方法。
public <T> T get(T[] ts, int index) {
return ts[index];
}
我们必须要区别开什么是创建泛型变量,什么是使用泛型变量。其中<T>是创建泛型变量,它必须在返回值前面给出。
泛型方法中的泛型变量只有两个可以使用的点:返回值和参数,而且所有有意义的泛型方法中都会在返回值和参数两个位置上使用泛型变量,但语法上没有强制的要求。
调用泛型方法,通常无需为泛型变量直接赋值,而是通过传递的参数类型间接为泛型变量赋值,例如:
String[] strs = {“hello”, “world”};
String s = get(strs, 0);
因为给T[] ts参数赋值为strs,而strs的变量为String[],所以等同与给get方法的泛型变量赋值为String类型。所以返回值类型T为String类型。
泛型擦除
泛型是编译期状态,所有的泛型会被编译器擦除,变成了Object类型!编译器会在适当的位置上给你添加强转!
枚举(鸡肋)
[b]1 什么是枚举类型[/b]
我们学习过单例模式,即一个类只有一个实例。而枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如word文档的对齐方式有几种:左对齐、居中对齐、右对齐。开车的方向有几种:前、后、左、右!
我们称呼枚举类中实例为枚举项!一般一个枚举类的枚举项的个数不应该太多,如果一个枚举类有30个枚举项就太多了!
[b]2 定义枚举类型[/b]
定义枚举类型需要使用enum关键字,例如:
public enum Direction { FRONT, BEHIND, LEFT, RIGHT; } |
Direction d = Direction.FRONT; |
注意,定义枚举类的关键字是enum,而不是Enum,所有关键字都是小写的!
其中FRONT、BEHIND、LEFT、RIGHT都是枚举项,它们都是本类的实例,本类一共就只有四个实例对象。
在定义枚举项时,多个枚举项之间使用逗号分隔,最后一个枚举项后需要给出分号!但如果枚举类中只有枚举项(没有构造器、方法、实例变量),那么可以省略分号!建议不要省略分号!
不能使用new来创建枚举类的对象,因为枚举类中的实例就是类中的枚举项,所以在类外只能使用类名.枚举项。
[b]3 枚举与switch[/b]
枚举类型可以在switch中使用
Direction d = Direction.FRONT; switch(d) { case FRONT: System.out.println("前面");break; case BEHIND:System.out.println("后面");break; case LEFT: System.out.println("左面");break; case RIGHT: System.out.println("右面");break; default:System.out.println("错误的方向"); } Direction d1 = d; System.out.println(d1); |
注意,在switch中,不能使用枚举类名称,例如:“case Direction.FRONT:”这是错误的,因为编译器会根据switch中d的类型来判定每个枚举类型,在case中必须直接给出与d相同类型的枚举选项,而不能再有类型。
[b]4 所有枚举类都是Enum的子类[/b]
所有枚举类都默认是Enum类的子类,无需我们使用extends来继承。这说明Enum中的方法所有枚举类都拥有。
l int compareTo(E e):比较两个枚举常量谁大谁小,其实比较的就是枚举常量在枚举类中声明的顺序,例如FRONT的下标为0,BEHIND下标为1,那么FRONT小于BEHIND;
l boolean equals(Object o):比较两个枚举常量是否相等;
l int hashCode():返回枚举常量的hashCode;
l String name():返回枚举常量的名字;
l int ordinal():返回枚举常量在枚举类中声明的序号,第一个枚举常量序号为0;
l String toString():把枚举常量转换成字符串;
l static T valueOf(Class enumType, String name):把字符串转换成枚举常量。
[b]5 枚举类的构造器[/b]
枚举类也可以有构造器,构造器默认都是private修饰,而且只能是private。因为枚举类的实例不能让外界来创建!
enum Direction { FRONT, BEHIND, LEFT, RIGHT; Direction() { System.out.println("hello"); } } |
其实创建枚举项就等同于调用本类的无参构造器,所以FRONT、BEHIND、LEFT、RIGHT四个枚举项等同于调用了四次无参构造器,所以你会看到四个hello输出。
[b]6 枚举类可以有成员[/b]
其实枚举类和正常的类一样,可以有实例变量,实例方法,静态方法等等,只不过它的实例个数是有限的,不能再创建实例而已。
enum Direction { FRONT("front"), BEHIND("behind"), LEFT("left"), RIGHT("right"); private String name; Direction(String name) { this.name = name; } public String getName() { return name; } } |
Direction d = Direction.FRONT; System.out.println(d.getName()); |
因为Direction类只有唯一的构造器,并且是有参的构造器,所以在创建枚举项时,必须为构造器赋值:FRONT(“front”),其中”front”就是传递给构造器的参数。你不要鄙视这种语法,你应该做的是接受这种语法!
Direction类中还有一个实例域:String name,我们在构造器中为其赋值,而且本类还提供了getName()这个实例方法,它会返回name的值。
[b]7 枚举类中还可以有抽象方法(了解)[/b]
还可以在枚举类中给出抽象方法,然后在创建每个枚举项时使用“特殊”的语法来重复抽象方法。所谓“特殊”语法就是匿名内部类!也就是说每个枚举项都是一个匿名类的子类对象!
通常fun()方法应该定义为抽象的方法,因为每个枚举常量都会去重写它。
你无法把Direction声明为抽象类,但需要声明fun()方法为抽象方法。
enum Direction { FRONT() { public void fun() { System.out.println("FROND:重写了fun()方法"); } }, BEHIND() { public void fun() { System.out.println("BEHIND:重写了fun()方法"); } }, LEFT() { public void fun() { System.out.println("LEFT:重写了fun()方法"); } }, RIGHT() { public void fun() { System.out.println("RIGHT:重写了fun()方法"); } }; public abstract void fun(); } |
[b]8 每个枚举类都有两个特殊方法[/b]
每个枚举类都有两个不用声明就可以调用的static方法,而且这两个方法不是父类中的方法。这又是枚举类特殊的地方,下面是Direction类的特殊方法。
l static Direction[] values():返回本类所有枚举常量;
l static Direction valueOf(String name):通过枚举常量的名字返回Direction常量,注意,这个方法与Enum类中的valueOf()方法的参数个数不同。
相关文章推荐
- Java web学习指南
- STL技术文章不完全列表(STL学习使用指南)
- 高质量C++/C编程指南学习笔记(上)
- Web 2.0学习指南
- STL学习使用指南
- JAVA WEB学习笔记-Cookie和Session专题
- Boost 库 学习指南
- 学习笔记[序列化].NET Framework 开发员指南
- 【原创】 C++ 学习指南一 (草稿) --送给各位C++初学者的新年礼物
- JSP快速学习指南
- 命令行环境学习C#指南
- C++ 学习指南——这篇文章真是太经典了(转载)
- Ant学习指南
- 学习JSP指南
- [转贴]Rational Rose 入门指南:项目经理学习路径
- 手机软件开发学习准备指南
- Struts快速学习指南01(内部培训教材)-大部分素材来自于《Programming Jakarta Struts》一书
- sqlmap 学习指南
- Ant学习指南
- Ant学习指南