集合和数组的区别
1. 长度区别:
数组固定
集合可变
2. 内容区别:
数组可以是基本类型,也可以是引用类型
集合只能是引用类型
3. 元素内容:
数组只能存储同一种类型
集合可以存储不同类型(其实集合一般存储的也是同一种类型)
继承体系结构
Collection
|--List
|--ArrayList
|--Vector
|--LinkedList
|--Set
|--HashSet
|--TreeSet
案例:迭代器遍历方式
public static void main(String[] args) {
Collection c = new ArrayList();
c.add("java");
c.add("scala");
c.add("hadoop");
//遍历集合
Iterator it = c.iterator();
while(it.hasNext()) {
String s =(String) it.next();
System.out.println(s);
}
}
List
特点:
有序(存储顺序和取出顺序一致),可重复。
特有遍历:由size()和get()结合
List list = new ArrayList();
list.add("java");
list.add("scala");
list.add("hadoop");
//遍历集合
Iterator it = list.iterator();
while(it.hasNext()) {
String s =(String) it.next();
System.out.println(s);
}
for(int x=0; x<list.size(); x++) {
String s =(String) list.get(x);
System.out.println(s);
}
常见数据结构
ArrayXxx:底层数据结构是数组,查询快,增删慢
LinkedXxx:底层数据结构是链表,查询慢,增删快
HashXxx:底层数据结构是哈希表。依赖两个方法:hashCode()和equals()
TreeXxx:底层数据结构是二叉树。两种方式排序:自然排序和比较器排序
List的子类特点
ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高。
Vector(几乎不用)
底层数据结构是数组,查询快,增删慢。
线程安全,效率低。
LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高。
有特有功能:
a:添加
addFirst()
addLast()
b:删除
removeFirst()
removeLast()
c:获取
getFirst()
getLast()
Set
特点
无序,唯一(由hashCode()和equals()保证)
HashSet
A:底层数据结构是哈希表(是一个元素为链表的数组)
B:哈希表底层依赖两个方法:hashCode()和equals()
执行顺序:
首先比较哈希值是否相同
相同:继续执行equals()方法
返回true:元素重复了,不添加
返回false:直接把元素添加到集合
不同:就直接把元素添加到集合
TreeSet集合
A:底层数据结构是红黑树(是一个自平衡的二叉树)
B:保证元素的排序方式
a:自然排序(元素具备比较性)
让元素所属的类实现Comparable接口
b:比较器排序(集合具备比较性)
让集合构造方法接收Comparator的实现类对象
Collection集合总结
Collection
|--List 有序,可重复
|--ArrayList
底层数据结构是数组,查询快,增删慢。
线程不安全,效率高
|--Vector
底层数据结构是数组,查询快,增删慢。
线程安全,效率低
|--LinkedList
底层数据结构是链表,查询慢,增删快。
线程不安全,效率高
|--Set 无序,唯一
|--HashSet
底层数据结构是哈希表。
唯一性
依赖两个方法:hashCode()和equals()
开发中自动生成这两个方法即可
|--LinkedHashSet
底层数据结构是链表和哈希表
由链表保证元素有序
由哈希表保证元素唯一
|--TreeSet
底层数据结构是红黑树
排序:
自然排序
比较器排序
唯一性:
根据比较的返回值是否是0来决定
Collection集合使用谁?
唯一吗?
是:Set
排序吗?
是:TreeSet
否:HashSet
否:List
要安全吗?
是:Vector(几乎不用)
否:ArrayList或者LinkedList
查询多:ArrayList
增删多:LinkedList
泛型
是一种把明确类型的工作推迟到创建对象或者调用方法的时候才去明确的特殊的类型
特点:
1. 把运行时期的问题提前到了编译期间
2. 避免了强制类型转换
3. 优化了程序设计,解决了黄色警告线问题,让程序更安全
高级通配符
? 表示任意的类型都是可以的
? extends E 向下限定,E及其子类
? super E 向上限定,E极其父类
遍历:
// JDK7的新特性:泛型推断。
// ArrayList<Student> array = new ArrayList<>();
// 不建议
ArrayList<Student> array = new ArrayList<Student>();
Student s1 = new Student("java", 40);
Student s2 = new Student("scala", 10);
Student s3 = new Student("hadoop", 5);
array.add(s1);
array.add(s2);
array.add(s3);
// 遍历
Iterator<Student> it = array.iterator();
while (it.hasNext()) {
Student s = it.next();
}
for (int x = 0; x < array.size(); x++) {
Student s = array.get(x);
}
增强for循环
格式:
for(数据类型 变量名 : 数组或者Collection集合的对象) {
使用该变量即可,该变量其实就是数组或者集合中的元素。
}
好处
简化了数组和集合的遍历
弊端
增强for循环的目标不能为null。建议在使用前,先判断是否为null。
示例:
HashSet<Integer> ts = new HashSet<Integer>();
while (ts.size() < 10) {
ts.add(ts.size());
}
for (Integer i : ts) {
System.out.println(i);
}
案例:获取10个1至20的随机数,要求随机数不能重复
public static void main(String[] args) {
// 创建随机数对象
Random r = new Random();
// 创建一个Set集合
HashSet<Integer> ts = new HashSet<Integer>();
// 判断集合的长度是不是小于10
while (ts.size() < 10) {
int num = r.nextInt(20) + 1;
ts.add(num);
}
// 遍历Set集合
for (Integer i : ts) {
System.out.println(i);
}
}
案例:”aababcabcdabcde”,获取字符串中每一个字母出现的次数要求结果:a(5)b(4)c(3)d(2)e(1)
public static void main(String[] args) {
// 定义一个字符串(可以改进为键盘录入)
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串:");
String line = sc.nextLine();
// 定义一个TreeMap集合
TreeMap<Character, Integer> tm = new TreeMap<Character, Integer>();
//把字符串转换为字符数组
char[] chs = line.toCharArray();
//遍历字符数组,得到每一个字符
for(char ch : chs){
//拿刚才得到的字符作为键到集合中去找值,看返回值
Integer i = tm.get(ch);
//是null:说明该键不存在,就把该字符作为键,1作为值存储
if(i == null){
tm.put(ch, 1);
}else {
//不是null:说明该键存在,就把值加1,然后重写存储该键和值
i++;
tm.put(ch,i);
}
}
//定义字符串缓冲区变量
StringBuilder sb= new StringBuilder();
//遍历集合,得到键和值,进行按照要求拼接
Set<Character> set = tm.keySet();
for(Character key : set){
Integer value = tm.get(key);
sb.append(key).append("(").append(value).append(")");
}
//把字符串缓冲区转换为字符串输出
String result = sb.toString();
System.out.println("result:"+result);
}