对象数组
之前我们创建数组存储基本数据类型常量数据,比如创建一个数组来存储整数:int[] arr = new int[3]
;我们要存储String类型的数据,则需要创建String类型的数组:String[] arr=new String[3]
;我们可以按照定义String类型的数组去定义自定义类型的数组。比如:Student类
public class ArrayDemo {
public static void main(String[] args) {
//创建Student类型的数组
Student[] arr=new Student[3];
//创建Student类的对象
Student s1=new Student("heixuanfeng",19);
Student s2=new Student("bandao",18);
Student s3=new Student("zhujiao",20);
//将学生对象存储到数组中
arr[0]=s1;
arr[1]=s2;
arr[2]=s3;
//遍历数组
for (int i = 0; i < arr.length; i++) {
//通过数组名和下标取出Student类的数组中的数据 arr[i]
Student s=arr[i];
//输出数据
System.out.println(s.getName()+"====="+s.getAge());
}
}
}
对象数组的内存图
我们发现上面这样操作比较麻烦,有没有更加简单的,之前学习了三种存储数据的容器:变量 、数组、字符串缓冲区。这里我们学习集合容器。
集合
集合就是一个容器. 是一个长度可变的容器, 底层就是可变数组,可以存放数据。
1、集合与数组区别
- 从长度来讲:
数组:需要固定长度。
集合:长度可以改变,可以根据保存的数据进行扩容。 - 从存储内容上:
数组:可以存储基本类型数据,还可以存储引用类型的数据(比如:String和上述演示的Student类)。
集合:只能存储引用类型的数据,也就是说集合只能存储类的对象。 - 从存储类型上:
数组:只能存储相同类型的数据。
集合:可以存储不同类型的数据,集合中可以存储任意类型的引用数据类型。
集合图解:
解释:
- List , Set, Map都是接口,前两个继承至collection接口,Map为独立接口
- Set下有HashSet,LinkedHashSet,TreeSet
- List下有ArrayList,Vector,LinkedList
- Map下有Hashtable,LinkedHashMap,HashMap,TreeMap
- collection接口下还有个Queue接口,有PriorityQueue类
注意:
1、Queue接口与List、Set同一级别,都是继承了collection接口。LinkedList既可以实现Queue接口,也可以实现List接口。LinkedList实现了Queue接口。Queue接口窄化了对LinkedList的方法的访问权限(即在方法中的参数类型如果是Queue时,就完全只能访问Queue接口所定义的方法 了,而不能直接访问 LinkedList的非Queue的方法),以使得只有恰当的方法才可以使用。
2、SortedSet是个接口,它里面的(只有TreeSet这一个实现可用)元素一定是有序的。
Collection接口
- List子接口:有序,可重复
ArrayList
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程不安全,效率高
Vector
优点: 底层数据结构是数组,查询快,增删慢。
缺点: 线程安全,效率低
LinkedList
优点: 底层数据结构是链表,查询慢,增删快。
缺点: 线程不安全,效率高 - Set子接口:无序,唯一
HashSet
底层数据结构是哈希表。(无序,不可重复)
如何来保证元素唯一性?依赖两个方法:hashCode()和equals()
LinkedHashSet
底层数据结构是链表和哈希表。(FIFO插入有序,唯一)
1.由链表保证元素有序
2.由哈希表保证元素唯一
TreeSet
底层数据结构是红黑树。(唯一,有序)
1.如何保证元素排序的呢? (自然排序,比较器排序)
2.如何保证元素唯一性的呢? (根据比较的返回值是否是0来决定)
TreeMap
TreeMap底层是红黑树结构,作为Map的一员,包含着key–value形式的元素,和HashMap最大的区别是丢进去的东西自动排序。要注意的是默认的是对Key排序,也可以重写Comparator对Value排序,很方便。
// TreeMap继承关系
public class TreeMap<K,V>
extends AbstractMap<K,V>
implements NavigableMap<K,V>, Cloneable, java.io.Serializable
{}
public abstract class AbstractMap<K,V> implements Map<K,V> {}
构造器
(1) 使用无参构造器创建对象,默认会调用Comparable的compareTo方法排序(自然排序)
TreeMap<String, Object> treeMap = new TreeMap<>();
treeMap.put("id", 1);
treeMap.put("name", "tom");
treeMap.put("age", 13);
// {age=13, id=1, name=tom}
System.out.println(treeMap);
// 无参构造器
public TreeMap() {
comparator = null;
}
(2) 使用有参构造器创建对象,且这个参数是Comparator类型参数,可以指定key的比较方式
// 这里指定按了按照key的长度来排序
TreeMap<String, Object> comparatorTreeMap = new TreeMap<>(Comparator.comparingInt(String::length));
comparatorTreeMap.put("id", 1);
comparatorTreeMap.put("name", "tom");
comparatorTreeMap.put("age", 13);
comparatorTreeMap.put("z", 13);
// {z=13, id=1, age=13, name=tom}
System.out.println(comparatorTreeMap);
// 带Comparator参数的构造器
public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}
(3) 构造器可以接收一个map实现类的参数,如果这个map实现类是SortedMap接口实现类,则按照SortedMap中的排序规则进行排序;如果是其它的map,则按照TreeMap默认的排序
HashMap<String, Object> hashMap = new HashMap<>();
hashMap.put("id", 1);
hashMap.put("name", "tom");
hashMap.put("age", 13);
TreeMap<String, Object> map = new TreeMap<>(hashMap);
// {age=13, id=1, name=tom}
System.out.println(map);
// 有参构造,参数是Map类型
public TreeMap(Map<? extends K, ? extends V> m) {
comparator = null;
putAll(m);
}
// putAll 方法的实现
public void putAll(Map<? extends K, ? extends V> map) {
int mapSize = map.size();
// 如果map是SortedMap类型
if (size==0 && mapSize!=0 && map instanceof SortedMap) {
// 将SortedMap类型实现类的comparator赋值给c
Comparator<?> c = ((SortedMap<?,?>)map).comparator();
// 如果传入map的比较器和TreeMap的一致,则按照
if (c == comparator || (c != null && c.equals(comparator))) {
++modCount;
try {
buildFromSorted(mapSize, map.entrySet().iterator(),
null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
return;
}
}
super.putAll(map);
}
(4) 构造器可以接收一个SortedMap类型的参数,按照sortedMap指定的排序规则进行排序
TreeMap<String, Object> param = new TreeMap<>(Comparator.comparingInt(String::length));
param.put("id", 1);
param.put("name", "tom");
param.put("age", 13);
param.put("z", 13);
TreeMap<String, Object> treMap = new TreeMap<>(param);
System.out.println(treMap);
// 有参构造,接收一个SortedMap类型参数
public TreeMap(SortedMap<K, ? extends V> m) {
comparator = m.comparator();
try {
buildFromSorted(m.size(), m.entrySet().iterator(), null, null);
} catch (java.io.IOException cannotHappen) {
} catch (ClassNotFoundException cannotHappen) {
}
}
常用方法
TreeMap<String, Object> treeMap = new TreeMap<>();
// 新增数据,如果key判断之后返回0,则会替换掉value
treeMap.put("name", "lucy");
treeMap.put("age", 18);
// key 不允许null 会报空指针异常
treeMap.put(null, 18);
// 获取entrySet进行遍历
Set<Map.Entry<String, Object>> entries = treeMap.entrySet();
for (Map.Entry<String, Object> entry : entries) {
// name - lucy
System.out.println(entry.getKey() + " - " + entry.getValue());
}
// forEach进行遍历 name - lucy
treeMap.forEach((x, y) -> System.out.println(x + " - " + y));
// 获取keySet进行遍历
Set<String> keys = treeMap.keySet();
for (String key : keys) {
// name - lucy
System.out.println(key + " - " + treeMap.get(key));
}
// 返回与该键至少大于或等于给定键的Entry,如果不存在这样的键的键值映射,则返回null相关联
Map.Entry<String, Object> entry = treeMap.ceilingEntry("name");
if (!Objects.isNull(entry)){
System.out.println(entry.getValue());
}
treeMap.remove("name");
treeMap.replace("age", 19);
treeMap.clear();
put方法源码
public V put(K key, V value) {
Entry<K,V> t = root;
// 如果root是null,说明容器中没元素
if (t == null) {
// key进行类型检查,如果比较器是null,则自然排序,否则指定排序
compare(key, key); // type (and possibly null) check
// 创建Entry对象封装数据
root = new Entry<>(key, value, null);
size = 1;
modCount++;
return null;
}
int cmp;
Entry<K,V> parent;
// split comparator and comparable paths
Comparator<? super K> cpr = comparator;
// 比较器不为null
if (cpr != null) {
do {
parent = t;
// 使用比较器进行比较
cmp = cpr.compare(key, t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
// 如果比较返回0说明是相等,替换旧值
return t.setValue(value);
} while (t != null);
}
else {
// key 不能为null
if (key == null)
throw new NullPointerException();
@SuppressWarnings("unchecked")
// 自然排序
Comparable<? super K> k = (Comparable<? super K>) key;
do {
parent = t;
cmp = k.compareTo(t.key);
if (cmp < 0)
t = t.left;
else if (cmp > 0)
t = t.right;
else
return t.setValue(value);
} while (t != null);
}
// 封装数据
Entry<K,V> e = new Entry<>(key, value, parent);
if (cmp < 0)
parent.left = e;
else
parent.right = e;
fixAfterInsertion(e);
size++;
modCount++;
return null;
}
Entry 是TreeMap的静态内部类
static final class Entry<K,V> implements Map.Entry<K,V> {
K key;
V value;
Entry<K,V> left;
Entry<K,V> right;
Entry<K,V> parent;
boolean color = BLACK;
}