数据多了用对象存,对象多了用集合存,常用的两种存对象的容器是数组和集合,数组和集合类容器的不同:
1,数组虽然也可以存储对象,但长度是固定的,集合长度是可变的;
2,数组中可以存储基本数据类型,集合中只能存储对象。
3,数组只能储存单一类型的对象,集合可以则不同。
二,集合框架的形成与分类( Collection接口)
1,List:元素是有序的(怎么存进去的怎么取出来),元素可以重复,因为该集合体系有索引
1.1 ArrayList:(线程不同步)底层的数据结构使用的是数组结构。特点:查询速度很快,但是增删稍慢
1.2 LinkedList:底层使用的是链表数据结构。特点:查询很慢,增删速度非常的快
1.3 Vector:(线程同步)底层是数组数据结构。ArrayList效率比它快,Vector查询慢,增删也慢,一般不用Vector
2,Set:元素是无序(存入和取出的顺序不一定一致),元素不可以重复
2.1 HashSet:(线程不同步)底层数据结构是hashtable(哈希表)。
HashSet是如何保证元素的唯一性呢?
Answer:通过元素的两个方法,hashCode和equals来完成,如果元素的hashcode值相同才会调用equals是否为true,如果元素的Hashcode值不同,就直接在该Hashcode对应的物理地址上分配空间存储对象。
PS:对于判断元素是否存在,以及删除等操作,依赖的方法是元素的hashcode和equals方法
2.2 TreeSet:可以对Set集合中的元素进行排序。
底层数据结构是二叉树,保证元素的唯一性的依据:compareTo方法return 0,就不唯一了;
TreeSet排序的第一种方式:让元素自身具备比较性,元素需要实现Comparable接口,覆盖compareTo方法也称这种方式为元素的自然顺序,或者叫做默认顺序。
TreeSet的第二种排序方式:当元素自身不具备比较性时,或者具备的比较性不是所需要的,这时就需要让集合自身具备比较性。在集合一初始化时,就有了比较方式,通过构造函数就能够实现
两种排序方式(简述):
(1),元素自身具备比较性(实现comparable接口,实现compareTo方法);
(2),当初始化集合的时候,传入一个比较器,这个比较器需要自定义一个类实现Comparator接口中的compare方法。
(1),元素自身具备比较性(实现comparable接口,实现compareTo方法);
(2),当初始化集合的时候,传入一个比较器,这个比较器需要自定义一个类实现Comparator接口中的compare方法。
当两种排序方式都存在时,选取构造函数中的比较器更好,因为它初始化集合时就存在了,当Comparator比较器不符合要求,还可用Comparable接口中的方法。
PS:Set集合的功能和Collection是一致的。
3,集合框架的构成及分类图形结构如下
4,为什么会出现这么多集合框架呢?
如上图,这些存储方式都具备了一些相同的操作,将这些操作提取共同的部分,形成最父类的接口,子类只需继承父类并按照各自的操作方式实现父类的方法就行了。每一个容器对数据的存储方式称之为数据结构。
三,集合框架中的共性方法
1,增删和获取操作
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_1()
{
//创建一个集合容器,使用Collection接口的子类List接口中的已知实现子类ArrayList
ArrayList<String> al=new ArrayList<String>();
//1,添加元素
al.add("java-01");
al.add("java-02");
al.add("java-03");
al.add("java-04");
//输出原集合
sop(al);
//2,删除元素
al.remove("java-02");
//3,获取个数,集合长度
sop(al.size());
//4,判断元素
sop("al.contains('java-01') "+al.contains("java-01"));
//清空集合中的所有元素
al.clear();
/*Iterator<String> iterator=al.iterator();
while(iterator.hasNext())
{
sop(iterator.next(););
}*/
sop(al);//输出改变后的集合
sop(al.isEmpty());//判断集合是否为空
}</span></span>
2,判断操作(containsAll,removeAll,retainAll)
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_2()
{
ArrayList<String> arr=new ArrayList<String>();
arr.add("java-01");
arr.add("java-02");
arr.add("java-03");
arr.add("java-04");
ArrayList<String> arr2=new ArrayList<String>();
arr2.add("java-03");
arr2.add("java-05");
arr2.add("java-06");
arr2.add("java-04");
sop(arr.containsAll(arr2));//判断arr中是否包含arr2中的所有元素,返回值是boolean类型
sop(arr);
sop(arr.retainAll(arr2));//取交集,all中只会保留和all2相同的元素
sop(arr);
arr.removeAll(arr2);//删除arr中与arr2中相同的元素,返回值是boolean
sop(arr);
}</span></span>
3,迭代器
3.1 什么是迭代器?(形象的比喻:电玩城里面的投币夹小娃娃的游戏机,箱子相当于容器,夹子就是迭代器)
其实就是集合取出元素的方式,因为每个集合都有一种取出的方式,而实现取出这种功能不是一两个方法就能搞定的,因此将取出这种功能封装成一个对象,每一个集合里面都封装了一个取出自身元素的对象,而取出的方式因为每个对象而发生改变。将取出的类叫做迭代器,迭代器定义在集合的内部,因为迭代器要操作的是集合内部的数据,因此将迭代器这个接口定义在集合的内部,用内部类实现,这样就可以直接访问集合内部的元素,那么取出的方式就被定义成了内部类,而每一个容器的数据结构也不同,所以取出的动作和细节也不一样,但是都是共性内容(判断和取出),那么就可以进行共抽取,形成一个迭代器的接口,定义集合时只需在内部实现这个接口就Ok 了。
3.2 这些内部类都符合一个规则,该规则是Iterator,如何获取集合的取出对象呢?
通过一个对外提供的方法,iterator()方法。
使用方法类似于下例:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_get()//取出
{
ArrayList arr=new ArrayList();
arr.add("java-01");
arr.add("java-02");
arr.add("java-03");
arr.add("java-04");
Iterator it=arr.iterator();//获取迭代器,用于取出集合中的元素
while(it.hasNext()){
sop(it.next());
}
//这种方式更节约内存,It用完之后就释放了
for(Iterator It=arr.iterator();It.hasNext();){
sop(It.next());
}
}</span></span>
四,List体系特有的方法(凡是能够操作角标的方法都是该体系特有的方法)
1, 增
add(int index,Object element);在指定索引位置添加元素
addAll(int index,Collection col) ;将col集合中所有值添加到当前对象中
2, 删
remove(int index);移除索引位置为index的元素
removeAll(Collection col);移除该对象中和col集合中相同的元素
3, 改
set(int index,Object element);修改索引为index的值为element
4,查
get(int index);获取索引位置为index的元素值
subList(int start,int end);
listIterator();List集合特有的迭代器,ListIterator是Iterator的子接口
PS:在迭代时,不可以通过集合对象的方法操作集合中的元素,因为会发生ConcurrentModificationException异常,所以,在使用迭代器时,只能用迭代器的方法操作元素,可是Iterator方法是有限的只能对元素进行判断,取出,删除的操作,如果想要其他的操作如添加,修改等,就需要使用其子接口,listIterator来实现,这个是List中特有的迭代器, 该接口只能通过List集合的对象调用lsitIterator方法获取 。
5.Vetctor特有的枚举法遍历集合
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class VectorDemo {
public static void main(String args[])
{
Vector v=new Vector();
v.add("Java-1");
v.add("Java-2");
v.add("Java-3");
v.add("Java-4");
v.elementAt(0);
//用枚举的方式获取所有元素
Enumeration en=v.elements();
while(en.hasMoreElements())
{
System.out.println(en.nextElement());
}
//迭代器
Iterator it=v.iterator();
while(it.hasNext())
{
System.out.println(it.next());
}
}
}</span></span>
分析:Vector中带elements的方法都是它的特有方法,他是容器的始祖,后被ArrayList代替了,枚举就是Vector特有的取出方式,同时它也具备迭代器和遍历的方式。 发现枚举和迭代器很像,其实枚举和迭代器是一样的,因为枚举的名称和方法的名称都过长,所以被迭代器取代了。
6,LinkedList中特有的方法
addFirst();
addLast();
getFirst();
getLast();获取元素但不删除元素
removeFirst(); 从1.6版本开始使用pollFirst()更好,当集合中没有元素时,会出现NoSuchElementsException,
而pollFirst()不用抛出异常,返回null
removeLast();获取元素的同时删除元素
pollFirst();
pollLast();获取元素的同时删除元素
peekFirst();
peekLast();获取值不删除元素
offerFirst():添加元素
offerLast()
下面这个类是对以上方法的使用:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class LinkedListDemo {
public static void main(String args[])
{
LinkedList link=new LinkedList();
link.add("java-5");
link.add("Java-1");
link.add("Java-2");
link.add("Java-3");
link.add("Java-4");
link.addFirst("Java-0");
link.addLast("Java-6");
sop(link.getFirst());
sop(link.getLast());
sop(link.size());
sop(link.removeFirst());
sop(link);
Iterator it=link.iterator();
while(it.hasNext())
{
sop(it.next());
}
//获取所有元素的另一种方法
while(!link.isEmpty())
{
sop(link.removeFirst());//如果Link为空,会出现不存在该元素异常
}
}
private static void sop(Object obj) {
System.out.println(obj);
}
}</span></span>
五,List练习
1,LinkedList练习
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/* 需求:使用LinkedList模拟一个堆栈或者队列数据结构
堆栈:先进后出,如同一个杯子
队列:先进先出First in First out FIFO 如同一个水管
*/
import java.util.*;
//将链表封装
class Queue<E>
{
private LinkedList<E> link=null;
Queue()
{
this.link=new LinkedList<E>();
}
public void myAdd(E e)
{
link.add(e);
}
public E myGet()
{
return link.removeLast();//先进后出,堆栈
//return link.removeFirst();先进先出,队列
}
public boolean isNull()
{
return link.isEmpty();
}
}
public class LinkedListTest {
public static void main(String args[])
{
Queue<String> que=new Queue<String>();
que.myAdd("java-1");
que.myAdd("jav-2");
que.myAdd("java-3");
que.myAdd("java-4");
while(!que.isNull())
{
sop(que.myGet());
}
}
private static void sop(Object obj) {
System.out.println(obj);
}
}</span></span>
2,ArrayList练习
例子一:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
需求:去除ArrayList集合中的重复元素
*/
import java.util.*;
public class ArrayListTest {
public static void main(String args[])
{
ArrayList arr=new ArrayList();
arr.add("1");
arr.add("2");
arr.add("1");
arr.add("2");
arr.add("1");
arr.add("2");
sop(singleNew(arr));
}
private static void sop(Object obj) {
System.out.println(obj.toString());
}
public static ArrayList singleNew(ArrayList arr)
{
ArrayList newArr=new ArrayList();
Iterator it=arr.iterator();
while(it.hasNext())
{
Object obj=it.next();
if(!newArr.contains(obj))//如果新的集合中没有该元素,将该元素添加到新集合,否则继续向下查找
newArr.add(obj);
}
return newArr;
}
}</span></span>
例子二:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
将自定义对象作为元素存到ArrayList集合中,并去除重复元素
比如:存人对象,同姓名同年龄,视为同一个人,为重复元素。
思路:1,对人描述,将数据封装进人对象。
2,定义容器,将人存入。
3,取出。
PS:List集合判断元素是否相同,依据是元素的equals方法
*/
import java.util.*;
public class ArrayListDemo {
public static void main(String args[])
{
ArrayList arr=new ArrayList();
arr.add(new Person("zhangsan","nan",23));
arr.add(new Person("lisi","nan",30));
arr.add(new Person("wangwu","nv",45));
arr.add(new Person("zhangsan","nan",23));
arr.add(new Person("lisi","nan",30));
arr.add(new Person("wangwu","nv",45));
arr.remove(new Person("wangwu","nv",45));//如果没有修改equals方法,这个删除时不会成功的,因为删除前肯定要调用equals方法判断当前对象与集合中对象是否相等,
//相等再删除,如果不重写equals方法,它就会按照默认的方法判断两个对象是否相等,不能按照我们判定对象相同的标准判定。
Out(arr);
arr=singleNew(arr);
sop("删除重复元素之后:");
Out(arr);
}
private static void sop(Object obj) {
System.out.println(obj.toString());
}
private static void Out(ArrayList arr)
{
Iterator it=arr.iterator();
while(it.hasNext())
{
Person p=(Person)it.next();
sop("name: "+p.getName()+";sex: "+p.getSex()+";age: "+p.getAge());
}
}
public static ArrayList singleNew(ArrayList arr)
{
ArrayList newArr=new ArrayList();
Iterator it=arr.iterator();
while(it.hasNext())
{
Object obj=it.next();
//其实contains底层调用的是equals方法
if(!newArr.contains(obj))//它不知道什么是判断相等的标准,是根据equals来判断是否相等,这儿在Person类中复写equals来实现判断相等与否
newArr.add(obj);
}
return newArr;
}
}
class Person//创建人的类
{
private String name,sex;
private int age;
Person(String name,String sex,int age)
{
this.name=name;
this.age=age;
this.sex=sex;
}
public boolean equals(Object obj)//Person继承自Object,现在这是覆盖父类中的equals方法
{
if(!(obj instanceof Person))//判断obj是否是Person类型数据
return false;
Person p=(Person)obj;
return this.name.equals(p.getName())&&(this.age==p.getAge());
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
public String getSex()
{
return this.sex;
}
}</span></span>
五,Set练习
1,HashSet练习
1.1,验证Set的无序不重复
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">//用来验证hashset里面的方法
public static void method_1()
{
HashSet hs=new HashSet();//按照hash值排序的
hs.add("aa");
hs.add("bb");
hs.add("cc");
hs.add("dd");
hs.add("dd");//无序不重复
sop(hs.add("ee"));
sop(hs.add("ee"));//第二次没有添加进去
//Set取出的方法就只有迭代器
Iterator it=hs.iterator();
while(it.hasNext())
{
sop(it.next());//无序的
}
sop(hs);
}</span></span>
分析:根据输出结果可以看出,第二次添加ee时返回值是fasle,没有添加成功。
1.2,往hashset集合中存入自定义对象,姓名和年龄相同为一个人,存入重复元素测试
分析:
首先Set的特点是无序且元素不重复,想要存入重复元素测试,首先得判断元素是否相等,而hashSet中判断元素是否相同先调用hashCode方法,就一下子能定位到它应该放置的物理位置上。如果这个位置上没有元素,它就可以直接存储在这个位置上,不用再进行任何比较了;如果这个位置上已经有元素了, 就调用它的equals方法与新元素进行比较,相同的话就不存了,不相同就散列其它的地址。
PS:
元素相等哈希值一定相等,哈希值相同不一定是同一个元素。
练习一代码如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
往hashset集合中存入自定义对象,姓名和年龄相同为一个人,重复元素测试
*/
import java.util.*;
public class HashSetDemo {
public static void main(String args[])
{
HashSet hs=new HashSet();//按照hash值排序的
hs.add(new Person("a1",12));//存数据先看地址
hs.add(new Person("a2",13));
hs.add(new Person("a3",14));
hs.add(new Person("a3",14));
hs.add(new Person("a2",13));
hs.add(new Person("a3",14));
sop(hs.contains(new Person("a3",14)));
sop(hs.remove(new Person("a3",14)));
Iterator it=hs.iterator();
while(it.hasNext())
{
Person p=(Person)it.next();
sop("name--> "+p.getName()+"||Age--> "+p.getAge());
}
}
private static void sop(Object obj) {
System.out.println(obj);
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public boolean equals(Object obj)//Person继承自Object,现在这是覆盖父类中的equals方法
{
if(!(obj instanceof Person))//判断obj是否是Person类型数据
return false;
Person p=(Person)obj;
System.out.println(this.name+"...equals..."+p.name);
return this.name.equals(p.getName())&&(this.age==p.getAge());
}
public int hashCode()
{
System.out.println(this.name+"......hashCode");
return name.hashCode()+34*age;
//return 60;//当hash值相同时才会去调用equals方法,为了调用equals方法去比较,这儿把所有的哈希值都设置为一样的
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
}</span></span>
分析:从输出结果可以看出,每添加一个元素,都会调用一次hashCode,如果哈希值相同,还会调用equals方法判定,这样保证了元素的唯一性和存储的高效性。同时,当调用remove和contains方法时,也调用了hashCode和equals方法。
2,TreeSet练习
2.1 TreeSet会按照字典序给存进来的元素排序
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public static void method_1()
{
TreeSet ts=new TreeSet();
ts.add("1");
ts.add("10");
ts.add("45");
ts.add("2");
ts.add("a");
Iterator it=ts.iterator();
while(it.hasNext())
{
sop(it.next());
}
}</span></span>
2.2 往TreeSet集合中存自定义对象Student,按照学生的年龄进行排序。当主要条件相同时,一定要判断次要条件(先按照年龄排序,如果年龄相同,再判断姓名是否相同)
分析:TreeSet 底层的数据结构是二叉树,存入元素前必须先判断元素的大小,而其判断元素大小是通过元素内部复写的compareTo方法或者创建TreeSet对象时构 造函数中创建的Comparator子类对象中的compare方法。因此,当添加自定义的数据类型的元素时,TreeSet对象不知道如何判断元素大 小,因此添加自定义数据类型的元素时必须重写compareTo方法或者实现Comparator接口。
方式一:以复写compareTo方式实现需求的代码如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">/*
需求:
往TreeSet集合中存自定义对象Studen,想按照学生的年龄进行排序。当主要条件相同时,一定要判断次要条件(先按照年龄排序,如果年龄相同,再判断姓名是否相同)
当添加自定义对象时,会出现java.lang.ClassCastException异常,因为找不到比较的对象不知道谁大谁小
*/
import java.util.*;
public class TreeSetDemo_01 {
public static void main(String args[])
{
TreeSet ts=new TreeSet();//二叉树排序,往里面存的数必须具备比较性
ts.add(new Student("zhangsan",12));
ts.add(new Student("lisi",36));
System.out.println(ts.add(new Student("wangwu",34)));
System.out.println(ts.add(new Student("zhangsan",12)));
Iterator it=ts.iterator();
while(it.hasNext())
{
Student stu=(Student)it.next();
sop(stu.getName()+"||"+stu.getAge());
}
}
private static void sop(Object obj) {
System.out.println(obj);
}
}
class Student implements Comparable//为了具备可比较性,实现一个接口,强制让学生具备比较性
{
private String name;
private int age;
Student(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
@Override
public int compareTo(Object obj) {
if(!(obj instanceof Student))
throw new RuntimeException("不是学生对象");
Student s=(Student)obj;
System.out.println(this.age+"----"+s.getAge());
if(this.age==s.getAge())
return this.name.compareTo(s.name);
return this.age-s.getAge();
}
}</span></span>
方式二:以实现Comparator接口方式实现需求的代码如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
/*
当元素自身不具备比较性,或者具备的比较性不是所需要的,现在就构造一个比较器
*/
public class TreeSetDemo_04 {
public static void main(String args[])
{
TreeSet ts=new TreeSet(new MyCompare());//MyCompare是自己定义的一个比较器
ts.add(new Person("zhangsan",12));
ts.add(new Person("lisi",36));
ts.add(new Person("wangwu",34));
ts.add(new Person("wangwu",34));
ts.add(new Person("lisi",36));
Iterator it=ts.iterator();
while(it.hasNext())
{
Person stu=(Person)it.next();
sop(stu.getName()+"||"+stu.getAge());
}
}
private static void sop(Object obj) {
System.out.println(obj);
}
}
class Person
{
private String name;
private int age;
Person(String name,int age)
{
this.name=name;
this.age=age;
}
public String getName()
{
return this.name;
}
public int getAge()
{
return this.age;
}
}
class MyCompare implements Comparator
{
public int compare(Object o1,Object o2)
{
Person s1=(Person)o1;
Person s2=(Person)o2;
int num=s1.getName().compareTo(s2.getName());
if(num==0){
//return s1.getAge()-s2.getAge();
return new Integer(s1.getAge()).compareTo(new Integer(s2.getAge()));//形成整型的包装类调用compareTo比较也行
}
return num;
}
}</span></span>
PS:要想在TreeSet中使元素按照输入的顺序输出只需将比较器构造为return -1;同理,如果是倒叙输出,则return 1。
六,泛型
1,泛型的优点
JDK1.5版本之后出现的新特性,用于解决安全问题,是一个安全机制。当类中要操作的引用数据类型不确定的时候,早期定义Object来完成扩展,现在定义泛型来完成扩展当使用泛型时,可以使类型转换异常等错误出现在编译时,而不是像以前用Object实现时异常出现在运行时。
好处:
首先,将运行时期出现的问题ClassCastException(转换异常),转移到了编译时期方便于程序员解决问题,让运行时期问题减少,更安全。
首先,将运行时期出现的问题ClassCastException(转换异常),转移到了编译时期方便于程序员解决问题,让运行时期问题减少,更安全。
其次,避免了强制转换的麻烦。
2,泛型的定义
泛型格式:通过<>来定义要操作的引用数据类型,在使用java提供的对象时,什么时候写泛型呢?
通常在集合框架下很常见,只要见到<>就要定义泛型, 其实<>就是用来接收类型的,当使用泛型时,将集合中想要存取的数据类型作为参数传递到<>中就行。
泛型类定义泛型:在整个类中有效,如果被方法使用,那么泛型类型的对象明确要操作的具体数据类型后,所有要操作的类型都已经固定了。
泛型方法:为了让不同方法可以操作不同类型,而且类型还不确定,那么可以将泛型定义在方法上。
PS:静态方法不可以访问类上定义的泛型,如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。同时,定义泛型时,左边和右边的数据类型必须相同。
3,泛型中的通配符
“?” 通配符,也可以理解为占位符
泛型的限定:
? extends E:可以接收E类型或者E的子类型,上限
? super E:可以接收E类型或者E的父类型,下限
下面代码是使用泛型的一个简单示例:
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
import java.lang.String;
public class Example {
public static void main(String args[])
{
TreeSet<String> ts=new TreeSet<String>(new LenComparator());//定义一个String类型的容器
//arr.add(4444);-->arr.add(new Integer(444));会导致编译失败
ts.add("1");
ts.add("10");
ts.add("45");
ts.add("2");
ts.add("a");
Iterator<String> it=ts.iterator();
while(it.hasNext())
{
String s=it.next();
System.out.println(s);
}
}
}
class LenComparator implements Comparator<String>
{
public int compare(String s1,String s2)
{
int num=new Integer(s1.length()).compareTo(new Integer(s2.length()));
if(num==0)
return s1.compareTo(s2);
return num;
}
}</span></span>
泛型类中可以定义泛型方法,静态方法的泛型定义等,如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public class Example2 {
public static void main(String args[])
{
Demo<String> d=new Demo<String>();
d.print("dha");
d.print(4);//类型定义在方法上,输入什么类型的数据就输出什么类型的数据
d.show("4");//传入的参数类型必须与泛型确定的类型一致
Demo.method(4);
Demo.method("aaa");
}
}
class Demo<T>//可以泛型类的同时也泛型方法
{
public void show(T p)
{
System.out.println("show: "+p);
}
public <T> void print(T p)//泛型方法
{
System.out.println("print: "+p);
}
public static <T> void method(T t) //T在建立对象时明确,而static存在的时候还没有加载对象,先加载静态的,再加载动态的
{
System.out.println("method: "+t);
}
}</span></span>
继承泛型类或者接口时,可以选择定义泛型子类,也可以定义指定数据类型的子类,如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">public class Example3
{
public static void main(String args[])
{
InterDemo<Integer> id=new InterDemo<Integer>();
id.show(new Integer(4));
InterDemo2 id2=new InterDemo2();
id2.show("yes");
}
}
interface Inter<T>
{
void show(T t);
}
class InterDemo<T> implements Inter<T>
{
public void show(T t)
{
System.out.println(t);
}
}
class InterDemo2 implements Inter<String>
{
public void show(String t)
{
System.out.println(t);
}
}</span></span>
泛型的通配符以及泛型限定上限和下限的使用方式如下
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class Example4 {
public static void main(String args[])
{
ArrayList<String> arr=new ArrayList<String>();
arr.add("a1");
arr.add("a2");
arr.add("a1");
arr.add("a2");
System.out.println("arr---print ");
print(arr);
ArrayList<Integer> arr1=new ArrayList<Integer>();
arr1.add(1);
arr1.add(2);
arr1.add(1);
arr1.add(2);
System.out.println("arr1---print ");
print(arr1);
ArrayList<Person> arr2=new ArrayList<Person>();
arr2.add(new Person("a1"));
arr2.add(new Person("a2"));
arr2.add(new Person("a1"));
arr2.add(new Person("a2"));
System.out.println("arr2---printPer ");
printPer(arr2);
System.out.println("arr2---show ");
show(arr2);
//ArrayList<Student> arr3=new ArrayList<Person>();这样是错误的,左边是什么右边就是什么
ArrayList<Student> arr3=new ArrayList<Student>();
arr3.add(new Student("a1"));
arr3.add(new Student("a2"));
arr3.add(new Student("a1"));
arr3.add(new Student("a2"));
System.out.println("arr3---printPer ");
printPer(arr3);
System.out.println("arr3---show ");
show(arr3);
}
public static void print(ArrayList<?> arr)//不明确类型,没法调用?好的方法
{
Iterator<?> it=arr.iterator();
System.out.print("{");
while(it.hasNext())
{
System.out.print(it.next()+",");
}
System.out.println("}");
}
public static void printPer(ArrayList<? super Student> arr)//能打印的是Student或者Student的父类,泛型限定下限
{
Iterator<? super Student> it=arr.iterator();
System.out.print("{");
while(it.hasNext())
{
Person stu=(Person)it.next();
System.out.print(stu.getName()+",");
}
System.out.println("}");
}
public static void show(ArrayList<? extends Person> arr)//能打印的是Person或者Person的子类,泛型限定上限
{
Iterator<? extends Person> it=arr.iterator();
System.out.print("{");
while(it.hasNext())
{
Person stu=it.next();
System.out.print(stu.getName()+",");
}
System.out.println("}");
}
}
class Person
{
private String name;
Person(String name)
{
this.name=name;
}
public String getName()
{
return this.name;
}
}
class Student extends Person
{
Student(String name) {
super(name);
}
}</span></span>
TreeSet构造函数接收一个比较器时有两种情况:1,TreeSet(Collection<? extends E> c);2,TreeSet(Collection<? super E> c)。因此在定义构造函数时,构造一个父类的比较器,子类使用比较器时,就不用分别定义各自的比较器了,例如
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">import java.util.*;
public class Example5 {
public static void main(String args[])
{
//TreeSet<Dog> ts=new TreeSet<Dog>(new DogComp());
TreeSet<Dog> ts=new TreeSet<Dog>(new Comp());
ts.add(new Dog("wangwang1"));
ts.add(new Dog("wangwang2"));
ts.add(new Dog("wangwang3"));
ts.add(new Dog("wangwang4"));
Iterator<Dog> it=ts.iterator();
while(it.hasNext())
{
System.out.println(it.next().getName());
}
//TreeSet<Cat> ts1=new TreeSet<Cat>(new CatComp());分别new一个自己的比较器,很麻烦
TreeSet<Cat> ts1=new TreeSet<Cat>(new Comp());//用泛型传参数时传父类,这样子类也可以用该比较器,不过下面发方法只能用父类中有的方法
ts1.add(new Cat("miao1"));
ts1.add(new Cat("miao2"));
ts1.add(new Cat("miao3"));
ts1.add(new Cat("miao4"));
Iterator<Cat> it1=ts1.iterator();
while(it1.hasNext())
{
System.out.println(it1.next().getName());
}
}
}
class Animal
{
private String name;
Animal(String name)
{
this.name=name;
}
public String getName()
{
return this.name;
}
}
class Dog extends Animal
{
Dog(String name)
{
super(name);
}
}
class Cat extends Animal
{
Cat(String name)
{
super(name);
}
}
/*class DogComp implements Comparator<Dog>//如果传子类的数据类型进来,需要为不同子类构造比较器,这样很麻烦,就像要给猫和狗分别创建比较器一样
{
public int compare(Dog d1,Dog d2)
{
return d1.getName().compareTo(d2.getName());
}
}
class CatComp implements Comparator<Cat>//猫数据类型的比较器
{
public int compare(Cat d1,Cat d2)
{
return d1.getName().compareTo(d2.getName());
}
}*/
//泛型限定是进行泛型扩展用的,有扩展性就有局限性
class Comp implements Comparator<Animal>//创建父类的比较器,动物类的比较器,避免多次构造比较器的麻烦
{
public int compare(Animal d1,Animal d2)
{
return d1.getName().compareTo(d2.getName());
</span></span><pre name="code" class="java"><span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;"> }</span></span>
<span style="font-size:14px;"><span data-wiz-span="data-wiz-span" style="font-size: 12pt;">}</span></span>