数组其实就是一个集合。集合实际上就是一个容器,可以来容纳其他类型的数据。
集合为什么说在开发中使用较多?
集合不能直接存储基本数据类型,另外集合也不能直接存储java对象,集合当中存储的都是java对象的内存地址。(或者说集合中存储的是引用)
注意
在java中每一个不同的集合,底层会对应不同的数据结构。往不同的集合中存储元素,等于将数据放到不同的数据结构当中。
什么是数据结构?
java.util.*;
一类是单个方式存储元素:
一类是以键值对的方式存储元素:
Collection中能存放什么元素?
Collection接口中常用方法
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
/*
java.util.Collection接口中常用方法
boolean add(Object e) 向集合中添加元素
int size() 获取集合中元素的个数
void clear() 清空集合
boolean contains(Object o) 判断当前集合中是否包含元素o,包含返回true
boolean remove(Object o) 删除集合中的某个元素
boolean isEmpty() 判断该集合元素的个数是否为0
Object[] toArray() 调用这个方法可以把集合转换为数组
*/
public class CollectionTest01 {
public static void main(String[] args) {
//创建一个集合对象
//Collection c = new Collection(); 接口是抽象的,无法实例化
//多态
Collection c = new ArrayList();
//测试Collection接口中的常用方法
c.add(100); //自动装箱,实际上是放进去一个对象的内存地址,Integer x = new Integer(100)
c.add(new Object());
c.add(new Student());
c.add(true); //自动装箱
//获取集合中元素的个数
System.out.println("集合中元素的个数是:" + c.size()); //4
//清空集合
c.clear();
System.out.println("集合中元素的个数是:" + c.size()); //0
//再向集合中添加元素
c.add("hello"); //添加"hello对象的内存地址放到集合当中"
c.add("world");
c.add("pudding");
//判断集合中是否包含pudding
boolean flag = c.contains("pudding");
System.out.println(flag); //true
//删除集合中的某个元素
c.remove("world");
System.out.println("集合中元素的个数是:" + c.size()); //2
//判断集合是否为空(集合中是否存在元素)
System.out.println(c.isEmpty()); //false
c.add("abc");
c.add("def");
c.add(new Student());
//转换为数组
Object[] obj = c.toArray();
for (int i = 0; i < obj.length; i++) {
//遍历数组
Object o = obj[i];
System.out.println(o);
/*
abc
def
com.collection.Student@154617c
*/
}
}
}
class Student{
}
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
public class CollectionTest04 {
/*boolean contains(Object o) 判断集合中是否包含某个对象o,如果包含返回true
那么它在底层是怎么判断集合中是否包含某个元素的呢?
调用了equals方法进行比对
equals方法返回true,就表示包含这个元素
*/
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
String s1 = new String("abc"); //s1 = 0x1111
c.add(s1);
String s2 = new String("def"); //s2 = 0x2222
c.add(s2);
//集合中元素的个数
System.out.println("集合中元素的个数:" + c.size()); //2
String x = new String("abc"); //s3 = 0x5555
//c集合中是否包含x?
System.out.println(c.contains(x)); //集合中是否包含"abc" //true
}
}
测试contains方法:
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Objects;
/*
测试contains方法
*/
public class CollectionTest05 {
public static void main(String[] args) {
//创建集合对象
Collection c = new ArrayList();
//创建用户对象
User u1 = new User("jack");
User u2 = new User("jack");
//加入集合
c.add(u1);
//判断集合中是否包含u2
/*
没有重写equals之前:这个结果是false
调用Object的equals方法,==比较的是内存地址
*/
//System.out.println(c.contains(u2)); //false
//重写equals方法之后,比较的时候会比较name
System.out.println(c.contains(u2)); //true
}
}
class User{
private String name;
public User(){
}
public User(String name) {
this.name = name;
}
//重写equals方法
//将来调用equals方法的时候,一定是调用这个重写的equals方法
//这个equals方法比较原理是:只要姓名一样就表示同一个用户
@Override
public boolean equals(Object o) {
if (o == null || !(o instanceof User)) return false;
if (o == this) return true;
User user = (User) o;
//如果名字一样表示同一个人(不再比较对象的内存地址了)
return user.name.equals(this.name);
}
}
结论:
public class CollectionTest05 {
public static void main(String[] args) {
//创建集合对象
Collection cc = new ArrayList();
//创建字符串对象
String s1 = new String("hello");
//加进去
cc.add(s1);
//创建了一个新的字符串对象
String s2 = new String("hello");
//删除s2
cc.remove(s2);
//集合中的元素个数
System.out.println(cc.size()); //0
}
}
结论:
关于集合的remove
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest06 {
public static void main(String[] args) {
//创建集合
Collection c = new ArrayList();
//注意:此时获取迭代器,指向的那是集合中没有元素状态下的迭代器
//一定要注意:集合结果只要发生改变,迭代器必须重新获取
//当集合结构发生改变,迭代器没有重写获取时,调用next()方法时:java.util.ConcurrentModificationException
//Iterator it = c.iterator();
//添加元素
c.add(1);
c.add(2);
c.add(3);
//获取迭代器
Iterator it = c.iterator();
while (it.hasNext()) {
//编写代码时next()方法返回值类型必须是Object
//Integer i = it.next
Object obj = it.next();
System.out.println(obj); //1 2 3
}
Collection c2 = new ArrayList();
c2.add("abc");
c2.add("def");
c2.add("xyz");
Iterator it2 = c2.iterator();
while (it2.hasNext()){
Object o = it2.next();
//删除元素
//删除元素之后,集合结构发生改变,应该重写去获取迭代器
//但是,循环下一次的时候并没有重写获取迭代器,所以出现了异常:java.util.ConcurrentModificationException
//出现异常的根本原因:集合中元素删除了,但是没有更新迭代器
//c2.remove(o); 直接通过集合去删除元素,没有通知迭代器。(导致迭代器的快照和原集合状态不同)
//使用迭代器可以删除元素
//迭代器去删除时,会自动更新迭代器,并且更新集合(删除集合中元素)
it2.remove();
System.out.println(o);
}
System.out.println(c2.size()); //0
}
}
Iterator it = c.iterator();
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
public class CollectionTest02 {
public static void main(String[] args) {
//注意:以下的遍历方式/迭代方式,是所有Collection通用的一种方式
//Map集合中不能用,在所有的Collection以及子类中使用
//创建集合对象
Collection c = new ArrayList(); //后面的集合无所谓,主要看前面的Collection接口,怎么迭代
//添加元素
c.add("abc");
c.add("def");
c.add(100);
c.add(new Object());
//对集合Collection进行遍历
//第一步:获取集合对象的迭代器对象Iterator
Iterator it = c.iterator();
//第二步:通过以上获取的迭代器对象开始遍历集合
/*
迭代器对象中的方法:
boolean hasNext() 如果仍有元素可以迭代,则返回 true。
Object next() 返回迭代的下一个元素。
*/
boolean hasNext = it.hasNext();
System.out.println(hasNext); //true
if (hasNext) {
//不管你当初存进去什么,取出来统一都是Object
Object obj = it.next();
System.out.println(obj); //abc
}
//或者用循环
while (it.hasNext()) {
Object object = it.next();
System.out.println(object);
}
}
}
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
public class CollectionTest03 {
public static void main(String[] args) {
//创建集合对象
Collection c1 = new ArrayList(); //ArrayList集合有序可重复
//添加元素
c1.add(1);
c1.add(2);
c1.add(3);
c1.add(4);
//迭代集合
Iterator it = c1.iterator();
while (it.hasNext()){
Object object = it.next();
/*if (object instanceof Integer) {
System.out.println("Integer类型");
}*/
//存进去什么类型,取出来还是什么类型,只不过输出的时候转换成字符串
System.out.println(object);
}
//HashSet集合:无序不可重复
Collection c2 = new HashSet();
c2.add(100);
c2.add(200);
c2.add(300);
c2.add(100);
Iterator it2 = c2.iterator();
while (it2.hasNext()){
System.out.println(it2.next());
}
}
}
List集合中的元素特点:有序可重复
List既然是Collection接口的子接口,那么肯定List接口有自己"特色"方法
package com.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/*
以下只列出List接口特有的常用的方法
void add(int index, Object element)
Object get(int index)
int indexOf(Object o)
int lastIndexOf(Object o)
Object remove(int index)
Object set(int index, Object element)
*/
public class ListTest01 {
public static void main(String[] args) {
//创建List类型集合
List myList = new ArrayList();
//添加元素
myList.add("A"); //默认都是向集合末尾添加元素
myList.add("B");
myList.add("C");
myList.add("D");
//1. 在列表的指定位置插入元素(第一个参数是下标)
//这个方法使用不多,因为对于ArrayList集合来说效率比较低
myList.add(1, "king");
//迭代
Iterator it = myList.iterator();
while (it.hasNext()){
Object elt = it.next();
System.out.println(elt); //A B C D
}
//2. 根据下标获取元素
Object firstObj = myList.get(0);
System.out.println(firstObj);
//因为有下标,所以List集合有自己比较特殊的遍历方式
//通过下标遍历,(List集合特有的方法)
for (int i = 0; i < myList.size(); i++) {
Object obj = myList.get(i);
System.out.println(obj);
}
//3. 获取指定对象第一次出现处的索引
System.out.println(myList.indexOf("king")); // 1
//4. 获取指定对象最后一次出现处的索引
System.out.println(myList.lastIndexOf("C")); //3
//5. 删除指定下标位置的元素
myList.remove(0);
System.out.println(myList.size());
System.out.println("=====================");
//6. 修改指定位置的元素
myList.set(2,"Soft");
//遍历集合
for (int i = 0; i < myList.size(); i++) {
Object obj = myList.get(i);
System.out.println(obj); //king B Soft D
}
}
}
ArrayList集合初始化容量是10
ArrayList集合底层是Object类型的数组Object[]
构造方法:
new ArrayList();
new ArrayList(20);
ArrayList集合的扩容:增长到原容量的1.5倍
数组优点:检索效率高
数组缺点:随机增删元素效率低,向数组末尾添加元素不受影响
集合ArrayList的构造方法:
package com.collection;
import java.util.ArrayList;
import java.util.List;
public class ArrayListTest01 {
public static void main(String[] args) {
//默认初始化容量是10
List list1 = new ArrayList();
//集合中的size()方法是获取当前集合中元素的个数,而不是获取集合的容量
System.out.println(list1.size()); //0
//指定初始化容量,数组长度为20
List list2 = new ArrayList(20);
System.out.println(list2.size()); //0
}
}
package com.collection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
public class ArrayTest02 {
public static void main(String[] args) {
//默认初始化容量10
List myList1 = new ArrayList();
//指定初始化容量20
List myList2 = new ArrayList(20);
Collection c = new HashSet();
c.add(100);
c.add(200);
c.add(900);
c.add(50);
//通过这个构造方法就可以将HashSet集合转换为List集合
List myList3 = new ArrayList(c);
for (int i = 0; i < myList3.size(); i++) {
System.out.println(myList3.get(i)); //50 100 900 200
}
}
}
本质是:双向链表
链表优点:
链表缺点:不能通过数学表达式计算被查找元素的内存地址,每一次查找都是从头结点开始遍历,直到找到为止,所以LinkedList集合检索/查找效率较低
ArrayList:把检索效率发挥到了极致(末尾添加元素效率还是很高的)
LinkedList:把随机增删发挥到了极致
package com.collection;
import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
public class LinkedListTest01 {
public static void main(String[] args) {
//LinkedList集合底层也是有下标的
//注意:ArrayList之所以检索效率比较高,不是单纯因为下标的原因,是因为底层数组发挥的作用
//LinkedList集合照样有下标,但是检索/查找某个元素的时候效率比较低,因为只能从节点开始一个一个遍历
List list = new LinkedList();
list.add("a");
list.add("b");
list.add("c");
for (int i = 0; i < list.size(); i++) {
Object obj = list.get(i);
System.out.println(obj);
}
//LinkList集合有初始化容量吗?
//最初这个链表中没有任何元素,first和last引用都是null
//不管是LinkedList还是ArrayList,以后写代码时不需要关心具体是哪个集合
//因为我们要面向接口编程,调用的方法都是接口中的方法
//List list2 = new ArrayList(); 这样写底层用了数组
List list2 = new LinkedList(); //这样写底层用来双向链表
list2.add("123");
list2.add("456");
list2.add("789");
for (int i = 0; i < list2.size(); i++) {
System.out.println(list2.get(i));
}
}
}
底层也是一个数组
初始化容量:10
怎么扩容?
Vector在所有的方法都是线程同步的,都带有synchronized关键字,是线程安全的,效率较低,使用较少
怎么将一个线程不安全的ArrayList集合转换成线程安全的呢?
package com.collection;
import java.util.*;
public class VectorTest {
public static void main(String[] args) {
//创建一个Vector集合
//Vector vector = new Vector();
List vector = new Vector();
//添加元素
//默认容量10个
vector.add(1);
vector.add(2);
vector.add(3);
vector.add(4);
vector.add(5);
vector.add(5);
vector.add(6);
vector.add(7);
vector.add(8);
vector.add(9);
vector.add(10);
//满了之后扩容(扩容是)
vector.add(11);
Iterator it = vector.iterator();
while (it.hasNext()) {
Object obj = it.next();
System.out.println(obj);
}
//这个可能以后要使用
List mylist = new ArrayList(); //非线程安全
//变成线程安全
Collections.synchronizedList(mylist);
//mylist集合就是线程安全的
mylist.add("111");
mylist.add("222");
mylist.add("333");
}
}
存储元素特点:
package com.collection;
import java.util.HashSet;
import java.util.Set;
public class HashSetTest01 {
public static void main(String[] args) {
//演示一下HashSet集合特点
Set<String> stringSet = new HashSet<>();
//添加元素
stringSet.add("hello1");
stringSet.add("hello4");
stringSet.add("hello3");
stringSet.add("hello2");
stringSet.add("hello3");
stringSet.add("hello4");
//遍历
/*
结果:
hello1
hello4
hello2
hello3
*/
for(String s:stringSet){
System.out.println(s);
}
}
}
TreeSet集合存储元素特点:
package com.collection;
import java.util.Set;
import java.util.TreeSet;
public class TreeSetTest01 {
public static void main(String[] args) {
//创建集合对象
Set<String> strs = new TreeSet<>();
//添加元素
strs.add("A");
strs.add("B");
strs.add("Z");
strs.add("Y");
strs.add("Z");
strs.add("M");
//遍历
/*
结果:
A
B
M
Y
Z
*/
for (String s:strs) {
System.out.println(s);
}
}
}
java.util.Map接口中常用的方法:
package com.collection;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/*
Map集合中常用的方法
V put(K key, V value)向Map集合中添加键值对
V get(Object key)通过key获取value
void clear() 清空Map集合
boolean containsKey(Object key) 判断Map中是否包含某个key
boolean containsValue(Object value) 判断Map中是否包含某个Value
boolean isEmpty() 判断Map集合中元素个数是否为0
V remove(Object key)通过key删除键值对
int size() 获取Map集合中键值对的个数
Collection values() 获取Map集合中所有的value,返回一个Collection
Set keySet() 获取Map集合所有的key(所有的键是一个Set集合)
Set> entrySet() 将Map集合转换为Set集合
假设现在有一个Map集合,如下所示:
map1集合对象
key value
-------------------
1 zhangsan
2 lisi
3 wangwu
4 zhaoliu
Set set = map1.entrySet();
set集合对象
1=zhangsan
2=lisi
3=wangwu
4=zhaoliu
【注意:Map集合通过entrySet()方法转换成的这个Set集合,Set集合中元素的类型是Map.Entry】
Map.Entry和String一样,都是一种类型的名字,只不过:Map.Entry是静态内部类,是Map中的静态内部类
*/
public class MapTest01 {
public static void main(String[] args) {
//创建Map集合对象
Map<Integer,String> map = new HashMap<>();
//向Map集合中添加键值对
map.put(1,"zhangsan"); //1在这里进行了自动装箱
map.put(2,"lisi");
map.put(3,"wangwu");
map.put(4,"zhaoliu");
//通过key获取value
String value = map.get(2);
System.out.println(value);
//获取键值对的数量
System.out.println("键值对的数量:" + map.size()); //4
//通过key删除key-value
map.remove(2);
System.out.println("键值对的数量:" + map.size()); //3
//判断是否包含某个key
//contains方法底层调用的都是equals进行比对的,所以自定义的类型需要重写equals方法
System.out.println(map.containsKey(4)); //true
//判断是否包含某个value
System.out.println(map.containsValue("wangwu")); //true
//获取所有的value
Collection<String> values = map.values();
for (String s:values){
System.out.println(s);
}
//清空map集合
map.clear();
System.out.println("键值对的数量:" + map.size()); //0
//判断是否为空
System.out.println(map.isEmpty()); //true
}
}
package com.collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class MapTest02 {
public static void main(String[] args) {
//第一种方式:获取所有的key,通过遍历key,来遍历value
Map<Integer,String> map = new HashMap<>();
map.put(1,"zhangsan");
map.put(2,"lisi");
map.put(3,"wangwu");
map.put(4,"zhaoliu");
//遍历Map集合
//获取所有的key,所有的key是一个Set集合
Set<Integer> keys = map.keySet();
//遍历key,通过key获取value
//迭代器可以
Iterator<Integer> it = keys.iterator();
while (it.hasNext()){
Integer key = it.next();
String value = map.get(key);
System.out.println(key + "=" + value);
/*
1=zhangsan
2=lisi
3=wangwu
4=zhaoliu
*/
}
//foreach也可以
for (Integer key:keys){
System.out.println(key + "=" + map.get(key));
}
//第二种方式:Set> entrySet()
//将Map集合直接全部转换为Set集合
//Set集合中元素的类型是:Map.Entry
Set<Map.Entry<Integer,String>> set = map.entrySet();
//遍历Set集合,每一次取出一个Node
//迭代器
Iterator<Map.Entry<Integer,String>> it2 = set.iterator();
while (it2.hasNext()){
Map.Entry<Integer,String> node = it2.next();
Integer key = node.getKey();
String value = node.getValue();
System.out.println(key + "=" + value);
}
//foreach方式
//这种方式效率比较高,因为获取key和value都是直接从node对象中获取的属性值
//这种方式适合大数据量
for (Map.Entry<Integer,String> node : set){
System.out.println(node.getKey() + "=" + node.getValue());
}
}
}
HashMap集合:
哈希表是一个怎样的数据结构?
HashMap集合底层的源代码
public class HashMap{
//HashMap底层实际上就是一个数组(一维数组)
Node<K,V> table;
//静态内部类HashMap.Node
static class Node<K,V> {
final int hash; //哈希值(哈希值是key的hashCode()方法执行结果。hash值通过哈希函数/算法,可以转化存储成数组下标)
final K key; //存储到Map集合中的那个key
V value; //存储到Map集合中的那个value
Node<K,V> next; //下一个节点的内存地址
}
map.put(k,v)实现原理:
v = map.get(k)实现原理:
为什么哈希表的随机增删,以及查询效率都很高?
放在HashMap集合key部分的元素其实就是放到HashSet集合中了,所有HashSet集合中的元素也需要同时重写HashCode()+equals()方法
注意:同一个单向链表上所有节点的hash相同,因为他们的数组下标是一样的。但同一个链表上k和k的equals方法肯定返回的是false,都不相等
哈希表HashMap使用不当无法发挥性能!
HashMap集合的默认初始化容量是16,默认加载因子是0.75,达到75%开始扩容
package com.collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
public class HashMapTest01 {
public static void main(String[] args) {
//测试HashMap集合key部分的元素特点
//Integer是key,它的hashCode和equals都重写了
Map<Integer,String> map = new HashMap<>();
map.put(1111,"zhangsan");
map.put(6666,"lisi");
map.put(7777,"wangwu");
map.put(2222,"zhaoliu");
map.put(2222,"king"); //key重复的时候value会自动覆盖
System.out.println(map.size()); //4
//遍历Map集合
Set<Map.Entry<Integer,String>> set = map.entrySet();
for (Map.Entry<Integer,String> entry : set){
//验证结果:HashMap集合key部分元素:无序不可重复
System.out.println(entry.getKey() + "=" + entry.getValue());
}
}
}
package com.bean;
import java.util.HashSet;
import java.util.Set;
/*
1. 向Map集合中存,以及从Map集合中取,都是县调用key的hashCode方法,然后在调用equals方法
equals方法有可能调用,也有可能不会调用
2. 注意:如果一个类的equals方法重写了,那么hashCode()方法必须重写,
并且equals方法返回如果是true,hashCode()方法返回的值必须一样
equals方法返回true表示两个对象相同,在同一个单向链表上比较
那么对于同一个单向链表上的节点来说,他们的哈希值都是相同的
所有hashCode()方法的返回值也应该是相同的
3. 放在hashCode集合key部分,以及放在hashSet集合中的元素,需要同时重写hashCode方法和equals方法
*/
public class HashMapTest02 {
public static void main(String[] args) {
Student s1 = new Student("zhangsan");
Student s2 = new Student("zhangsan");
//重写equals方法之前是false
System.out.println(s1.equals(s2)); //false
//重写equals方法之后是true
System.out.println(s1.equals(s2));
System.out.println("s1的hashCode="+s1.hashCode()); //22307196
System.out.println("s2的hashCode="+s2.hashCode()); //10568834
//s1.equals(s2)已经是true了,表示s1和s2是一样的,那么王hashCode集合中方法的话,
//按说只能放进去一个(HashSet集合特点无序不可重复)
Set<Student> students = new HashSet<>();
students.add(s1);
students.add(s2);
System.out.println(students.size()); //这个结果按说应该是1,但是结果为2
//重写equals和hashCode之后hashCode都为-1432604525
}
}
package com.bean;
import java.util.Objects;
public class Student {
private String name;
public Student() {
}
public Student(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//重写equals (如果名字一样,表示同一个学生)
/*public boolean equals(Object object){
if (object == null || !(object instanceof Student)) return false;
if (object == this) return true;
Student student = (Student)object;
if (this.name.equals(student.name)) return true;
return false;
}*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Student student = (Student) o;
return Objects.equals(name, student.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
package com.bean;
import java.util.Hashtable;
import java.util.Map;
/*
Hashtable的key和value都不能为null的
HashMap集合的key和value都是可以为null的
Hashtable方法都带有synchronized:线程安全的
线程安全有其他的方案,这个Hashtable对线程的处理导致效率较低,使用少
Hashtable和HashMap一样,底层都是哈希表数据结构
*/
public class HashTableTest01 {
public static void main(String[] args) {
Map map = new Hashtable();
map.put(null,"123"); //出现异常
}
}
package com.collection;
import java.util.Properties;
/*
掌握Properties属性类对象的相关方法
Properties是一个Map集合,继承Hashtable,Properties的key和value都是String类型
Properties被称为属性类对象
Properties是线程安全的
*/
public class PropertiesTest01 {
public static void main(String[] args) {
//创建一个Properties对象
Properties properties = new Properties();
//需要掌握Properties的两个方法,一个存,一个取
properties.setProperty("url","jdbc:mysql//localhost:3306");
properties.setProperty("username","root");
properties.setProperty("password","123");
// 通过key获取value
String url = properties.getProperty("url");
String username = properties.getProperty("username");
String password = properties.getProperty("password");
System.out.println(url);
System.out.println(username);
System.out.println(password);
}
}
package com.collection;
import java.util.TreeSet;
/*
*/
public class TreeSetTest02 {
public static void main(String[] args) {
//创建一个TreeSet集合
TreeSet<String> ts = new TreeSet<>();
//添加String
ts.add("zhangsan");
ts.add("lisi");
ts.add("wangwu");
//遍历
for (String s:ts){
//安装字典顺序,升序
System.out.println(s);
}
TreeSet<Integer> ts2 = new TreeSet<>();
ts2.add(100);
ts2.add(200);
ts2.add(900);
ts2.add(10);
ts2.add(150);
for (Integer elt:ts2){
System.out.println(elt);
}
}
}
lisi
wangwu
zhangsan
10
100
150
200
900
package com.collection;
import java.util.TreeSet;
public class TreeSetTest03 {
public static void main(String[] args) {
Customer c1 = new Customer(32);
Customer c2 = new Customer(20);
Customer c3 = new Customer(30);
Customer c4 = new Customer(25);
//创建TreeSet集合
TreeSet<Customer> customers = new TreeSet<>();
//添加元素
customers.add(c1);
customers.add(c2);
customers.add(c3);
customers.add(c4);
//遍历
for (Customer c : customers){
System.out.println(c);
}
}
}
/*
放在TreeSet集合中的元素需要实现java.lang.Comparable接口
并且实现compareTo方法,equals可以不写
*/
class Customer implements Comparable<Customer>{
int age;
public Customer(int age) {
this.age = age;
}
//需要在这个方法中编写比较的逻辑:按照什么进行比较
//k.compareTo(t.key)
//拿着参数k和集合中每一个k进行比较,返回值可能是><=0
@Override
public int compareTo(Customer c) { //c1.compareTo(c2);
//this是c1
//c是c2
//c1和c2比较的时候,就是this和c比较
/*int age1 = this.age;
int age2 = c.age;
if (age1 == age2){
return 0;
} else if (age1>age2){
return -1;
} else {
return 1;
}*/
return this.age - c.age; //=0 >0 <0
}
public String toString(){
return "Customer[age="+age+"]";
}
}
Customer[age=20]
Customer[age=25]
Customer[age=30]
Customer[age=32]
比较规则怎么写?
package com.collection;
import java.util.TreeSet;
/*
先按照年龄升序,如果年龄一样再按照姓名升序
*/
public class TreeSetTest04 {
public static void main(String[] args) {
TreeSet<Vip> vips = new TreeSet<>();
vips.add(new Vip("zhangsan",20));
vips.add(new Vip("zhangsi",20));
vips.add(new Vip("lisi",20));
vips.add(new Vip("king",18));
for (Vip vip : vips){
System.out.println(vip);
}
}
}
class Vip implements Comparable<Vip>{
String name;
int age;
public Vip(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Vip{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public int compareTo(Vip v) {
if (this.age == v.age) {
//年龄相同按照名字排序
//姓名是String类型,可以直接比较,调用compareTo来完成比较
return this.name.compareTo(v.name);
} else {
return this.age - v.age;
}
}
}
Vip{name='king', age=18}
Vip{name='lisi', age=20}
Vip{name='zhangsan', age=20}
Vip{name='zhangsi', age=20}
CompareTo方法的返回值很重要:
TreeSet集合中元素可排序的第二种方式:使用比较器的方式
放到TreeSet或者TreeMap集合key部分的元素想做到排序,包括两种方式:
Comparable和Comparator怎么选择?
package com.collection;
import java.util.Comparator;
import java.util.TreeSet;
public class TreeSetTest05 {
public static void main(String[] args) {
//创建TreeSet集合的时候,需要使用这个比较器
//TreeSet wuGuis = new TreeSet<>(); 这样不行,没有通过构造方法传递一个比较器进去
//给构造方法传递一个比较器
//方式一:TreeSet wuGuis = new TreeSet<>(new WuGuiComparator());
//方式二:大家可以使用匿名内部类的方式(这个类没有名字。直接new接口)
TreeSet<WuGui> wuGuis = new TreeSet<>(new Comparator<WuGui>() {
@Override
public int compare(WuGui o1, WuGui o2) {
return o1.age - o2.age;
}
});
wuGuis.add(new WuGui(1000));
wuGuis.add(new WuGui(800));
wuGuis.add(new WuGui(100));
for (WuGui wuGui : wuGuis){
System.out.println(wuGui);
}
}
}
class WuGui {
int age;
public WuGui(int age) {
this.age = age;
}
@Override
public String toString() {
return "WuGui{" +
"age=" + age +
'}';
}
}
//单独在这里编写一个比较器
//比较器实现java.util.Comparator接口。(Comparable是java.lang包下的。Comparator是java.util包下的)
/*
方式一:
class WuGuiComparator implements Comparator{
@Override
public int compare(WuGui o1, WuGui o2) {
return o1.age - o2.age;
}
}*/
WuGui{age=100}
WuGui{age=800}
WuGui{age=1000}
package com.collection;
import java.util.*;
public class CollectionsTest {
public static void main(String[] args) {
//ArrayList集合不是线程安全的
List<String> list = new ArrayList<>();
//变成线程安全
Collections.synchronizedList(list);
//排序
list.add("abc");
list.add("abx");
list.add("sbc");
list.add("abe");
Collections.sort(list);
for (String s: list){
System.out.println(s);
}
List<Dog> dogs = new ArrayList<>();
dogs.add(new Dog(1000));
dogs.add(new Dog(800));
dogs.add(new Dog(100));
//注意:对list集合中元素排序,需要保证list集合中元素实现了:Comparable接口
Collections.sort(dogs);
for (Dog dog : dogs){
System.out.println(dog);
}
//对Set集合怎么排序?
Set<String> set = new HashSet<>();
set.add("zhangsan");
set.add("zhangs");
set.add("lisi");
//将Set集合转换成List集合
List<String> myList = new ArrayList<>(set);
}
}
class Dog implements Comparable<Dog>{
int age;
public Dog(int age) {
this.age = age;
}
@Override
public int compareTo(Dog o) {
return this.age - o.age;
}
@Override
public String toString() {
return "Dog{" +
"age=" + age +
'}';
}
}
JDK5.0之后推出的新特性:泛型
使用泛型的好处:
使用泛型的缺点:
package com.collection;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest01 {
public static void main(String[] args) {
/*
//不使用泛型机制,分析程序缺点
List myList = new ArrayList();
//准备对象
Cat c = new Cat();
Bird b = new Bird();
//将对象添加到集合当中
myList.add(c);
myList.add(b);
//遍历集合,取出每个Animal,让他move
Iterator it = myList.iterator();
while (it.hasNext()) {
//没有这个语法,通过迭代器取出的就是Object
//Animal a = it.next();
Object obj = it.next();
//obj中没有move方法,无法调用,需要向下转型
if (obj instanceof Animal) {
Animal a = (Animal) obj;
a.move();
}
}
*/
//使用JDK5.0之后的泛型机制
//使用泛型List之后,表示List集合中只允许存储Animal类型的数据
//用泛型来指定集合中存储的数据类型
List<Animal> myList = new ArrayList<Animal>();
//指定List集合中只能存储Animal,那么存储String就编译报错了
//这样用了泛型之后,集合中元素的数据类型更加统一了
//myList.add("abc");
Cat c = new Cat();
Bird b = new Bird();
myList.add(c);
myList.add(b);
//获取迭代器
//这个表示迭代器迭代的是Animal类型
Iterator<Animal> it = myList.iterator();
while (it.hasNext()) {
//使用泛型之后,每一次迭代返回的数据都是Animal类型
Animal a = it.next();
//这里不需要进行强制类型转换了。直接调用
a.move();
//调用子类型特有的方法还是需要向下转换的
Animal a1 = it.next();
if (a1 instanceof Cat) {
Cat c1 = (Cat)a;
c1.catchMouse();
}
if (a1 instanceof Bird) {
Bird b1 = (Bird) a1;
b1.fly();
}
}
}
}
class Animal{
//父类自带方法
public void move(){
System.out.println("动物在移动");
}
}
class Cat extends Animal{
//子类特有方法
public void catchMouse(){
System.out.println("猫抓老鼠");
}
}
class Bird extends Animal{
//子类特有方法
public void fly(){
System.out.println("鸟儿飞翔");
}
}
JDK8之后引入:自动类型推断机制(又称钻石表达式)
package com.collection;
import sun.corba.Bridge;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class GenericTest02 {
public static void main(String[] args) {
//ArrayList<这里的类型会自动推断>(),前提是JDK8之后才允许
//自动类型推断,钻石表达式
List<Animal> myList = new ArrayList<>();
myList.add(new Animal());
myList.add(new Cat());
myList.add(new Bird());
//遍历
Iterator<Animal> it = myList.iterator();
while (it.hasNext()) {
Animal a = it.next();
a.move();
}
List<String> stringList = new ArrayList<>();
//类型不匹配
//stringList.add(new Cat());
//类型不匹配
//stringList.add(123);
}
}
自定义泛型的时候<>,尖括号中的是一个标识符,随便写。
java源代码中经常出现的是:< E>和< T>
package com.collection;
public class GenericTest03<标识符随便写> {
public void doSome(标识符随便写 o){
System.out.println(o);
}
public static void main(String[] args){
//new对象的时候指定了泛型是:String类型
GenericTest03<String> gt = new GenericTest03<>();
//类型不匹配
//gt.doSome(100);
gt.doSome("abc");
GenericTest03<Integer> gt2 = new GenericTest03<>();
gt2.doSome(100);
MyIterator<String> mi = new MyIterator<>();
String s1 = mi.get();
MyIterator<Animal> mi2 = new MyIterator<>();
Animal a = mi2.get();
//不用泛型就是Object类型
GenericTest03 gt3 = new GenericTest03();
gt3.doSome(new Object());
}
}
class MyIterator<T>{
public T get(){
return null;
}
}