泛型:
jdk1.5出现的安全机制。
好处:
1,将运行时期的问题ClassCastException转到了编译时期。
2,避免了强制转换的麻烦。
<>:什么时候用?当操作的引用数据类型不确定的时候。就使用<>.将要操作的引用数据类型传入即可。其实<>就是一个用于接受具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型。
泛型技术是在给编译器使用的技术,用于编译时期。确保了类型的安全。
运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。
为什么擦除?因为为了兼容运行的类加载器。
泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者在强制转换了。
共用类:
Person:
public class Person implements Comparable{
@Override
public String toString() {
return "Person" + name + ":" + age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
private String name;
private int age;
public Person() {
super();
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public int compareTo(Person p){
int temp=this.age-p.age;
return temp==0?this.name.compareTo(p.name):temp;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Person other = (Person) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
Student:
public class Student extends Person{
@Override
public String toString() {
return "Student:" + getName() + ":" + getAge();
}
public Student(){
super();
}
public Student(String name, int age) {
super(name, age);
}
}
Worker:
public class Worker extends Person{
@Override
public String toString() {
return "Worker" + getName() + ":" + getAge();
}
public Worker(){
super();
}
public Worker(String name,int age){
super(name,age);
}
}
ComparatorByName:
public class ComparatorByName implements Comparator{
@Override
public int compare(Person o1, Person o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
GenericDemo:
public static void main(String[] args) {
int[] arr=new int[4];
ArrayList al=new ArrayList();
al.add("abc");
al.add("hahah");
Iterator it=al.iterator();
while(it.hasNext()){
String str=it.next();
System.out.println(str);
}
}
运行:
GenericDemo2:
public static void main(String[] args) {
TreeSet ts =new TreeSet(new ComparatorByName());
ts.add(new Person("lisi8",21));
ts.add(new Person("lisi3",23));
ts.add(new Person("lisi",21));
ts.add(new Person("lisi0",20));
Iterator it=ts.iterator();
while(it.hasNext()){
Person p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
运行:
那么用泛型操作不确定引用类型的数据呢?
以前的做法是把所有共性取出来,所以所有对象都可以往里面存。即用Object定义一个对象。
在jdk1.5以后,使用泛型来接受要操作的引用数据类型--即泛型类。
什么时候用?
当类中操作的引用数据类型不确定的时候,就使用泛型来表示。这样做比Object安全得多。
Tool:
/*
public class Tool {
以前是把所有共性都取出来,所以所有对象都可以往里面存
private Object object;
public void setObject(Object object) {
this.object = object;
}
public Object getObject(){
return object;
}
}
*/
/*
在jdk1.5后,使用泛型来接受类中要操作的引用数据类型。
即泛型类。什么时候用?当类中操作的引用数据类型不确定的时候,就使用泛型来表示。
这么做比Object要安全得多。
*/
public class Tool{
private QQ q;
public QQ getObject() {
return q;
}
public void setObject(QQ Object) {
this.q = Object;
}
/*
将泛型定义在方法上
*/
public void show(W str){
System.out.println("show:"+str.toString());
}
public void print(QQ str){
System.out.println("print:"+str);
}
/*
当方法静态时,不能访问类上定义的泛型。如果静态方法使用泛型,只能将泛型定义在方法上。
*/
public static void method(Y obj){
System.out.print("method"+obj);
}
}
GenericDefineDemo:
public static void main(String[] args) {
//以前的做法
/*Tool tool=new Tool();
tool.setObject(new Worker());
Student stu=(Student) tool.getObject();*/
//1.5以后
Tool tool=new Tool();
tool.setObject(new Student("kk",21));
Student stu =tool.getObject();
System.out.print(tool.getObject());
}
运行:
将泛型定义在方法上。
GenericDefineDemo2:
public static void main(String[] args) {
Tool tool=new Tool();
tool.show(new Integer(4));
tool.show("abc");
tool.print("haha");
// tool.print(new Integer(4));报错,因为此方法没有用泛型定义
Tool.method("haha");
Tool.method(new Integer(9));
}
运行:
将泛型定义在接口上。
GenericDefineDemo3:
public class GenericDefineDemo3 {
public static void main(String[] args) {
InterImpl in=new InterImpl();
in.show("abc");
InterImpl2 in2=new InterImpl2();
in2.show(5);
}
}
//泛型接口,将泛型定义在接口上。
interface Inter{
public void show(T t);
}
class InterImpl implements Inter{
public void show(String str){
System.out.println("show:"+str);
}
}
class InterImpl2 implements Inter{
public void show(Q q){
System.out.println("show:"+q);
}
运行:
泛型的通配符:? 未知类型。
GenericAdvanceDemo:
public static void main(String[] args) {
ArrayList al=new ArrayList();
al.add("abc");
al.add("hehe");
ArrayList al2=new ArrayList();
al2.add(5);
al2.add(87);
printCollection(al);
printCollection(al2);
}
// 迭代并打印集合中的元素
// 通配符?的使用
private static void printCollection(Collection> al) {
Iterator> it=al.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
运行:
泛型的限定:
? extends E:接受E类型或者E的子类对象。上限。
? super E:接受E类型或者E的父类型对象。下限。
GenericAdvanceDemo2:
public static void main(String[] args) {
ArrayList al=new ArrayList();
al.add(new Person("abc",30));
al.add(new Person("abc4",34));
ArrayList al2=new ArrayList();
al2.add(new Student("stu1",11));
al2.add(new Student("stu2",22));
ArrayList al3=new ArrayList();
al3.add("stu3331");
al3.add("stu3332");
printCollection(al);
printCollection(al2);
}
/*
迭代并打印集合中的元素
通配符?的使用
可以对类型进行限定:
? extends E:接受E类型或者E的子类型对象。上限!
? super E:接受E类型或者E的父类型。下限!
*/
/*
private static void printCollection(Collection extends Person> al) {
Iterator extends Person> it=al.iterator();
while(it.hasNext()){
Person p=it.next();
System.out.println(p.getName()+":"+p.getAge());
}
}
*/
private static void printCollection(ArrayList super Student> al) {
Iterator super Student> it=al.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
运行:
一般存储对象的时候用上限。比如 添加元素 addAll。
GenericAdvanceDemo3:
public static void main(String[] args) {
ArrayList al1=new ArrayList();
al1.add(new Person("abc",30));
al1.add(new Person("abc4",34));
ArrayList al2=new ArrayList();
al2.add(new Student("stu1",11));
al2.add(new Student("stu2",22));
ArrayList al3=new ArrayList();
al3.add(new Worker("stu1",11));
al3.add(new Worker("stu2",22));
ArrayList al4=new ArrayList();
al4.add("anbc");
// al1.addAll(al4);错误,类型不匹配
al1.addAll(al2);
al1.addAll(al3);
System.out.print(al1.size());
}
一般取出对象的时候用下限。比如 比较器。
public class GenericAdvanceDemo4 {
public static void main(String[] args){
TreeSet al1=new TreeSet(new CompByName());
al1.add(new Person("abc4",34));
al1.add(new Person("abc1",30));
al1.add(new Person("abc2",38));
TreeSet al2=new TreeSet(new CompByName());
al2.add(new Student("stu1",11));
al2.add(new Student("stu2",22));
al2.add(new Student("stu7",20));
TreeSet al3=new TreeSet();
al3.add(new Worker("stu1",11));
al3.add(new Worker("stu2",22));
TreeSet al4=new TreeSet();
al4.add("abchd");
Iterator it =al2.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
}
/*
class TreeSet{
Tree(Comparator super Worker> comp);
}
什么时候用下限呢?通常对集合中的元素进行取出操作时,可以用下限
*/
class CompByName implements Comparator{
@Override
public int compare(Person o1, Person o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
class CompByStuName implements Comparator{
@Override
public int compare(Student o1, Student o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
class CompWorkerName implements Comparator{
@Override
public int compare(Worker o1, Worker o2) {
int temp=o1.getName().compareTo(o2.getName());
return temp==0?o1.getAge()-o2.getAge():temp;
}
}
运行:
通配符“?”的体现:containsAll(),removeAll()等。
GenericAdvanceDemo5:
public static void main(String[] args) {
ArrayList al1=new ArrayList();
al1.add(new Person("abc",30));
al1.add(new Person("abc4",34));
ArrayList al2=new ArrayList();
al2.add(new Person("abc22222",30));
al2.add(new Person("abc4222222",34));
ArrayList al4=new ArrayList();
al4.add("abcdef");
al4.add("abc");
al1.containsAll(al4);
// "abc".equals(new Person("ahaha",20));比较的是地址,都属于Object类型
}
// ?:啥类型不知道,就用这个 如:containsAll(),removeAll()等
public static void printCollection(Collection> al){
Iterator> it = al.iterator();
while(it.hasNext()){
System.out.println(it.next().toString());
}
}
总结:
集合的一些技巧:
需要唯一吗?
需要:Set
需要制定顺序:
需要:TreeSet
不需要:HashSet
但是想要一个存储一致的顺序(有序):LinkedHashSet
不需要:List
需要频繁增删吗?
需要:LinkedList
不需要:ArrayList
如何记录每一个容器的结构和所属体系?
看名字!
List
|--ArrayList
|--LinkedList
Set
|--HashSet
|--TreeSet
后缀名就是该集合的所属体系。
前缀名就是该集合的数据结构。
array:就i要想到数组,查询快,有角标。
link:就i要想到链表,增删快,想到add get remove first last的方法。
hash:就i要想到哈希表,唯一性,元素需要覆盖hashcode和equals。
tree:就i要想到二叉树,排序,两个接口Comparable,Comparator。
而且通常这些常用的集合容器都是不同步的。