泛型
泛型是jdk1.5使用的新特性
泛型的好处:
1. 将运行时的异常提前至了编译时
2. 避免了无谓的强制类型转换
泛型在集合中的常见应用:
ArrayList<String> list = new ArrayList<String>(); true 推荐使用
以下两种写法主要是为了兼顾新老系统的兼用性问题。
ArrayList<String> list = new ArrayList(); true
ArrayList list = new ArrayList<String>(); true
注意: 泛型没有多态的概念,左右两边的数据类型必须要一致,或者只是写一边的泛型类型
推荐使用: 两边都写泛型
import java.util.ArrayList; public class Demo1 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<String>(); //<String> 表示该容器只能存储字符串类型的数 list.add("aa"); list.add("bb"); list.add("cc"); for(int i = 0 ; i < list.size() ; i++){ String str = list.get(i); System.out.println("大写:"+ str.toUpperCase()); } } }
自定义泛型: 自定义泛型就是一个数据类型的占位符或者是一个数据类型的变量。
方法上自定义泛型:
修饰符 <声明自定义的泛型>返回值类型 函数名(使用自定义泛型){
}
在泛型中不能使用基本数据类型,如果需要使用基本数据类型,那么就使用基本数据类型对应的包装类型。
byte----> Byte
short---> Short
int----> Integer
long----> Long
double ----> Double
float -----> Float
boolean----->Boolean
char-------> Character
方法泛型注意的事项:
1. 在方法上自定义泛型,这个自定义泛型的具体数据类型是在调用该 方法的时候传入实参时确定具体的数据类型的。
2. 自定义泛型只要符合标识符 的命名规则即可, 但是自定义泛型我们一般都习惯使用一个大写字母表示。 T Type E Element
public class Demo2 { public static void main(String[] args) { String str = getData("abc"); Integer i = getData(123); } public static <T>T getData(T o){ return o; } }
泛型类:
泛型类的定义格式:
class 类名<声明自定义泛型>{
}
泛型类要注意的事项
1. 在类上自定义泛型的具体数据类型是在使用该类的时候创建对象时候确定的。
2. 如果一个类在类上已经声明了自定义泛型,如果使用该类创建对象 的时候没有指定 泛型的具体数据类型,那么默认为Object类型
3.在类上自定义泛型不能作用于静态的方法,如果静态的方法需要使用自定义泛型,那么需要在方法上自己声明使用。
import java.util.ArrayList; class MyArrays<T>{ public void reverse(T[] arr){ for(int start = 0, end = arr.length-1 ; start<end ; start++,end--){ T temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; } } public String toString(T[] arr){ StringBuilder S = new StringBuilder(); for(int i = 0 ; i < arr.length ; i++){ if(i==0){ S.append("["+arr[i]+","); }else if(i==arr.length-1){ S.append(arr[i]+"]"); }else{ S.append(arr[i]+","); } } return S.toString(); } public static <T>void print(T[] t){ //类上的自定义泛型无法作用于静态方法,必须重新声明 } } public class Demo2 { public static void main(String[] args) { Integer[] arr = {10,12,14,19}; MyArrays<Integer> tool = new MyArrays<Integer>(); tool.reverse(arr); System.out.println("数组的元素:"+tool.toString(arr)); MyArrays<String> tool2 = new MyArrays<String>(); String[] arr2 = {"aaa","bbb","ccc"}; tool2.reverse(arr2); ArrayList<String> list = new ArrayList<String>(); } }
泛型接口
泛型接口的定义格式:
interface 接口名<声明自定义泛型>{
}
泛型接口要注意的事项:
1. 接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定 的。
2. 在接口上自定义的泛型如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型。
如果要延长接口自定义泛型 的具体数据类型,那么格式如下:
格式:
public class Demo4<T> implements Dao<T>{
}
interface Dao<T>{ public void add(T t); } public class Demo3<T> implements Dao<T> { public static void main(String[] args) { Demo3<String> d = new Demo3<String>(); } @Override public void add(T t) { // TODO Auto-generated method stub } }
泛型的上下限
(以例题展示方法)
需求1: 定义一个函数可以接收接收任意类型的集合对象, 要求接收的集合对象只能存储Integer或者是Integer的父类类型数据。
需求2: 定义一个函数可以接收接收任意类型的集合对象, 要求接收的集合对象只能存储Number或者是Number的子类类型数据。
泛型中通配符: ?
? super Integer : 只能存储Integer或者是Integer父类元素 泛型下限
? extends Number : 只能存储Number或者是Number类型的子类数据 泛型上限
import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; public class Demo4 { public static void main(String[] args) { ArrayList<Integer> list1 = new ArrayList<Integer>(); ArrayList<Number> list2 = new ArrayList<Number>(); HashSet<String> set = new HashSet<String>(); //getData(set); } //泛型的上限 public static void getData(Collection<? extends Number> c){} //泛型的下限 public static void print(Collection<? super Integer> c){} }
集合之小结
单例集合 的体系:
Collection 单例集合的根接口
List 如果是实现了List接口的集合类, 具备的特点:有序,重复。
ArraryList 底层 是使用了Object数组实现的,特点: 查询速度快,增删慢。
LinkedList 底层是使用了链表数据结构实现 的, 特点: 查询速度慢,增删快。
Vector Vector的实现与ArrayList是一致,但是是线程安全 的,操作效率低。 jdk1.0的时候出现的
Set 如果是实现了Set接口的集合类,具备的特点:无序,不可重复。
HashSet 底层是使用了一个哈希表支持的, 特点:存取速度快。
HashSet添加元素的原理:往HashSet添加元素的时候,首先HashSet会调用元素的hashCOde方法得到元素的哈希码值,然后会经过一系列运算就可以算出该元素在哈希表中的存储位置
情况1:如果算出该元素的位置目前没有任何元素存储,那么该元素可以直接存储
情况2: 如果算出该元素的位置目前已经存有其他的元素,那么还会调用元素的equals方法与该位置的元素再比较一次。
如果equals方法返回的是false,那么该元素允许存储,如果euqlas方法返回的是true,那么该元素被视为重复元素,不允许存储。
TreeSet 底层是使用了红黑树(二叉树)数据结构实现的, 特点:会对元素进行排序存储。
TreeSet要注意的事项:
1. 往TreeSet添加元素的时候,如果元素本身具备自然顺序的特性,那么会根据元素自然顺序的特性进行排序存储。
2. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,那么元素所属的类必须要实现Comparable接口,把元素的比较规则定义
在CompareTo方法上。
3. 往TreeSet添加元素的时候,如果元素本身不具备自然顺序的特性,而且元素所属的类没有实现COmparable接口,那么必须要在创建
TreeSet对象的时候传入比较器。
4. 如果比较的方法(CompareTo 或者Compare )返回的是0的时候,那么该元素就被视为重复元素,不允许添加。
比较器的定义格式: 自定义一个类实现COmparator接口即可。
class 类名 implements Comparator{
}