容器
容器也是一个集合
- 存储多个数据
- 长度可以随着内容的多少进行改变
- 可以存储任意类型的数据
数组:
- 长度一旦确定不可改变
- 存储相同类型的数据
- 有序(索引)、
- 存储多个数据
collection 存储字符串类型的数据
Map键值对形式数据的 容器体系
自定义容器类
只存储字符串类型的数据
- 添加功能:这里添加数据相当于把数组重新拷贝一份,新加的数据在新数组的后面
- 删除功能:相当于新拷贝一份数组,删除的在新数组中不拷贝
- 修改功能:
- 查询功能
collection接口
容器体系的上层接口,是集中,收集的意思表示一组对象,这些对象也称为collection的元素,一些collection允许有重复的元素,另一些则不允许,一些collection是有序的,而另一些则是无序的。
collection有两个子接口:
- Set中的数据没有顺序,不可重复
List中的数据有顺序,可重复
容器类中可存放不同的类型的数据,但是必须都为引用数据类型的数据,基本数据类型会自动装箱
方法 | 返回值 | 作用 | CRUD |
---|---|---|---|
add(E e) | boolean | 添加元素 | C |
size() | int | 返回容器大小 | R |
contain(Object o) | boolean | 包含(引用类型重写equals) | R |
isEmpty() | boolean | 容器是否为空 | R |
equals(Object o) | boolean | 比较两个容器内容是否相同 | R |
remove(Object o) | boolean | 删除元素 | D |
clear() | void | 清空容器 | D |
toArray() | Object[] | 所有元素存放在数组中 | |
toArray(T[] a) | T[] | ||
retainAll(Collection<?> c) | boolean | 求交集 | |
intertor | Iterator | 遍历 | 遍历 |
<>泛型
使用原因:JDK1.4以前的类型不明确,装入集合的类型都被当做Object对待,从而失去自己的实际类型,从集合去除时往往需要转型,效率低,容易产生错误
优点:增强程序的可读性和稳定性
使用泛型,保留了容器中元素的类型,安全省心的使用容器。
Iterator
Iterator对象称作迭代器,Iterator方法用以返回一个实现了Iterator接口的对象,方便的实现对容器内元素的遍历操作。
Iterator接口定义了如下方法:
boolean hasNext();
判断是否有元素没有被遍历Object next();
返回游标当前位置的元素并将游标移动到下一个位置void remove();
删除游标前面的元素
迭代器的三步骤:
- 获取对象
- 判断是否存在下一个
- 获取元素
List接口
位置允许有元素重复,新增了一些根据索引操作的方法
方法 | 返回值 | 作用 | CRUD |
---|---|---|---|
add( index,E element) | void | 指定位置添加元素 | C增 |
get(int index) | E | 获取指定位置元素(for遍历) | R查 |
indexOf(Object o) | int | 元素第一次出现的 索引(重写equals) | R |
lastIndexOf(Object o) | int | 元素最后一次出现的索引 | R |
set(int ,E) | E | 覆盖元素,返回覆盖前的元素 | U改 |
remove(int,int ) | E | 删除指定索引的元素,返回该元素获取子集合 | D删 |
subList(int,int) | List | 获取子集合 | 其他 |
listIterator() | ListIterator | 可以反向输出 | 遍历 |
List集合遍历
- 普通for循环
- 增强for循环
- 迭代器
- 列表迭代器
ArrayList
ArrayList 是 List 的子类,允许存放重复元素,因此有序。集合中元素被访问的顺序取决于集合的类型。如果对 ArrayList 进行访问,迭代器将从索引 0 开始, 每迭代一次,索引值加 1。然而,如果访问 HashSet 中的元素,每个元素将会按照某种随机的次序出现。虽然可以确定在迭代过程中能够遍历到集合中的所有元素,但却无法预知元素被访问的次序。
-
底层实现:由可变数组实现,通过数组拷贝实现容器可以根据内容进行动态扩容
-
优点:遍历和获取的时候效率高,因为数据根据索引操作效率高
-
缺点:增删效率低,大量涉及到数组拷贝问题
-
扩容:使用Arrays和copyOf方法进行扩容,每次扩容原容量的1.5倍
int newCapacity = oldCapacity + (oldCapacity
-
没有新增方法,可以多态
-
应用场景:单线程环境下,在大量做查询的业务下,适合使用ArrayList容器
LinkedList
- LinkedList 是一种可以在任何位置进行高效地插入和删除操作的有序序列。
- 底层实现:底层是由双向链表结构实现
- 优点:做增删效率高
- 缺点:做查询效率低
- 新增方法:新增了一些关于链表镖头和链表尾部的方法
**removeFirst**()
移除并返回此列表的第一个元素。
**removeLast**()
移除并返回此列表的最后一个元素。
package test14;
//单链表
public class LinkedList {
public static void main(String[] args) {
MyLinkedList my=new MyLinkedList();
my.add("莫问");
my.add("相知");
my.add("花间");
System.out.println(my.size());
System.out.println(my.get(0));
System.out.println(my.get(1));
System.out.println(my.get(2));
}
}
//定义容器类
class MyLinkedList{
//记录链表头节点
private Node head;
//记录容器中数据的个数
private int size;
public MyLinkedList() {
}
//添加数据的方法
public void add(String value){
Node node=new Node(value,null);
//第一次添加,当前节点作为链表头存在
if(head==null){
head=node;
size++;
return;
}
//每次加节点都在链表的尾部添加,当前添加节点赋值给原链表的最后一个节点的nextNode属性
Node temp=head;
//temp指向最后一个节点
while(true){
//temp作为最后一个节点出现,最后一个节点记录下一个节点的地址为null
if(temp.getNextNode()==null){
temp.setNextNode(node);
break;
}
temp=temp.getNextNode();
}
size++;
}
public int size(){
return this.size;
}
//根据索引获取的方法
public String get(int index){
//判断索引
if(index<0||index>size){
return "索引越界";
}
Node temp=head;
for(int i=0;i<index;i++){
//temp指向下一个节点
temp=temp.getNextNode();
}
return temp.getData();
}
}
//节点
class Node{
//存储的数据
private String data;
//下一个节点的地址
private Node nextNode;
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
public Node getNextNode() {
return nextNode;
}
public void setNextNode(Node nextNode) {
this.nextNode = nextNode;
}
public Node(String data, Node nextNode) {
super();
this.data = data;
this.nextNode = nextNode;
}
@Override
public String toString() {
return "Node [data=" + data + ", nextNode=" + nextNode + "]";
}
}
Vector
- Vector(向量)与 ArrayList 底层一致,就是多了线程安全而已,效率较低
- 扩容是每次扩容原容量的2倍
- 应用场景:多线程环境下,保证数据安全,大量做查询适合使用Vector
比较LinkedList, ArrayList, Vector
LinkedList:底层用双向链表实现的 List。特点:查询效率低,增删效率高,线程不安全。
ArrayList:底层用数组实现的 List。特点:查询效率高,增删效率低,线程不安全。
Vector:底层用数组实现的 List,特点:线程安全,效率较低。
线程安全用Vector,线程不安全,查找较多用ArrayList,增删元素较多用LinkedList.
compare比较器
-
内部比较器(自然排序):实现Comparable接口,重写comparaTo方法,在方法中自定义比较规则,默认类型的比较规则,默认升序
p1.compareTo(p2)
,返回值<0 p1<p2 返回值=0 相等 返回值>0 p1>p2
-
外部比较器(自定义比较器):实现接口java.util.Comparator的接口,重写compare()方法,方法中自定义比较规则
- //static void sort(T[] a, Comparator<? super T> c) 第二个参数中定义当前排序的比较规则
-
int compare(T o1, T o2) 比较用来排序的两个参数。
public class Compare {
public static void main(String[] args) {
Person p1 = new Person("王大", 30);
Person p2 = new Person("王二", 20);
Person p3 = new Person("王三", 28);
Person p4 = new Person("王四", 40);
Person p5 = new Person("王五", 20);
Person[] p = { p1, p2, p3, p4, p5 };
System.out.println(Arrays.toString(p));
Arrays.sort(p);
System.out.println(p1.compareTo(p2));//没法比较,默认是Object类型的比较,类型不同
//外部比较器
//static <T> void sort(T[] a, Comparator<? super T> c) 第二个参数中定义当前排序的比较规则
Arrays.sort(p, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
return ((Person) o2).getAge() - ((Person) o1).getAge();
}
});//匿名内部类中重写比较方法
System.out.println(Arrays.toString(p));
}
}
class Person implements Comparable<Person> {
private String name;
private int 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;
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
// 自定义比较,默认试试升序
@Override
public int compareTo(Person o) {
// TODO Auto-generated method stub
return 0;
}
// 内部比较器
/*
* @Override public int compareTo(Person o) { 根据年龄升序排序 return (int)
* (this.getAge() -o.getAge()); //根据年龄降序排序 //return (int) (o.getAge()
* -this.getAge()); }
*/
}
set接口
无序,不含重复元素,
add(E e)
如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。addAll(Collection<? extends E> c)
如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中(可选操作)。clear()
移除此 set 中的所有元素(可选操作)。equals(Object o)
比较指定对象与此 set 的相等性。contains(Object o)
如果 set 包含指定的元素,则返回true
。hashCode()
返回 set 的哈希码值。remove(Object o)
如果 set 中存在指定的元素,则将其移除(可选操作)。size()
返回 set 中的元素数(其容量)。
Set<String> set=new HashSet();
set.add("四海王气闲");
set.add("地方");
set.add("个人股");
set.add("过他");
set.add("过他");
//数据存放顺序和添加的不一定一致,但是一旦确定不会改变
System.out.println(set);//[地方, 四海王气闲, 个人股, 过他]去重且无序
System.out.println(set);//[地方, 四海王气闲, 个人股, 过他]一旦确定不会改变
set.remove("个人股");
//移除
System.out.println(set);
}
}
**HashSet:**底层是由Hashmap维护
-
底层:哈希表(hashtable)
-
特点:查询,增删效率高,但是无序,不可重
-
如果两个对象Hashcode()值相同,不一定是一个对象,需要进一步比较equals()
-
如果两个对象的hashscode()值不相同,肯定不是一个对象
-
自定义引用数据类型去重问题:重写hashcode()和equals()方法,计算桶的位置时根据对象的内容计算而非地址
-
构造方法:
HashSet()
构造一个新的空 set,其底层HashMap
实例的默认初始容量是 16,加载因子是 0.75HashSet(Collection<? extends E> c)
构造一个包含指定 collection 中的元素的新 setHashSet(int initialCapacity)
构造一个新的空 set,其底层HashMap
实例具有指定的初始容量和默认的加载因子(0.75)。HashSet(int initialCapacity, float loadFactor)
构造一个新的空 set,其底层HashMap
实例具有指定的初始容量和指定的加载因子。
public static void main(String[] args) {
//定义一个HashSet容器,存放Person类型的对象,达到去重的效果,认为:对象的所有成员属性值都相同,就是相同的对象
HashSet<Person> set=new HashSet();
set.add(new Person("王大", 20));
set.add(new Person("王二", 40));
set.add(new Person("王三", 26));
set.add(new Person("王二", 40));
System.out.println(set);//没有去重
}
//Person类中
//重写equals并没有去重
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;
}
重写hashcode和equals去重
@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;
}
TreeSet:
-
底层:是TreeMap,红黑树,平衡二叉树的一种
-
优点:默认升序排序
-
使用元素的自然排序对元素进行排序,或者根据创建set时提供的conparator进行排序
-
使用场景:去重,对多个数据存在自定义排序的,没有索引,
- 不想要自定义排序,可用hashset
- 想有索引 ArraysList
- 线程安全 vector
- 增删比较多还有索引,LinkedList
public static void main(String[] args) {
// TreeSet(Comparator<? super E> comparator)
TreeSet<Person> tree = new TreeSet<Person>(new Comparator<Person>() {
@Override // 去重+排序的原则
public int compare(Person o1, Person o2) {
return o1.getAge() - o2.getAge();
}
});
tree.add(new Person("王大", 18));
tree.add(new Person("王二", 17));
tree.add(new Person("王三", 20));
System.out.println(tree);
System.out.println(tree.last());
System.out.println(tree.first());
}
}
Map接口
- 存储键值对类型的数据 k-v ->映射关系
- k的特点: 无序的,不可重复的 -->所有的key,就是一个set集合
- v的特点: 无序的,可重复 --> Collection的特点
- 一个key对象一个value值,如果想要对应多个,多个value值可以存在在一个数组|容器中
- key相同时候,value会覆盖
public static void main(String[] args) {
Map<String, Integer> map = new HashMap();
// 添加
map.put("王大", 20);
map.put("王二", 30);
map.put("王三", 40);
map.put("王四", 50);
map.put("王五", 20);
map.put("王六", 20);
System.out.println(map);
// 移除
map.remove("王三", 40);
System.out.println(map);
// 包含,containsKey(k)和containsVale(v)返回boolean型,
System.out.println(map.containsKey("王四"));
System.out.println(map.containsValue(30));
// 获取 get(k) 得到V
System.out.println(map.get("王大"));// 20
System.out.println(map);
// keySet() 返回所有的key,组成一个set集合
Set<String> set = map.keySet();
System.out.println(set);// [王大, 王五, 王六, 王四, 王二]
// 遍历方式
// 1.for each
// 2.迭代器
Iterator<String> it = set.iterator();
while (it.hasNext()) {
String key = it.next();
System.out.println(key + "," + map.get(key));
}
System.out.println("---------------");
// 获取所有value值,只能拿到value的值,无法获取key
Collection<Integer> col = map.values();
for (Integer in : col) {
System.out.println(in);
}
System.out.println("---------------");
// 3.Set<Map.Entry<K,V>> entrySet()
Set<Map.Entry<String, Integer>> sets = map.entrySet();
for (Map.Entry<String, Integer> entry : sets) {
System.out.println(entry.getKey() + "-->" + entry.getValue());
}
}
HashMap
- 底层: 哈希表的结构
- 初始容量:16
- 加载因子: 0.75
- 扩容:原容量的2倍
- 如果HashMap的key是自定义的引用数据类型,需要对key的数据的类型重写hashCode()和equals()方法,实现去重,value会覆盖
- 如果key相同,value不覆盖–>先判断,如果key相同就不存储,key不相同,才存储
- 如果需求个根据value去重,需要手动定义判断 containsKey() containsValue()
- HashMap 推荐使用 ,线程不安全,增删,查询效率高
- TreeMap 中的数据有按照指定规则进行排序,推荐使用TreeMap
- Hashtable 线程安全的HashMap
- 适用于在Map中插入、删除和定位元素。
- 根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快的访问速度。遍历时,取得数据的顺序是完全随机的。
TreeMap
基于红黑树(Red-Black tree)的 NavigableMap
实现。该映射根据其键的自然顺序进行排序,或者根据创建映射时提供的 Comparator
进行排序,
-
适用于按自然顺序或自定义顺序遍历键(key)。
-
去重和排序都按照比较规则进行操作 内部和外部比较器
properties
- 键值对都是默认String类型的
- 属性列表中每个键及其对应值都是一个字符串。