泛型(Generic)
当集合中存储的对象类型不同时,那么会导致程序在运行的时候的转型异常。解决:通过给容器加限定的形式规定容器只能存储一种类型的对象.
泛型的好处: JDK1.5 的特性,低于这个版本会报错
* 1. 将运行时的异常提前到编译时;
* 2. 不需要强转
格式: 集合类<类类型> 变量名 = new 集合类<类类型>()
eg: * ArrayList<String> list = new ArrayList<String>(); 对 ,推荐使用
* ArrayList<Object> list = new ArrayList<String>(); 错
* ArrayList<String> list = new ArrayList<Object>(); 错
* // 以下两种写法是为了兼容
* ArrayList<String> list = new ArrayList(); 对
* ArrayList list = new ArrayList<String>(); 对
注意: 泛型没有多态的概念,左右两边的数据类型必须要一致,或者只是写一边的泛型类型;
实例: 把小写字母改成大写字母
public class test_1{
public static void main(String args[]) {
// <String> 表示该容器只能存储字符串类型的数据
ArrayList<String> list = new ArrayList<String>();
list.add("a");
list.add("aa");
list.add("ab");
list.add("cd");
// 编译的时候就报错
// list.add(123);
for(int i=0; i<list.size(); i++) {
String str = list.get(i);
System.out.println(str.toUpperCase());
}
}
}
自定义泛型: 一个数据类型的占位符或者一个数据类型的变量
需求: 定义一个方法可以接收任意类型的参数,而且返回类型必须要与实参的类型一致* 修饰符 <声明自定义的泛型>返回值类型 函数名() { ...... }
eg: public <T> T getData(T data) {
return data;
}
* 在泛型中不能使用基本的数据类型,如果需要使用基本的数据类型, 那么就使用基本数据类型对应的包装类型 。
* int---->Integer
* short--->Short
* long------>Long
* byte---->Byte
* double---->Double
* float----->Float
* boolean------>Boolean
* char------->Character
*
* 方法泛型注意的事项:
* 1. 在方法上自定义泛型,
* 这个自定义泛型的具体数据类型是在调用该方法的时候传入实参时确定具体的数据类型的。
* 2. 自定义泛型只要符合标识符的命名规则即可,
* 但是自定义泛型我们一般都习惯使用一个大写字母表示。 T (Type) 或者 E (Element)
public class test_1{
public static void main(String args[]) {
String str = getData("aa");
int qq = getData(123);
}
// <T>T , <abc>abc 只是一个占位符
public static <abc>abc getData(abc obj) {
return obj;
}
}
泛型类:
类上的泛型声明格式: 修饰符 class 类名<泛型> { ...... }注意事项:
* 1. 在类上自定义泛型的具体数据类型是在使用该类的时候创建对象时候确定的
* 2. 如果一个类在类上已经声明了自定义泛型,如果使用该类创建对象的时候没有指定泛型的具体数据类型,那么默认为Object类型。
* 3. 在类上自定义泛型不能作用于静态的方法,如果静态的方法需要使用自定义泛型,那么需要自己声明使用
class Myarray<T>{
// 元素翻转
public void reverse(T[] arr){
for(int n = 0, endindex = arr.length-1; n<endindex; n++,endindex--) {
T temp = arr[n];
arr[n] = arr[endindex];
arr[endindex] =temp;
}
}
public <T>String toString(T[] arr) {
StringBuilder sb = new StringBuilder();
for (int i=0; i<arr.length; i++) {
if(i==0) {
sb.append("[" + arr[i] + ",");
}else if (i == arr.length-1) {
sb.append(arr[i] + "]");
}else {
sb.append(arr[i] + ",");
}
}
return super.toString();
}
// 静态的不能引用非静态的!!!! 方法中自定义
// public static void print(T[] t) {}
// 这个T 是传入的时候确定数据类型
public static <T>void print(T[] t) {}
}
public class test_1{
public static void main(String args[]) {
Integer[] arr = {10,12,14,19};
Myarray<Integer> tool = new Myarray<Integer>();
tool.reverse(arr);
System.out.println(tool.toString(arr));
}
}
泛型 (Generic)接口
* 泛型接口定义格式:
* interface 接口名<声明自定义泛型>{ ...... }
* 注意: !!
* 1. 接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定的。
* 2. 如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型。
*
* 需求: 目前我实现一个接口的时候,我还不明白我目前要操作的数据类型,
* 我要等待创建接口实现类 对象的时候我才能指定泛型的具体数据类型。
interface fzx<T>{
public void add(T t);
}
public class test_1<T> implements fzx<T>{
public static void main(String args[]) {
test_1<String> nvxia = new test_1<String>();
}
public void add(T t) {
}
}
泛型的上下限
* 需求: 定义一个函数可以接收任意类型的集合对象。
* 并且接收的集合对象只能存储Integer或者Integer的父类类型
* 泛型中的通配符:
* ? super Integer 表示可以接受Integer或者Integer的父类类型
? extends Number 接收Number 类型或者Number的子类型
* eg: Vector<? super Integer> x = new Vector<Number>();
* 需求: 定义一个函数可以接收任意类型的集合对象。
* 并且接收的集合对象只能存储Number或者Number的子类类型
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
public class test_1 {
public static void main(String args[]) {
ArrayList<Integer> list = new ArrayList<Integer>();
ArrayList<Number> list2 = new ArrayList<Number>();
HashSet<String> set = new HashSet<String>();
print(list2);
println(list);
}
//下限
public static void println (Collection<? extends Number> c) {
}
// 这个可以接收任意类型的集合 ,但不接收别的,比如字符串 泛型上限!!
public static void print (Collection<? super Integer> c) {
}
}
复习:
* 单例集合的体系:
* collection 单例集合的跟接口
* List 有序,可重复
* ArrayList 底层使用了Object数组实现。特点:查询快,增删慢
* LinkedList 链表数据结构实现的, 查询慢,增删块
* Vector 与ArrayList是一致的,但是线程安全的,操作效率低。
* Set 无序,不可重复
* HashSet 底层使用了一个哈希表支持,特点: 存取快
* HashSet 添加元素的原理:
* 首先 HashSet 会调用元素的hashCode方法得到元素的哈希码值,然后会经过一系列运算,
* 就可以算出该元素在哈希表的存储位置。
* 情况1: 算出该元素的位置目前没有任何元素存储,那么该元素直接存储
* 情况2: 如果该位置已经存在其他元素,那么还会调用元素的equals方法与该位置再比较一次。
*
* 如果equals返回false 该元素允许存储,若为 true,不允许存储
*
* TreeSet 底层使用了红黑树(二叉树)数据结构实现的,特点:会对元素进行排序存储。
* 注意事项:
* 1. 添加元素的时候,元素本身具备自然顺序的特性,那么会根据自然顺序进行排序存储。
* 2. 不具备自然顺序的特性,那么元素所属类必须要实现Comparable接口,
* 把元素的比较规则定义在CompareTo方法上。
* 3. 不具备自然顺序的特性,而且元素所属的类 没有 实现Comparable 接口,
* 那么必须创建TreeSet对象时传入比较器。
* 4. 如果比较的方法(CompareTo 或者 Compare )返回的是0,该元素为重复元素,不允许添加。
* 比较器的定义格式:自定义一个类实现Comparator接口即可
* class 类名 implements Comparator{
*
* }
*
* 泛型: JDK1.5以后出现的, 好处: 1. 编译就可知道是否出错;2. 避免无谓的强制性转换
* 泛型方法:
* 修饰符 <声明自定义的泛型>返回值类型 函数名(自定义的泛型 变量名)
*
* 泛型接口定义格式:
* interface 接口名<声明自定义泛型>{
*
* }
* 注意: !!
* 1. 接口上自定义的泛型的具体数据类型是在实现一个接口的时候指定的。
* 2. 如果在实现接口的时候没有指定具体的数据类型,那么默认为Object类型
*
* 泛型的上下限:
* 泛型中的通配符:
* ? super Integer 表示可以接受Integer或者Integer的父类类型
* ? extends Number 接收的集合对象只能存储Number或者Number的子类类型
*/