集合类、泛型、枚举
1.集合类:
使用集合框架的原因:
有些数据用数组存储不方便,因为数组的长度是固定的。我们需要其他的存储结构来存放长度可变的数据(如对象),所以java.util包中提供了一些集合类(容器)。
Coleection: list:用来装有序的东西(带格子的抽屉)
—— > ArrayList:底层是用数组实现
—— > LinkList:底层是用链表实现
set:用来装无序的东西(箱子,不能重复)
—— > HashSet:可以为空,由HashMap实现所以迭代顺序不确定
—— > TreeSet:按照自然顺序递增排序(对象必须实现comparator接口),也可以按照指定比较器递增排序(重写compare方法)
Map:用来装一对一的东西:(字典)
—— > HashMap:允许null键,但必须唯一。遍历时无序,若要有序可以将他在放入treeMap中。或用HashMap的子类LinkedHashMap(按数据放入顺序输出)
—— > TreeMap:不允许null键。遍历时有序(一般是键对象升序),但添加、删除和定位映射关系时性能差于HashMap
另外,介绍个工具类,java.util.Collections。注意,这不是Collection接口。Collections很像 Arrays类。Arrays提供了一系列用于对数组操作的静态方法,查找排序等等。Collections也提供了一系列这样的方法,只是它是用于处理 集合的,虽然Collections类和Collection接口很像,但是不要被Collections的名字给欺骗了,它不是只能处理 Collection接口以及子接口的实现类,同样也可以处理Map接口的实现类。
集合的遍历(以HashMap举例):
//HashMap的三种迭代输出
1.
HashMap<Integer,ProductInfo> maps = (HashMap)session.getAttribute("shopcar");
for(Map.Entry<Integer,ProductInfo> map : maps.entrySet()){
ProductInfo info = map.getValue();
}
2.
Iterator<Interger> iterator = maps.keySet().iterator()
while(iterator.hasNext()){
Interger key = iterator.next();
String value = maps.get(key);
System.out.println(key);
}
3.for(Iterator<Interger> iter = maps.keySet().iterator();iter.hasNext();){
Integer key = iter.next():
String value = maps.get(key);
System.out.println(key);
}
2.枚举:
我们可以将枚举类型看作是一个类(它实际编译时也会生成一个class类)。它继承于java.lang.Enum类,当我们定义一个枚举类型时,可以看作是一个枚举类的实例,而且默认被public static final修饰。所以可以直接通过枚举名来使用枚举中的属、方法以及java.lang.Enum中的方法(values()、valueOf()、ordinal()等);我们也可以将枚举类看作是类似于int,char的一种数据类型,但你只能给它赋予enum里面规定的值;我们还可以将枚举看作是用来存储数据的数组或集合,但它只用来存放数据值固定,而且个数确定的数据。
枚举的优点:枚举它类型安全,运行效率高,紧凑有效的数据定义,可以和程序其他部分完美交互
枚举的使用:当我们知道数据集中数据的所有个数(如一年有春、夏、秋、冬,人有男人、女人,并且想为这些数据赋予属性和方法时我们就可以使用枚举)。枚举既可以定义在类外也可以定义在类里面(在类里面时类似于内部类)。
interface Constants { // 将常量放置在接口中
public static final int Constants_one= 1;
public static final int Constants_two = 2;
}
interface d {
public String getDescription();
public int getI();
}
enum Constants1 { // 将常量放置类内的枚举类型中,类似与内部类,当然也可以在类外部定义一个枚举存放
Constants_one, Constants_two
}
enum Constants2{ // 将常量放置在枚举类型中
Constants_A("我是枚举成员A"), // 定义带参数的枚举类型成员
Constants_B("我是枚举成员B"),
Constants_C(3),
Constants_D(4);
private String description;
private int i = 4;
private Constants2() {
}
// 定义参数为String型的构造方法
private Constants2(String description) {
this.description = description;
}
private Constants2(int i) { // 定义参数为整型的构造方法
this.i = this.i + i;
}
public String getDescription() { // 获取description的值
return description;
}
public int getI() { // 获取i的值
return i;
}
}
enum AnyEnum implements d { //实现接口的枚举
A { // 可以在枚举类型成员内部设置方法
public String getDescription() {
return ("我是枚举成员A");
}
public int getI() {
return i;
}
},
B {
public String getDescription() {
return ("我是枚举成员B");
}
public int getI() {
return i;
}
},
C {
public String getDescription() {
return ("我是枚举成员C");
}
public int getI() {
return i;
}
},
D {
public String getDescription() {
return ("我是枚举成员D");
}
public int getI() {
return i;
}
};
private static int i = 5;
}
public class Test {
// 使用接口定义常量
public static void doit(int c) { // 定义一个方法,这里的参数为int型
switch (c) { // 根据常量的值做不同操作
case Constants.Constants_one:
System.out.println("doit() Constants_one");
break;
case Constants.Constants_two:
System.out.println("doit() Constants_two");
break;
}
}
// 定义一个方法,这里的参数为枚举类型对象
public static void doit2(Constants1 c) {
switch (c) { // 根据枚举类型对象做不同操作,与doit()对比好处是doit2()只接受我们定义的数据,否则编译会报错
case Constants_one:
System.out.println("doit2() Constants_one");
break;
case Constants_two:
System.out.println("doit2() Constants_two");
break;
}
}
public static void main(String[] args) {
//测试省略
}
}
3.泛型:
我们要进行强制类型转换的时候一般都会用instanceof来判断父类对象是不是子类的一个实例,从而判断是否可以强制转换,避免运行时异常(ClassCastExcoption)。但很多时候会不经意间进行强制转换,而使用泛型就可一避免发生ClassCastException,如果不能强制转换它会在编译时就报错。import java.util.*;
public class MutiOverClass<K, V> {
public Map<K, V> m = new HashMap<K, V>(); // 定义一个集合HashMap实例
// 设置put()方法,将对应的键值与键名存入集合对象中
public void put(K k, V v) {
m.put(k, v);
}
public V get(K k) { // 根据键名获取键值
return m.get(k);
}
public static void main(String[] args) {
// 实例化泛型类对象
MutiOverClass<Integer, String> mu
= new MutiOverClass<Integer, String>();
for (int i = 0; i < 5; i++) {
// 根据集合的长度循环将键名与具体值放入集合中
mu.put(i, "我是集合成员" + i);
}
for (int i = 0; i < mu.m.size(); i++) {
// 调用get()方法获取集合中的值
System.out.println(mu.get(i));
}
}
}
其实上面这个类定义为泛型类是多余的,因为Java中ArrayList、HashMap、HashSet、Vector这些集合框架已经都被泛型化了。
public class ArrayClass<T> {
private T[] array; // 定义泛型数组
public void SetT(T[] array) { // 设置SetXXX()方法为成员数组赋值
this.array = array;
}
public T[] getT() { // 获取成员数组
return array;
}
public static void main(String[] args) {
ArrayClass<String> a = new ArrayClass<String>();
String[] array = { "成员1", "成员2", "成员3", "成员4", "成员5" };
a.SetT(array); // 调用SetT()方法
for (int i = 0; i < a.getT().length; i++) {
System.out.println(a.getT()[i]); // 调用getT()方法返回数组中的值
}
}
}
在该例中定义泛型类时声明一个泛型的成员数组,然后在泛型类中设置set与get方法就可以定义一个类型不确定的数组。但是不可以直接使用泛型来简历数组
实例(private T[] array = new T[10] )这是错误的。
3.泛型的其他用法:
使用class 类名称<T extends anyClass>来限制该类必须是anyClass的子类或实现了anyClass接口,类似的我们可以使用类型通配符来声明一个必须是某个类子类或实现了某个接口的对象变量A<? extends anyClass> a,或规定传入参数的类型public void do(A<? extends List>){};同理也可以使用super关键字向上限制。
注意:A<?>默认表示为A可以实例化Object及其子类的类型,不同的是这样实例化的对象不能对其加入新的信息,只能获取或删除。
若一个泛型类继承另一个泛型类或实现泛型接口需要在继承中指明,否则这个泛型类的泛型都会自动变为Object。
class SubClass<T1,T2> extends ExtendClass<T1>{}这是对的,后面的ExtendClass<T1>不能省略<T1>