1 泛型
什么是泛型?为什么要使用泛型?
泛型,即"参数化类型"。一提到参数,最熟悉的就是定义方法时有形参,然后调用此方法时传递实参。那么参数化类型怎么理解呢?顾名思义,就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后再使用/调用时传入具体的而类型(类型实参)。
泛型的本质是为了参数化类型 ( 在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型 ) 。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数,这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
【示例】无泛型的例子
ArrayList list = new ArrayList();
list.add("adddff");
list.add("123");
list.add(new Integer(123));
Iterator it = list.iterator();
while(it.hasNext()){
String str = (String)it.next();
System.out.println(str);
}
java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
为了解决这一问题,JDK1.5引入了泛型新机制,用于解决安全问题,是一个安全机制。
泛型的出现把运行时期的问题,转移到了编译时期。同时避免了强制转化的麻烦。
【示例】有泛型
ArrayList list = new ArrayList<>();
list.add("adddff");
list.add("123");
list.add(new Integer(123));
有了泛型之后再编译器就会报错, add(java.lang.String) in ArrayList cannot be applied to(java.lang.Integer)
1.1 泛型的使用方式
泛型由三种使用方式:泛型类、泛型接口、泛型方法。
泛型类 泛型类型用于类的定义中,被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口,最典型的就是各种容器类,比如:List、Set、Map。
泛型类的最基本写法 : class 类名 {}
【示例】最普通的泛型类
public class Generic{
private T key;
public Generic(T key){
this.key = key;
}
public T getKey(){
retrun T;
}
}
泛型传递的类型参数只能是引用数据类型,不能是基本数据类型。
比如:class Generic{},下面的T全部自动转为String类型。
泛型类不一定要传入类型实参,泛型只是用来限制传入数据的类型。不写的话一样没有问题。
【示例】不适用泛型
Generic generic = new Generic("111111"); Generic generic1 = new Generic(4444); Generic generic2 = new Generic(55.55); Generic generic3 = new Generic(false);
Log.d("泛型测试","key is " + generic.getKey());
Log.d("泛型测试","key is " + generic1.getKey());
Log.d("泛型测试","key is " + generic2.getKey());
Log.d("泛型测试","key is " + generic3.getKey());
D/泛型测试: key is 111111
D/泛型测试: key is 4444
D/泛型测试: key is 55.55
D/泛型测试: key is false
泛型接口
泛型接口与泛型类的定义和使用基本相同。泛型接口常备用在各种类的生产器中。
【示例】泛型接口的定义
public interface Genertic{
public T next();
}
当实现泛型接口的类,未传入泛型实参时:
【示例】
/**
* 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
* 即:class FruitGenerator implements Generator{
* 如果不声明泛型,如:class FruitGenerator implements Generator,编译器会报错:"Unknown class"
*/
class FruitGenerator implements Generator{
@Override
public T next() {
return null;
}
}
当实现泛型接口的类,传入泛型实参时:
/**
* 传入泛型实参时:
* 定义一个生产器实现这个接口,虽然我们只创建了一个泛型接口Generator
* 但是我们可以为T传入无数个实参,形成无数种类型的Generator接口。
* 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
* 即:Generator,public T next();中的的T都要替换成传入的String类型。
*/
public class FruitGenerator implements Generator {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
泛型方法
【示例】
/**
* 泛型方法的基本介绍
* @param tClass 传入的泛型实参
* @return T 返回值为T类型
* 说明:
* 1)public 与 返回值中间非常重要,可以理解为声明此方法为泛型方法。
* 2)只有声明了的方法才是泛型方法,泛型类中的使用了泛型的成员方法并不是泛型方法。
* 3)表明该方法将使用泛型类型T,此时才可以在方法中使用泛型类型T。
* 4)与泛型类的定义一样,此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型。
*/
public T genericMethod(Class tClass)throws InstantiationException ,
IllegalAccessException{
T instance = tClass.newInstance();
return instance;
}
2 集合(ArrayList、LinkedList、Vector)
为什么会出现集合类?
面向对象语言对事物的体现都是以对象的形式。所以为了方便对多个对象的操作,就对对象进行储存,集合就是储存对象最常用的而一种方式。
数组和集合类同时容器,有何不同?
数组虽然也可以储存对象,但长度是固定的;集合长度是可变的的。 数组中可以储存基本数据类型,集合只能储存对象。
集合类的特点: 集合只用于储存对象,集合长度是可变的,集合可以储存不同类型的对象。
Collection集合体系
Collection
List Set
ArrayList HashSet
LinkedList TreeSet
Vector
Collection是集合容器中的根接口。
为什么会出现这么多的容器呢?
每一个容器对数据储存的方式都有相同。 这个储存方式称为数据结构。
List:元素是有序的,元素可以重复.
List集合特有的方法:
增
add(index, element);
addAll(index, Collection);
删
remove(index);
改
set(index, element);
查
get(index);
subList(from, to);
listIterator();
List集合特有的迭代器ListIterator是Iterator的子接口
在迭代时,不可以通过集合对象的方法操作集合中的元素。
会发生java.util.ConcurrentModificationException异常
所以,在迭代时只能用迭代器的方法操作元素,可以Iterator方法是有限的,
只能对元素进行判断,取出,删除的操作,
如果想要其他操作如添加,修改等,就需要通过子接口ListIterator来实现。
List接口:有三个子类
ArrayList LinkedList Vector
底层实现 数组 双向链表 数组
ArrayList:查询快,增删稍慢。
LinkedList:增删快,查询慢
Vector: 线程安全,效率比ArrayList低。被ArrayList取代了。
LinkedList特有方法
addFirst();
addLast();
在此列表的开头/末尾插入指定的元素。
getFirst();
getLast();
获取元素,但不删除
removeFirst();
removeLast();
获取元素,元素被删除
如果集合中没有元素,会出现noSuchElementException异常
在JDK1.6出现了替代方法,
offerFirst();
offerLast();
在此列表的开头/末尾插入指定的元素。
peekFirst();
peekLast();
获取元素,但不删除元素,如果没有元素,会返回null
pollFirst();
pollLast();
获取元素被删除;如果此列表为空,则返回 null。
ArrayList:
创建一个储存字符串的ArrayList对象:
ArrayList list = new ArrayList();
创建一个储存日期的ArrayList对象:
ArrayList list2 = new ArrayList();
JDK1.7以后,下述表达式
ArrayList list = new ArrayList();
可以简化为: ArrayList list = new ArrayList<>();
因为编译器有一个新的feature叫做类型推断(type inference), 能够从变量声明推断类型。
【示例】ArrayList常用的方法
public static void method_1(){
//创建一个集合容器,使用Collection接口的子类ArrayList
ArrayList list = new ArrayList<>();
//添加元素
list.add("java01");
list.add("java02");
list.add("java03");
list.add("java04");
list.add("java05");
//获取个数,集合长度
sop("size: "+ list.size());
//删除元素
list.remove("java01");
sop(list);
//清空集合
list.clear();
sop(list);
//判断元素
sop("java03是否存在: "+ list.contains("java03"));
sop("集合是否为空呀?"+ list.isEmpty());
}
public static void sop(Object obj){
System.out.println(obj);
}
遍历ArrayList集合中的元素
//遍历元素,迭代器遍历
Iterator iterator = list.iterator();
while(iterator.hasNext()){
Object obj = iterator.next();
System.out.println(obj);
}
//方式二
for(Iterator iterator1 = list.iterator(); iterator1.hasNext();){
System.out.println(iterator1.next());
}
//for循环遍历
for(int i 0; i < list.size(); i++){
sop("list("+ i +")="+list.get(i)+", ");
}
//for-each循环
for(Object obj : list){
System.out.println(obj);
}