泛型
一、泛型概念
泛型
:JDK1.5以后,使用容器时,必须明确容器中元素的类型。这种机制称之为 :泛型
。
泛型格式
:
<数据类型>,这种格式不是很难理解,<> 尖括号也是括号,往括号里面写东西其实就是在传递参数。
泛型的好处
:
(1)安全
(2)将运行时期的异常转为编译时期的异常
(3)避免了强制类型转换的麻烦
二、泛型的使用
1.泛型类的使用
2.泛型方法的使用
// <T>声明有一个泛型 T t 真正使用泛型
class Utils<W>{
// 泛型在方法上
public<T> void print(T t,W w){
// 向下转型成w
W w1 = (W)new Object();
System.out.println("print:" + t);
}
public static<Q> Q pr(Q q){
return q;
}
// 静态方法使用泛型 -- 用不了类级别的泛型
// public static<Q> Q pr(Q q,W w){
// W w = (W)new Object();
// }
}
public class Demo03 {
public static void main(String[] args) {
Utils<String> su = new Utils<String>();
su.print(12,"Curley G");
// boolean类型
boolean pr = su.pr(false);
System.out.println(pr);
}
}
3.泛型接口的使用
// 接口
interface Inter<E>{
void show(E e);
}
// 实现类1 -- 明确类型
class ImplInter1 implements Inter<String>{
public void show(String s){
System.out.println("字符串类型:" + s);
}
}
// 实现类2 -- 不明确类型
class ImplInter2<E> implements Inter<E>{
public void show(E e){
System.out.println("不确定类型:" + e);
}
}
// 测试类
public class Demo04 {
public static void main(String[] args) {
// 多态:父类引用指向子类对象
Inter ir = new ImplInter1();
ImplInter1 ir1 = new ImplInter1();
// 多态时泛型限定会有问题
Inter<String> ir3 = new ImplInter2<String>();
ir3.show("Curley");
}
}
4.自定义泛型
// 类 -- Tool
class Tool{
// 年龄
private int age;
public int getAge(){
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// 类 -- Tool1
class Tool1{
// 年龄
private int age;
public int getAge(){
return age;
}
public void setAge(int age) {
this.age = age;
}
}
// 自定义泛型类 T 只是形式
class ToolPlus<T>{
// 用泛型类作为类型
private T t;
// 泛型是不可以实例化的
public T getT(){
// new T();
// T t = (T)new Object(); //将对象向下转型为泛型
return t;
}
public void setT(T t){
this.t = t;
}
}
// 测试类
public class Demo02 {
public static void main(String[] args) {
ToolPlus<String> sp = new ToolPlus<>();
sp.setT("123");
ToolPlus<Integer> sp1 = new ToolPlus<>();
sp1.setT(123);
sp.getT();
sp1.getT();
}
}
三、泛型通配符
当使用泛型类
或者接口
时,传递的具体的类型不确定,可以通过通配符(?)
表示。但是一旦使用泛型的通配符机制后,只能使用Object
类中的共性方法,集合中元素自身方法无法使用。
public class Demo05 {
public static void main(String[] args) {
List<Student> list = new ArrayList<Student>();
list.add(new Student("Curley",22));
list.add(new Student("Idiot",20));
list.add(new Student("Daisy",18));
Set<Worker> set = new HashSet<>();
set.add(new Worker("A",26));
set.add(new Worker("B",28));
set.add(new Worker("C",30));
// LinkedHashSet 既去重又有序
Set<String> sets = new LinkedHashSet<>();
sets.add("a");
sets.add("b");
sets.add("c");
printCollection(list);
System.out.println();
printCollection(set);
System.out.println();
// printCollection(sets);// 因为它没有继承Person类
}
public static void printCollection(Collection<? extends Person> coll){
Iterator<?> it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
四、泛型限定
泛型限定可以这样书写:
? extends Person : 接收Person类型或者Person的子类型。
public static void printCollection(Collection<? extends Person> list) {
for (Iterator<? extends Person> it = list.iterator(); it.hasNext();) {
System.out.println(it.next());
}
}
上述这种限定称为:限定泛型的上限:? extends E:接收E类型或者E的子类型。
当然有上限,肯定也有泛型的下限:? super E:接收E类型或者E的父类型。
在API中TreeSet集合的构造函数中允许我们传递一个其它集合作为TreeSet集合的构造时的初始化数据,并且对传递的这个集合做了相应的限定。TreeSet(Collection<? extends E> c)
我们知道TreeSet集合在定义时要求必须明确其中存放对象的类型,即TreeSet集合的定义格式如下:
class TreeSet<E>{
TreeSet(Collection<? extends E> c){}
}
TreeSet集合的构造函数要求传递数据类型必须是E的子类类型或者E本身。TreeSet集合要保证排序,那么就必须要求在我们创建TreeSet对象是明确的类型本身必须具备比较功能(这个对象要实现Comparable接口),如果我们在创建TreeSet对象时明确数据类型,并且在创建TreeSet时给TreeSet中传递另外一个集合进行初始化,那么这个集合中的对象必须保证和TreeSet对象要求的数据类型保持一致,或者是其子类(只要是其子类,当然就具备比较功能)。所以在设计TreeSet构造函数如果传递集合进行初始化动作,就使用到了泛型的上限。
class TreeSet<E>{
TreeSet(Comparator<? super E> c){}
}
TreeSet集合在定义是要求其中存放的对象类型必须是E类型,当我们给集合传递比较器后,每当给集合中存放元素,都会取出集合中已经存放的元素,并用其和正要存放元素进行比较。可以用比较器用E本身接收,当然也可以用比较器用E的父类接收,即就形成了多态,这样的话就形成了限定的下限了。
代码体现:
// 类 -- A
public class A {
private String str;
// 构造方法
public A(){
}
public A(String str){
this.str = str;
}
}
// 类 -- B 继承 A
class B extends A{
public B(){
}
public B(String str){
super(str);
}
public int compareTo(Object o) {
return 0;
}
}
// 类 -- C 继承 B
class C extends B{
public C(){}
public C(String str){
super(str);
}
}
// 测试类
public class Demo01 {
public static void main(String[] args) {
// 容器1
List<A> list1 = new ArrayList<A>();
list1.add(new A("a1"));
list1.add(new A("a2"));
list1.add(new A("a3"));
list1.add(new A("a4"));
// 容器2
List<B> list2 = new ArrayList<B>();
list2.add(new B("b1"));
list2.add(new B("b2"));
list2.add(new B("b3"));
list2.add(new B("b4"));
// 容器3
List<C> list3 = new ArrayList<C>();
list3.add(new C("c1"));
list3.add(new C("c2"));
list3.add(new C("c3"));
list3.add(new C("c4"));
// B对象始终可以使用
printCollection1(list2);
printCollection2(list2);
// printCollection2(list1); (<? extends B> B或者B的子类)
printCollection2(list1);
// printCollection1(list3); (<? super B> B的父类或者B)
printCollection1(list3);
TreeSet<B> treeSet = new TreeSet<B>(new Comparator<A>(){
public int compare(A o1, A o2) {
B b = (B)o1;
B b2 = (B)o2;
return b.compareTo(b2);
}
});
}
// 上限限定 (继承)
public static void printCollection1(Collection<? extends B> coll){
Iterator it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
// 下线限定
public static void printCollection2(Collection<? super B> coll){
Iterator it = coll.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
五、自定义线性表
// 接口类
public interface List<E> extends Iterable<E> {
// 在表尾添加新元素
public void add(E element);
// 在指定位置添加新元素
public void add(int index,E element);
// 移除指定元素
public void remove(E element);
// 移除指定位置元素,并获取旧元素
public E remove(int index);
// 获取指定位置元素
public E get(int index);
// 替换指定位置元素,并获取旧元素
public E set(int index,E element);
// 获取线性表长度
public int size();
// 查找指定元素并获取位置
public int indexOf(E element);
// 判断是否包含指定元素
public boolean contains(E element);
// 判断是否为空
public boolean isEmpty();
// 清空线性表
public void clear();
// 根据比较器排序
public void sort(Comparator<E> c);
// 截取新线性表
public List<E> subList(int startIndex,int endIndex);
}
public class ArrayList<E> implements List<E>{
// ArrayList 默认容量大小为10
private static final int DEFAULT_CAPACITY = 10;
// 底层的容器
private E[] value;
// 有效长度
private int size;
// 构造区
public ArrayList(){
this(DEFAULT_CAPACITY);
}
// 指定容器大小
public ArrayList(int capacity){
if(capacity < 0){
throw new IllegalArgumentException("容量数据错误,初始化失败!");
}
value = (E[])new Object[capacity];// 初始化E数组
size = 0;// 有效长度为0
}
// 指定数组E[] -- O(n) n:arr.length
public ArrayList(E[] arr){
if(arr == null){
throw new IllegalArgumentException("数组不能为null!");
}
// 创建一个大小arr数组
value = (E[])new Object[arr.length];
// 将原数组的值遍历到新数组中
for(int i = 0; i < arr.length; i++){
value[i] = arr[i];
}
size = arr.length;
}
// 在表尾添加新元素 -- O(n) n:size
public void add(E element) {
// 扩容
if(size == value.length){
resize(value.length + 10);
}
// 在有效位置size-1之后添加
value[size] = element;
size++;
}
// 在指定位置添加新元素 -- O(n) n:有效长度
public void add(int index, E element) {
// index的范围是:[0,size-1]
if(index < 0 || index >= size){
throw new IndexOutOfBoundsException("下标出错!");
}
// 如果容器已满(当有效长度和容器的长度相同时,则满) -- 扩容
if(size == value.length){
resize(value.length + 10);
}
// 从后面移动,腾出目标位置
for(int i = size-1;i >= index;i--){
value[i + 1] = value[i];
}
// 目标位置添加
value[index] = element;
size++;// 有效长度+1
}
// 扩/缩容 -- O(n) n:size
private void resize(int newCapacity){
// 创建新数组
E[] newValue = (E[])(new Object[newCapacity]);
// 将原数组的内容复制到新数组中
for(int i = 0;i < size;i++){
newValue[i] = value[i];
}
// 将新数组赋值给原数组
value = newValue;
}
// 移除指定元素 -- O(n) n:size
public void remove(E element) {
// 先查询目标元素的位置
int index = indexOf(element);
// 下标不符合条件,抛出异常
if(index < 0){
throw new IndexOutOfBoundsException("下标越界!");
}
// 调用remove() 指定位置删除
remove(index);
}
// 在末尾移除一个元素 -- O(n) n:size
public E remove(){
return remove(size - 1);
}
// 移除指定位置元素,并获取旧元素 -- O(n) n:size
public E remove(int index) {
if(index < 0 || index >= size){
throw new IndexOutOfBoundsException("下标越界" + index);
}
E ret = value[index];// 目标元素E
for(int i = index+1;i < size;i++){
value[i-1] = value[i];
}
size--;
// 有效长度是实际容量的1/4,并且容量>默认值
if(size == value.length/4 && value.length > DEFAULT_CAPACITY){
// 缩容
resize(value.length/2);
}
return null;
}
// 获取指定位置元素
public E get(int index) {
if(index < 0 || index > size-1){
throw new IndexOutOfBoundsException("下标越界!");
}
return value[index];
}
// 替换指定位置元素,并获取旧元素 -- O(1)
public E set(int index, E element) {
if(index < 0 || index >= size){
throw new IndexOutOfBoundsException("下标越界!");
}
// 存储原来的值
E ret = value[index];
// 用新值替换旧值
value[index] = element;
return ret;
}
// 获取线性表有效长度
public int size() {
return size;
}
// 数组独占:容量
private int getCapacity(){
return value.length;
}
// 查找元素并获取位置 -- O(n) n:size
public int indexOf(E element) {
int index = -1;// 找不到的时候默认返回-1
for(int i = 0;i < size;i++){
if(value[i].equals(element)){
index = i;
}
}
return index;
}
// 判断是否包含指定元素 -- O(n)
public boolean contains(E element) {
// 找不到返回-1,如果不是-1的话说明元素存在
return indexOf(element) != -1;
}
// 判断是否为空 -- O(1)
public boolean isEmpty() {
// 有效长度为0即为空
return size == 0;
}
// 清空线性表 -- O(1)
public void clear() {
// E[] newValue = (E[]) (new Object[DEFAULT_CAPACITY]);
// value = newValue;
value = (E[]) (new Object[DEFAULT_CAPACITY]);
size = 0;
}
// 根据比较器排序 -- O(log2 n)
public void sort(Comparator<E> c) {
if(c == null){
throw new IllegalArgumentException("参数异常!");
}
int j = 0;
E e = null;
// 插入排序
for(int i = 0;i < size; i++){
e = value[i];
for(j = i;j > 0 && c.compare(value[j-1],e)>0;j--){
value[j] = value[j-1];
}
value[j] = e;
}
}
// 截取新线性表 -- O(n) n:size
public List subList(int startIndex, int endIndex) {
// 开始下标<0,抛出异常
if(startIndex < 0){
throw new IndexOutOfBoundsException("下标越界!");
}
// 末尾下标大于等于有效长度,抛出异常,endIndex最大为size-1
if(endIndex >= size){
throw new IndexOutOfBoundsException("下标越界!");
}
// 开始下标>末尾下标,抛出异常
if(startIndex > endIndex){
throw new IndexOutOfBoundsException("下标越界!");
}
ArrayList<E> es = new ArrayList<>();
for(int i = startIndex;i <= endIndex;i++){
// 往新线性表中添加旧线性表的元素
es.add(value[i]);
}
return es;
}
// 比较两个数组中的元素是否相等
public boolean equals(Object o) {
if(this == o){
return true;
}
// 为空,也返回false
if(o == null){
return false;
}
if(!(o instanceof ArrayList)){
return false;
}
// 比较
ArrayList al = (ArrayList) o;
if(size != al.size){
return false;
}
// 用工具类比较值
return Arrays.equals(value,al.value);
}
// ArrayList 有效个数/容器大小 [x,x,x,x,x] -- O(n) n:size
public String toString() {
StringBuffer sb = new StringBuffer(String.format("ArrayList:%d/%d [",
size,value.length));
if(isEmpty()){
sb.append("]");
}else{
for(int i = 0;i < size;i++){
// 添加元素
sb.append(value[i]);
// 如果不是最后一个元素
if(i != (size-1)){
sb.append(",");
}
// 是最后一个元素
else{
sb.append("]");
}
}
}
// 将sb转化为String 并返回
return sb.toString();
}
/**
* 获取迭代器,创建ArrayListIterator对象
* @return
*/
public Iterator iterator() {
return new ArrayListIterator();
}
// 自定义迭代器
class ArrayListIterator implements Iterator<E> {
private int cur = 0;// 游标
// 是否有下一个元素
public boolean hasNext() {
return cur < size;
}
// 获取下一个元素
public E next() {
return value[cur++];
}
}
}
// 测试类
public class ArrayListTest {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>(10);
// 在表尾添加元素
list.add("Curley");
list.add("Idiot");
list.add("Daisy");
list.add("Sally");
list.add("a");
System.out.println("表尾添加元素:" + list);
// 指定位置添加元素
list.add(1,"str");
System.out.println("指定位置添加元素:" + list);
// 移除指定元素
list.remove("str");
System.out.println("移除指定元素:" + list);
// 在末尾移除一个元素
list.remove();
System.out.println("末尾移除一个元素:" + list);
// 移除指定位置元素
list.remove(3);
System.out.println("移除指定位置元素:" + list);
// 获取指定位置元素
String str = list.get(1);
System.out.println("获取指定位置元素:" + str);
// 替换指定位置元素
list.set(1,"ly");
System.out.println("替换指定位置元素:" + list);
// 获取线性表有效长度
int length = list.size();
System.out.println("线性表有效长度:" + length);
// 查找元素并获取位置
int i = list.indexOf("Curley");
System.out.println("查找指定元素并获取位置:" + i);
// 判断是否包含指定元素
boolean flag = list.contains("Idiot");
System.out.println("是否包含元素:" + flag);
// 根据比较器排序
list.sort(new Comparator<String>() {
public int compare(String o1, String o2) {
return o1.compareTo(o2);
}
});
System.out.println("排序后:" + list);
// toString()
System.out.println("toString():" + list.toString());
// 迭代
Iterator it = list.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
list.subList(0,2);
System.out.println(list);
// 清空
list.clear();
System.out.println("清空:" + list);
}
}