光集合是不够应对所有问题的,于是乎泛型定义了规范。
-
A:泛型概述:
限定集合存储的数据类型,Collection其中E代表 引用数据类型, 如果加上了该引用数据类型, 表示该集合中只能存储该类型对象, 或者该类型的子类对象. -
B:泛型好处
- 提高安全性(将运行期的错误转换到编译期)
- 省去强转的麻烦
-
C:泛型基本使用
- <>中放的必须是引用数据类型
-
D:泛型使用注意事项
- 前后的泛型必须一致 ,或者后面的泛型可以省略不写 (1.7的新特性菱形泛型)
用起来的话就是下面这样
import java.util.ArrayList;
import java.util.Iterator;
public class Demo1_Generic {
public static void main(String[] args) {
//demo1();
//int[] arr = new byte[5]; //数组要保证前后的数据类型一致
//ArrayList<Object> list = new ArrayList<Person>(); //集合的泛型要保证前后的数据类型一致
//ArrayList<Object> list = new ArrayList<>(); //1.7版本的新特性,菱形泛型,前面定义了,后面不加表示和前面一致
ArrayList<Object> list = new ArrayList<>(); //泛型最好不要定义成Object,没有意义
list.add("aaa");
list.add(true);
}
public static void demo2() {
ArrayList<Person> list = new ArrayList<Person>();
// list.add(110);
// list.add(true);
list.add(new Person("张三", 23));
list.add(new Person("李四", 24));
Iterator<Person> it = list.iterator();
while(it.hasNext()) {
//System.out.println(it.next());
//System.out.println(it.next().getName() + "..." + it.next().getAge());//next方法只能调用一次,如果调用多次会将指针向后移动多次
Person p = it.next();
System.out.println(p.getName() + "..." + p.getAge());
}
}
public static void demo1() {
//这里编译通过,运行包ClassCastException(类转换异常)
ArrayList list = new ArrayList();
list.add(110);
list.add(true);
list.add(new Person("张三", 23));
list.add(new Person("李四", 24));
Iterator it = list.iterator();
while(it.hasNext()) {
Person p = (Person)it.next();
System.out.println(p.getName() + "..." + p.getAge());
}
}
}
到了这里就会涉及到增强for循环了,用案例来说吧。
import java.util.ArrayList;
import java.util.Iterator;
public class Demo2_Foreach {
public static void main(String[] args) {
demo1();
}
public static void demo1() {
//基本数据类型数组的遍历
int[] arr = {11,22,33,44,55};
for (int i : arr) {
System.out.println(i);
}
//集合的遍历
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
list.add("d");
for (String string : list) {
System.out.println(string);
}
}
}
很好用的一个集合遍历方法,不过不能删除元素,只是单纯的遍历。Arrays工具类中还有一个asList()方法,用来集合换数组。而Collection中的toArray(T[] a)方法就是泛型版的集合转数组了。
接下来就是HashSet了。
HashSet原理
-
使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个equals()比较, 效率较低, 哈希算法提高了去重复的效率,降低了使用equals()方法的次数
-
当HashSet调用add()方法存储对象的时候, 先调用对象的hashCode()方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象
-
如果没有哈希值相同的对象就直接存入集合
-
如果有哈希值相同的对象, 就让哈希值相同的对象逐个进行equals()比较,比较结果为false就存入, true则不存
当然有个问题,set是无序的,这时候就要用到LinkedHashSet的特点可以保证怎么存就怎么取还可以保证元素是唯一的。
import java.util.HashSet;
import java.util.Scanner;
public class Test1 {
/**
* * 使用Scanner从键盘读取一行输入,去掉其中重复字符, 打印出不同的那些字符
* aaaabbbcccddd
*
* 分析:
* 1,创建Scanner对象
* 2,创建HashSet对象,将字符存储,去掉重复
* 3,将字符串转换为字符数组,获取每一个字符存储在HashSet集合中,自动去除重复
* 4,遍历HashSet,打印每一个字符
*/
public static void main(String[] args) {
//1,创建Scanner对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入一行字符串:");
//2,创建HashSet对象,将字符存储,去掉重复
HashSet<Character> hs = new HashSet<>();
//3,将字符串转换为字符数组,获取每一个字符存储在HashSet集合中,自动去除重复
String line = sc.nextLine();
char[] arr = line.toCharArray();
for (char c : arr) { //遍历字符数组
hs.add(c);
}
//4,遍历HashSet,打印每一个字符
for(Character ch : hs) {
System.out.print(ch);
}
}
}
set集合中还有个TreeSet集合
import java.util.Comparator;
import java.util.TreeSet;
public class Demo3_TreeSet {
/**
* @param args
* TreeSet集合是用来对象元素进行排序的,同样他也可以保证元素的唯一
* 当compareTo方法返回0的时候集合中只有一个元素
* 当compareTo方法返回正数的时候集合会怎么存就怎么取
* 当compareTo方法返回负数的时候集合会倒序存储
*/
public static void main(String[] args) {
demo1();
}
public static void demo1() {
//因为TreeSet要对元素进行排序,那你排序的依据是什么,姓名还是年龄还是其它的,得告诉它,怎么告诉?
//需要让Person类实现Comparable接口重写compareTo方法
TreeSet<Person> ts = new TreeSet<>();
ts.add(new Person("张三", 23));
ts.add(new Person("李四", 13));
ts.add(new Person("周七", 13));
ts.add(new Person("王五", 43));
ts.add(new Person("赵六", 33));
System.out.println(ts);
}
}
-
a.自然顺序(Comparable)
- TreeSet 类的 add()方法中 会把存入的对象 提升为Comparable类型
- 调用对象的 compareTo() 方法和集合中的对象 比较 (当前存入的是谁,谁就会调用compareTo方法)
- 根据compareTo() 方法返回的结果 进行存储
-
b.比较器顺序(Comparator)
- 创建TreeSet的时候 可以制定 一个Comparator
- 如果传入了Comparator的子类对象, 那么TreeSet就会按照 比较器中的顺序排序
- add()方法内部会自动 调用 Comparator接口 中compare()方法 排序
- 调用的对象(就是当前存入的对象) 是 compare方法的第一个参数, 集合中的对象(已经添加进去的对象 )是compare方法的第二个参数
-
c.两种方式的区别
- TreeSet构造函数什么都不传, 默认按照类中Comparable 的顺序(没有就报错ClassCastException)
- TreeSet如果传入Comparator , 就优先按照Comparator
好了,先到这里。
ps:每日一词
满江红·相逢无语雨为酒
栖凤梧桐,听千语,夜长难许。花弄柳,不吾年纪,被风迎去。细日烟生云换替,半池闲绿游鱼聚。漫天舞、行客喜相逢,伤漂旅。
同生宴,当好句。杯欲酒,天将予。遣家书一段,远消千虑。浮若无依情自禁,相思难见相思故。月迷明,心念有嫦娥,衷肠付。