集合类的由来:
对象用于封装特有数据,对象多了需要存储,如果对象的个数不确定,就使用集合容器进行存储。
集合的特点:
长度可以发生改变。
只能存储对象。
集合中不可以存储基本数据类型值。
可以存储多种类型对象(一般存储的还是同一种,因为1.5JDK的新特性 泛型)。
集合和数组的区别:
1)长度问题
数组固定。
集合可变。
2)存储元素问题
数组可以是基本类型,也可以是引用类型。
集合只能是引用类型。(JDK1.5以后还可以存储基本数据类型,因为JDK1.5自动装箱拆箱)
3)是否同一类型
数组元素类型一致。
集合元素类型可以不一致。(建议还是同一种类型,因为JDK1.5出现了泛型)
4)功能是否一致
数组只能对数据进行存取操作,当然数组中的元素还可以删除
集合不但可以对数据进行基本操作,还提供了更强大的功能,比如删除修改...。
集合体系的由来
集合是存储多个元素的容器,但是,由于数据结构不同,Java就提供了多种集合类。
而这多种集合类有共性的功能,所以,通过不断的向上抽取,最终形成了集合体系
结构。
为什么会出现这么多的容器呢?
因为每一个容器对数据的存储方式都有不同,这个存储方式称之为:数据结构。
数据结构:数据存储的方式。
如何学习和使用一个继承体系呢?
学习顶层:因为顶层定义的是共性内容。
使用底层:因为底层才是具体的实现。
简单一句话:参阅顶层内容,建立底层对象。
Collection:定义了集合框架的共性功能。
|---List(列表):元素是有序的,元素可以重复,因为该集合体系有索引。
|---ArrayList:底层是数组数据结构,查询速度很快,但是增删稍慢,线程不同步,默认10个元素。(线程不同步)
|---LinkedList:底层是链表数据结构,查询很慢,增删速度很快。(线程不同步)
|---Vector:底层是数组数据结构,和ArrayList一样,查询,增删,都很慢,Vector是1.0出现,ArrayList是1.2出现,(线程同步)但已经不用了。
|---Set(集):元素是无序的(存入和取出顺序不一定一致),元素不可以重复。
|---HashSet:底层数据结构是哈希表。线程是不同步的。
采用散列函数对元素进行排序(Asiic),是专门为快速查询而设计的。存入HashSet的对象必须定义hashCode方法。
|---LinkedHashSet:有序。内部使用散列以加快查询速度,同时使用链表维护元素插入的次序,在使用迭代器遍历Set时,结果会按元素插入的次序显示。
|---TreeSet:底层的数据结构是二叉树。线程是不同步的。对Set集合中的元素的进行指定(我们指定的比较器)顺序的排序。不同步。TreeSet底层的数据结构就是二叉树。
采用红黑树的数据结构进行排序元素,使用它可以从Set中提取有序(升序或者降序)的序列。需要注意的是,存入自定义类时,TreeSet需要维护元素的存储顺序,因此自定义类要实现Comparable接口并定义compareTo方法。
注意:集合只能保存引用数据类型,也就是存储的是对象的地址值,而不是对象本身。集合中的元素相当于引用类型变量。
注意:如果使用的集合涉及到了频繁的插入,建议使用LinkedList。
Collection
布尔型 | ||
布尔型 | addAll(Collection<? extendsE> c) | |
无返回值 | clear() | |
布尔型 | ||
布尔型 | containsAll(Collection<?> c) | |
布尔型 | equals(Object o) | |
整数 | hashCode() | |
布尔型 | isEmpty() | |
迭代器 | iterator() | |
布尔型 | remove(Object o) | |
布尔型 | removeAll(Collection<?> c) | |
布尔型 | retainAll(Collection<?> c) | |
整数 | size() | |
对象[] | toArray() | |
| toArray(T[] a) |
ArrayList特有方法:既然是对数据进行操作的,当然就有 增、删、改、查这四个方法。
无返回值 | add(int index,E element) |
布尔型 | addAll(Collection<? extendsE> c) |
布尔值 | addAll(int index,Collection<? extendsE> c) |
get(int index) | |
整数 | indexOf(Object o) |
整数 | lastIndexOf(Object o) |
代码示例:
import java.util.List;
import java.util.ArrayList;
public class Test{
public static void main(String[] args){
ArrayList al = new ArrayList();
al.add("黑马程序员——Java01");//添加了一个元素
al.add("黑马程序员——Java02");
al.add("黑马程序员——Java03");
al.add("黑马程序员——Java04");
sop(al.get(1));
al.remove("黑马程序员——Java04");//删除一个元素
sop(al.size());//打印下集合的长度 结果为3.因为删了一个
al.clear();//清空集合
sop(al.contains("黑马程序员——Java03"));
sop(al.isEmpty());
method();
}
public static void method(){
List list1 = new ArrayList();
list1.add("黑马程序员——Java01");
list1.add("黑马程序员——Java02");
list1.add("黑马程序员——Java03");
list1.add("黑马程序员——Java04");
List list2 = new ArrayList();
list2.add("黑马程序员——Java01");
list2.add("黑马程序员——Java02");
list2.add("黑马程序员——Java05");
list2.add("黑马程序员——Java06");
//list1.retainAll(list2);//取交集。拿list1元素跟list2的元素比,如果相同就保留。调用父类的方法
//sop(list1);
list1.removeAll(list2);
//删除交集。拿list1的元素跟list2的元素比,如果相同就删除。调用父类的方法
sop(list1);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
集合注意:
1、直接存储基本类型值也是可以的,因为JDK1.5后,有自动装箱技术,会将基本数据类转换成数据对象。
2、集合对象中存储的其实都是元素对象的引用。
3、add方法的参数是Object类型,可以接受所有类型的对象。但会出现向上转型,取出元素时的类型还是Object,不能使用具体对象的特有内容,想要使用特有内容,必须向下转型。集合框架中存放的都是对象的地址。当我们想用对象的特有方法的时候必须向下转型。
当我们想直接打印一个集合,其实是调用了这个对象的toString方法,当我们要打印一个对象的长度的时候,首先我们会想到length方法。但是由于我们添加数据的时候用的add方法,而add方法的参数类型是Object,也就说把存进去的数据向上转型了。但是我们都知道Object是没有length方法,此时无法使用length方法。那么就要向下转型才可以,只有使用子类的特有方法size。
迭代器(Iterator)
1、什么是迭代器?其实就是集合取出元素的方式。
就把取出方式定义在集合的内部,这样取出方式就可以直接访问结合内容的元素。那么取出方式就定义成了内部类。
而每一个容器的数据结构不同,所以取出的动作细节也不一样,但是都有共性内容:取出。那么可以写共性取出。
那么这些内部类都符合一个规则。该规则是Iterator。
迭代时注意:在迭代时候,不可以通过集合对象的方法操作集合中的元素,因为会发生 ConcurrenModificationException异常。所以在迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的,只能对元素进行判断,取出,删除的操作
如果想要其他的操作,如添加、修改等,就需要使用其子接口,ListIterator。
如何获取集合的取出对象呢?
通过一个对外提供的方法:iterator()
Iterator布尔型 | hasNext() |
E | next() |
无返回值 | remove() 从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。 |
迭代器的使用
1.使用步骤
1)通过集合对象获取迭代器对象。
2)通过迭代器对象判断。
3)通过迭代器对象获取。
2.迭代器原理
由于多种集合的数据结构不同,所以存储方式不同,所以,取出方式也不同。这个时候,我们就把判断和获取功能定义在了一个接口中,将来,遍历哪种集合的时候,只要该集合内部实现这个接口即可。
3.集合的常见使用步骤
1)创建集合对象。
2)创建元素对象。
3)把元素添加到集合中。
4)遍历集合。
1.通过集合对象获取迭代器对象。
2.通过迭代器对象判断。
3.通过迭代器对象获取。
4.Collection存储字符串和自定义对象并遍历。
//存储字符串代码示例:
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest1{
public static void main(String[] args){
ArrayList al = new ArrayList();
al.add("黑马程序员——Java01");
al.add("黑马程序员——Java02");
al.add("黑马程序员——Java03");
al.add("黑马程序员——Java04");
for(Iterator iter = al.iterator();iter.hasNext();){
sop(iter.next());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
//存储自定义对象代码示例:
import java.util.List;
import java.util.ArrayList;
import java.util.Iterator;
class Student{
private String name;
privateint age;
Student(String name,int age){
this.name=name;
this.age=age;
}
public String toString(){
return "姓名:"+name+"...年龄:"+age;
}
}
public class ArrayListTest2{
public static void main(String[] args){
List list = new ArrayList();
list.add(new Student("黑马程序员——张三",23));
list.add(new Student("黑马程序员——李四",24));
list.add(new Student("黑马程序员——王五",25));
list.add(new Student("黑马程序员——赵六",26));
for(Iterator iter = list.iterator();iter.hasNext();){
sop(iter.next());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
由于Iterator迭代器对数据的操作功能太少,只有对数据进行获取和删除等功能,所以就有了ListIterator迭代器。
ListIterator迭代器不仅可以对迭代器进行获取和删除,还可以对迭代器进行添加和修改。
ListIterator
无返回值 | add(E e) |
布尔型 | hasNext() |
布尔型 | hasPrevious() |
E | next() |
整数 | nextIndex() |
E | previous() |
整数 | previousIndex() |
无返回值 | remove() |
无返回值 | set(E e) |
List集合的遍历方式有俩种:一种是Iterator 一种是ListIterator
ListIterator代码示例:
import java.util.List;
import java.util.ArrayList;
import java.util.ListIterator;
public class ListIteratorTest{
public static void main(String[] args){
List list = new ArrayList();
list.add("黑马程序员——Java01");
list.add("黑马程序员——Java02");
list.add("黑马程序员——Java03");
list.add("黑马程序员——Java04");
for(ListIterator listIter = list.listIterator();listIter.hasNext();){
String name = (String)listIter.next();
sop(name);
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
ListIterator迭代器
是Iterator的子接口。有自己的特有功能,可以逆向遍历数据,但是需要先正向遍历。一般不用。
面试题:并发修改异常
并发修改异常的产生原因:用迭代器遍历集合,用集合去操作集合。
解决方案:使用集合操作。使用列表迭代器操作。
数据结构:栈,队列,数组,链表。
栈:先进后出。 如同一个杯子
队列:先进先出。如同一个水管
数组:查询快,增删慢。
链表:查询慢,增删快。
LinkedList特有方法:
无返回值 | addFirst(E e) |
无返回值 | addLast(E e) |
E | element() |
E | getFirst() |
E | getLast() |
布尔型 | offerFirst(E e) |
布尔型 | offerLast(E e) |
E | removeLast() |
E | removeLast() |
1.6出现了替换方法
布尔型 | offer(E e) |
布尔型 | offerFirst(E e) |
布尔型 | offerLast(E e) |
E | peek() |
E | peekFirst() |
E | peekLast() |
E | poll() |
E | pollFirst() |
E | pollLast() |
集合框架(LinkedList练习)
/*
使用LinkedFirst模拟一个堆栈或者队列数据结构
堆栈:先进后出 如同一个罐子
队列:先进先出 如同一个水管
*/
import java.util.LinkedList;
class Duilie{
private LinkedList link;
Duilie(){
link = new LinkedList();
}
public void myAdd(Object obj){
link.addFirst(obj);
}
public Object myGet(){
return link.removeLast();
}
public boolean isNull(){
return link.isEmpty();
}
}
public class DuilieTest{
public static void main(String args[]){
Duilie dl = new Duilie();
dl.myAdd("Java01");
dl.myAdd("Java02");
dl.myAdd("Java03");
dl.myAdd("Java04");
while(!dl.isNull()){
System.out.println(dl.myGet());
}
}
}
集合框架(ArrayList练习)
/*
去除ArrayList集合的重复元素。
*/
import java.util.ArrayList;
import java.util.Iterator;
public class ArrayListTest1{
public static void main(String args[]){
ArrayList al = new ArrayList();
al.add("Java01");
al.add("Java02");
al.add("Java03");
al.add("Java02");
al.add("Java04");
al = singleElement(al);
System.out.println(al);
}
public static ArrayList singleElement(ArrayList al){
ArrayList newAl = new ArrayList();
for(Iterator it = al.iterator();it.hasNext();){
Object obj = it.next();
if(!newAl.contains(obj)){//如果是同一个元素,那么就不存入。
new Al.add(obj);
}
}
return new Al;
}
}
集合框架(ArrayList练习2)
/*
将自定义对象作为元素存到ArrayList集合中,并去除重复元素
比如,存人对象,视为同一个人,为重复元素。
思路:
1、对人描述,将数据封装进人对象
2、定义容器,将人进行存入
3、取出
List集合判断是否包含其实是根据这个对象判断是否和内部的对象, equals,可以复写这个equals,写自己的判断
当List remove 删除时候,也是i先equals判断有没有,如果所以要注意
*/
import java.util.ArrayList;
import java.util.Iterator;
class Person{
private String name;
private int age;
Person(String name,int age){
this.name = name;
this.age = age;
}
public boolean equals(Object obj){
if(!(obj instanceof Person))
return false;
Person p = (Person)obj;
return name.equals(p.name) && this.age==p.age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
public class ArrayListTest2{
public static void main(String args[]){
ArrayList al = new ArrayList();
al.add(new Person("list01",31));
al.add(new Person("list02",32));
al.add(new Person("list02",32));
al.add(new Person("list03",33));
al.add(new Person("list04",34));
al.add(new Person("list04",34));
al.add(new Person("list05",35));
al = singleElement(al);
for(Iterator it = al.iterator();it.hasNext();){
Person p = (Person)it.next();
sop(p.getName()+":"+p.getAge());
}
}
public static void sop(Object obj){
System.out.println(obj.toString());
}
public static ArrayList singleElement(ArrayList al){
ArrayList newAl = new ArrayList();
for(Iterator it = al.iterator();it.hasNext();){
Object obj = it.next();
if(!newAl.contains(obj)){
new Al.add(obj);
}
}
return new Al;
}
}
集合框架(Vector中的枚举)
迭代器 | elements() |
import java.util.Vector;
import java.util.Enumeration;
public class Test{
public static void main(String[] args){
Vector v = new Vector();
v.add("Java01");
v.add("Java02");
v.add("Java03");
v.add("Java04");
for(Enumeration en = v.elements();en.hasMoreElements();){
sop(en.nextElement());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
枚举就是Vector特有的取出方式
发现枚举和迭代器很像。
其实枚举和迭代器是一样的。
因为枚举的名称以及方法的名称都过长。所以被迭代器取代了。
Vector和ArrayList在使用上非常相似,都可用来表示一组数量可变的对象应用的集合,并且可以随机地访问其中的元素。
Vector的方法都是同步的(Synchronized),是线程安全的,而ArrayList的方法不是,由于线程的同步必然要影响性能,因此,ArrayList的性能比Vector好。(建议使用ArrayList,因为高效,就算是多线程咱们也不用怕,因为可以自己加锁)
当Vector或ArrayList中的元素超过它的初始大小时,Vector会将它的容量翻倍,而ArrayList只增加50%的大小,这样,ArrayList就有利于节约内存空间。
Set :元素是无序的(存入和取出顺序不一定一致),元素不可以重复。
boolean | add(E e) | |
boolean | addAll(Collection<? extendsE> c) | |
void | clear() | |
boolean | contains(Object o) | |
boolean | containsAll(Collection<?> c) | |
boolean | equals(Object o) | |
int | hashCode() | |
boolean | isEmpty() | |
Iterator<E> | iterator() | |
boolean | remove(Object o) | |
boolean | removeAll(Collection<?> c) | |
boolean | retainAll(Collection<?> c) | |
int | size() | |
Object[] | toArray() | |
| toArray(T[] a) |
HashSet 底层数据结构是哈希表。
布尔型 | |
无返回值 | clear() |
布尔型 | contains(Object o) |
布尔型 | isEmpty() |
迭代器 | iterator() |
布尔型 | remove(Object o) |
整数 | size() |
HashSet是如何保证元素唯一性的呢?
是通过两个方法,hashCode和equals来完成。
如果元素hashCode值相同,才会判断equals是否为true。
如果元素的hashCode不同,不会调用equals方法。
怎么重写hashCode()和equals()方法呢?
hashCode():把对象的所有成员变量值相加即可。
如果是基本数据类型,就加值。如果是引用类型,就加哈希值。return name.hasCode()+ age * 27;equals(obj):先判断是否是同一类型的对象,再把传递进来的对象进行向下转型。再判断对象的内容是否相同。if(!(obj instanceofStudent)) ;
Student stu = (Student)obj;
return this.name.equals(stu.name) && this.age== stu.age;
所有成员变量的值比较。基本类型用==,引用类型用equals()。
注意:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashCode和equals方法。
举例:
public int hashCode(){
return name.hashCode()+age*21;
}
public boolean equals(Object obj){
if(!obj instanceof Person)
return false;
Person p=(Person)obj;
return name.equals(p.name) && age==p.age;
}
TreeSet :底层的数据结构是二叉树。线程是不同步的。
比较器 | comparator() |
存储字符串对象代码示例:
import java.util.TreeSet;
import java.util.Iterator;
public class Test{
public static void main(String args[]){
TreeSet ts =new TreeSet();
ts.add("Java01");
ts.add("Java03");
ts.add("Java02");
ts.add("Java04");
for(Iterator it = ts.iterator();it.hasNext();){
sop(it.next());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
TreeSet集合两种实现排序方式:
自然排序(元素具备比较性)
TreeSet的无参构造,要求对象所属的类实现Comparable接口。
比较器排序(集合具备比较性)
TreeSet的带参构造,要求构造方法接收一个实现了Comparator接口的对象。
Comparable
整数 | compareTo(T o) |
Comparator
整数 | |
布尔值 |
Comparable存储自定义对象代码示例:
/*
需求:往 TreeSet 集合中存储自定义对象学生。
想按照学生的年龄进行排序。
*/
import java.util.Iterator;
import java.util.TreeSet;
class Student implements Comparable{
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
public int compareTo(Object obj){
if(!(obj instanceof Student)){
throw new RuntimeException("不是学生对象");
}
Student s = (Student)obj;
int num = this.age-s.age;
if(num==0)
return this.name.compareTo(s.name);
else
return num;
}
public String toString(){
return name +"..."+age;
}
}
public class TreeTest1{
public static void main(String[] args){
TreeSet ts =new TreeSet();
ts.add(new Student("黑马程序员——张三",21));
ts.add(new Student("黑马程序员——王五",23));
ts.add(new Student("黑马程序员——周七",19));
ts.add(new Student("黑马程序员——赵六",18));
for(Iterator iter = ts.iterator();iter.hasNext();){
sop(iter.next());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
Comparator存储自定义对象代码示例:
import java.util.Iterator;
import java.util.TreeSet;
import java.util.Comparator;
class Student{
private String name;
private int age;
Student(String name,int age){
this.name=name;
this.age=age;
}
public String getName(){
return name;
}
public int getAge(){
return age;
}
}
class MyCompare implements Comparator{
public int compare(Object obj1,Object obj2){
Student s1 = (Student)obj1;Student s2 = (Student)obj2;
int num =new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));
if(num==0)
return s1.getName().compareTo(s2.getName());
return num;
}
}
public class TreeSetTest3{
public static void main(String[] args){
TreeSet ts = new TreeSet(new MyCompare());
ts.add(new Student("黑马程序员——张三",21));
ts.add(new Student("黑马程序员——王五",23));
ts.add(new Student("黑马程序员——周七",19));
ts.add(new Student("黑马程序员——赵六",18));
for(Iterator iter = ts.iterator();iter.hasNext();){
Student stu = (Student)iter.next();
sop(stu.getName()+"..."+stu.getAge());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
注意:如果同时有两种方案,以谁为主呢?以比较器为主。
集合框架(TreeSet练习)
/*
练习,按照字符串长度排序
字符串本身具备比较器,但是他的比较方式不是所需要的
这时就只能使用比较器。也可以不定义类,写匿名内部类也可以。
*/
import java.util.TreeSet;
import java.util.Iterator;
import java.util.Comparator;
public class TreeSetTest4{
public static void main(String args[]){
TreeSet ts =new TreeSet(new Comparator(){
public int compare(Object obj1,Object obj2){
String s1 = (String)obj1;
String s2 = (String)obj2;
int num = s1.length()-s2.length();
if(num==0)
return s1.compareTo(s2);
return num;
}
});
ts.add("黑马");
ts.add("csdn");
ts.add("黑马论坛");
ts.add("云计算");
for(Iterator it = ts.iterator();it.hasNext();){
sop(it.next());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
集合框架(泛型概述)
/*
泛型:JDK1.5 以后出现的新特性,用于解决安全问题,是一个安全机制。
好处:
1、将运行时期出现的问题(classCastException),转移到了编译时期。
方便于程序员解决问题。让运行时期问题减少,安全。
2、避免了强制转换的麻烦。
泛型格式:通过 <> 来定义要操作的引用数据类型。
什么时候使用泛型呢?
通常在集合框架中很常见。
只要见到<>就要定义泛型
其实<>就是用来接收类型的。
当使用集合时,将集合中要存储的数据类型作为参数传递到尖括号中即可,和函数传参数一样。
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
public class Test{
public static void main(String args[]){
List<Integer> al = new ArrayList<Integer>();
al.add(4);//自动装箱功能,现在作为了解。以后会学到的,包括泛型。
al.add(new Integer(4));
int x=5;
al.add(x);
for(Iterator<Integer> it = al.iterator();it.hasNext();){
sop(it.next());
}
}
public static void sop(Object obj){
System.out.println(obj);
}
}
集合框架(泛型类)
/*
泛型类
舍呢么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候
早起定义Object 来完成扩展
现在,定义泛型来完成扩展。
*/
//JDK1.5之前的做法
class Tool{
private Object obj;
public void setObject(Object obj){
this.obj=obj;
}
public Object getObject(){
return obj;
}
}
//JDK1.5泛型出现后,用泛型的做法
//泛型类
class Utils<E>{
private E o;
public void setObject(E o){
this.o = o;
}
public E getObject(){
return o;
}
}
class Worker{
}
class Student{
}
public class Test{
public static void main(String args[]){
//JDK1.4做法。
Tool t = new Tool();
//可以传入Student
t.setObject(new Student());
Object obj = t.getObject();
Student stu = (Student)obj;
//泛型出现以后的做法
Utils<Worker> u = new Utils<Worker>();
u.setObject(new Worker());
Worker w = u.getObject();
}
public static void sop(Object obj){
System.out.println(obj);
}
}
泛型可以让程序员避免强制转换的麻烦,并且把运行时强转问题转化到了编译时期。
集合框架(泛型方法)
/*
泛型类定义的泛型,在整个类中有效,如果被方法是用到泛型,类的对象明确。操作的具体类型后,所有要操作的类型就已经固定了。为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上,而不定义在类上。
public <T> void show(T t){
}
*/
//类型已经确定.
class GenericTest<T>{
public void show(T t){
sop("show:"+t);
}
public void print(T t){
sop("print:"+t);
}
public static void sop(Objectobj){
System.out.println(obj);
}
}
//类型不确定,使用泛型方法
class GenericTest2{
//泛型方法
public <Q>void show(Q q){
sop("show_2:"+q);
}
public <Q> void print(Q q){
sop("print_2:"+q);
}
public static void sop(Object obj){
System.out.println(obj);
}
}
public class GenericTest3{
public static void main(String args[]){
//泛型确定
GenericTest<String> d = new GenericTest<String>();
d.show("黑马程序员");
d.print("csdn社区");
//泛型不确定
GenericTest2 d2 = newGenericDemo_2();
d2.show("黑马程序员");
d2.print(new Integer(4));
d2.print(4);
}
public static void sop(Objectobj){
System.out.println(obj);
}
}
集合框架(静态方法泛型)
泛型类中也可以定义泛型方法
特殊之处:静态方法不可以访问类上定义的泛型,因为只有在实例化的时候,才会使用泛型
如果静态方法操作的引用数据类型不确定,可以将泛型定义在方法上。
<T> 泛型写在返回值前。
/*
public static <T> void setName(T t){
}
*/
集合框架(泛型接口)
interface Inter<T>{
void show(T t);
}
class InterImpl implementsInter<String>{
void show(Stringt)//这里只能是 String{
}
}
class InterImpl2<T> implementsInter<T>{
void show(T t);//这里类型不固定{
}
}
集合框架(泛型通配符)
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
public class GenericTest5{
public static void main(String args[]){
List<String> al = new ArrayList<String>();
al.add("黑马程序员");
al.add("CSDN社区");
al.add("黑马程序员论坛");
List<Integer> al1 = new ArrayList<Integer>();
al1.add(1);
al1.add(2);
al1.add(3);
printCollection(al);
printCollection(al1);
}
public static void printCollection(List<?> al){
for(Iterator<?> it = al.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
集合框架(泛型限定(上限))
/*
? 通配符
? extends E:可以接收 E 类型或者 E 的子类型。上限。
? superE:可以接收E类型或者E的父类型,下限
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
class Person{
private String name;
Person(String name){
this.name = name;
}
public String getName(){
return name;
}
}
class Student extends Person{
Student(String name){
super(name);
}
}
public class GenericTest9{
public static void main(String args[]){
List<Person> al =new ArrayList<Person>();
al.add(new Person("张三"));
al.add(new Person("李四"));
al.add(new Person("王五"));
List<Student> al1 = new ArrayList<Student>();
al1.add(new Student("赵六"));
al1.add(new Student("周七"));
al1.add(new Student("郑八"));
printCollection(al);
printCollection(al1);
}
//printCollection(al1);这是错误的,不能直接写
//public static voidprintCollection(ArrayList<Person> al)这样只能接受person
public static void printCollection(List<? extends Person> al){/*这样可以接收Person和Person的子类为了面向接口编程,而且上面定义的容器也是面向接口编程,这里写成List,否则编译不通过。因为ArrayList子类不能接收List父类。*/
for(Iterator<? extends Person> it = al.iterator();it.hasNext();){
System.out.println(it.next().getName());
}
}
}
集合框架(泛型限定(下限))
/*
? 通配符
? extends E:可以接收 E 类型或者 E 的子类型。上限。
? super E: 可以接收E类型或者E的父类型,下限
*/
import java.util.ArrayList;
import java.util.List;
import java.util.Iterator;
class Person{
private String name;
Person(String name){
this.name = name;
}
public String toString(){
return name;
}
}
class Student extends Person{
Student(String name){
super(name);
}
}
public class GenericTest10{
public static void main(String args[]){
List<Person> al =new ArrayList<Person>();
al.add(new Person("张三"));
al.add(new Person("李四"));
al.add(new Person("王五"));
List<Student> al1 = new ArrayList<Student>();
al1.add(new Student("赵六"));
al1.add(new Student("周七"));
al1.add(new Student("郑八"));
printCollection(al);
printCollection(al1);
}
public static void printCollection(List<? super Student> al){
for(Iterator<? super Student> it = al.iterator();it.hasNext();){
System.out.println(it.next());
}
}
}
使用泛型的限制:
什么时候定义泛型类?
当类中要操作的引用数据类型不确定的时候,
早期定义的Object来完成扩展。现在定义泛型类来完成扩展
泛型类定义的泛型,在整个类中有效。如果被方法使用,
那么泛型类的对象明确要操作的具体类型后,所有要操作的类型就已经固定了。
为了让相同方法可以操作不同类型,而且类型还不确定。
那么可以将泛型定义在方法上。
特殊之处:
静态方法不可以访问类上定义的泛型。因为只有在实例化的时候,才会使用泛型。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。
? 通配符。也可以理解为占位符。
泛型的限定:
?extends E: 可以接收E类型或者E的子类型。上限。
? super E: 可以接收E类型或者E的父类型。下限