1、集合式一个容器,可以用来容纳其它类型的数据
2、集合不能直接存储基本数据类型,集合也不能直接存储java对象,它存的是java对象的内存地址。如果存100,那也是java自动装箱Intiger之后再存的
集合在java中本身是一个容器,是一个对象。
集合中任何时候存储的都是“引用”。
在java中集合分为两大类,一类是单个方式存储元素:他们的超级父类接口:java.util.Collection;
一类是键值对的方式存储元素。。。。。。。。。java.util.Map;
关于java.uit collection中常用的方法
1、collection中能存储什么元素?
collection中可以存储object的所有子类型(集合中不能直接存储基本数据类型,也不能直接存储java对象,只是存储java对象的内存地址)
2、collection中长用的方法见下表,这里的方法是集合的公共方法,后面的所有集合都可以用下面的方法
返回值类型 | 方法 | 作用 |
---|---|---|
boolean | add(Object e) | 向集合尾部添加元素(这里无论元素是否添加成功,都返回true) |
int | size() | 判断集合的长度 |
void | clear() | 清空元素 |
boolean | contains(Object e) | 判断集合中是否包含元素e,返回true。false |
boolean | remove(Object e) | 删除集合中的某个元素 |
boolean | isEmpty() | 判断集合是否为空 |
Iterator | iterator() | 获取一个迭代器,iterator()方法,返回Iterator对象 |
Object[] | toArray() | 调用这个方法可以把集合转换为数组 |
boolean | addAll(Collection c) | 将一个集合c中元素全部存储到当前集合中 |
contains()比较的时候底层调用了equals方法,如果我们自己创建的类没有重写equals方法,那么在两个new出来的对象比较的时候,会采用最底层的equals()比较两个对象的内存地址,就会返回false,
所以放在集合中的元素需要重写equals()方法。
关于
迭代器,用来获取集合中所有的数据(就是以前写的for循环),迭代器就相当于一个指针,一开始并没有指向第一个元素,可以理解为放在了第一个元素之前的位置
要想使用迭代器,首先必须获取集合对象的迭代器
Iterator it = c.iterator();
迭代器是一个对象,对象中有三个常用的方法,这三个方法都是迭代对象 it 的方法
返回值类型 | 方法 | 作用 |
---|---|---|
boolean | hasNext() | 如果仍有元素可以迭代,则返回true |
Object | next() | next会让迭代器向下走一位,并且返回当前指向的元素 |
void | remove() | 从迭代器中删除当前元素 |
有序:List集合中存储的原素有下标,从0开始,以1递增
可重复:存过的数据还能再存进去
返回值类型 | 方法 | 作用 |
---|---|---|
Object | get() | 返回列表中指定位置的元素 |
int | indexOf(Object o) | 返回列表中第一次出现的指定元素的索引,如果没有,返回-1 |
int | lastIndexOf(Object o) | 返回列表中最后一次出现的指定元素的索引,如果没有,返回-1 |
Object | remove(int index) | 移出列表中指定位置的元素 |
Object | set(int index, element) | 用指定元素替换列表中指定位置的元素 |
void | add(int index, element) | 在列表的指定位置添加元素(重载方法) |
for(int i = 0; i<list.size(); i++){
System.out.println(list.get(i));
}
ArrayList集合底层是Object类型的数组,怎么优化?
尽可能少的扩容,因为扩容数组的效率比较低,建议在使用ArrayList集合的时 候预估计元素的个数,给定一个初始化容量
ArrayList集合初始化容量是0,当添加第一个元素之后,会默认初识化10(看源码)
ArrayList在自动扩容时一次扩容1.5倍(看源码)
ArrayList的构造方法:
List list = new ArrayList();//无参
List list2 = new ArrayList(100);//初始化容量为100
List list3 = new ArrayList(c);//将另一个集合传入新构造的集合中,这个传进来的也可以是Hashset
链表的优点:
由于链表上的元素空间存储位置不连续,所以随机增删元素的时候不会有大量元素位移,因此随机增删效率高
链表的缺点:
不能通过数学表达式计算出被查找元素的内存地址,每一次查找都是从头开始遍历,所以他的检索/查找效率低
vector和ArrayList比较:
相同点:
底层都是采用的数组结构
不同点: vector ArrayList
是线程安全的 是非线程安全的
初始化容量是10,每次扩容2倍 初始化0,添加第一个元素变为10,每次扩容1.5倍
使用一个集合工具类:
java.util.Collections;//这是集合工具类
java.util.Collection;//这是集合接口
用法:
List list = new ArrayList();//非线程安全的
Collections.synchronizedList(list);//变成线程安全的
在集合中,我们可以存储任意的对象的引用,这样就会导致集合中的元素比较杂乱,导致我们在集合中循环/迭代取出的元素都是 Object 类。
为了满足有时候我们集合中就只为了存储同一种类型的机制,java为我们提供了泛型机制,这样我们创建的集合就只能存储我们泛型指定的数据类型来存储,,在迭代取出元素的时候,也都是这个类型的元素(结合多态使用会更好)
//创建一个Animal泛型的集合
List<Animal> list = new ArrayList<Animal>();
//这个表示迭代器迭代的是Animal类型
Iterator<Animal> it = list.iterator();
List<Animal> list = new ArrayList<>();//就是后面的集合会自动推断,ArrayList<>括号中可以不加Animal
public class DEMO <E>{ // E只是一个标识符,可以随便写什么,起作用的是<>但是下面要用的E的地方必须和上面写的内容保持一致,E可以用在方法的传参,也可以用在返回值类型的声明。
public void doSome(E e){
System.out.println(e);
}
public static void main(String[] args) {
DEMO<String> demo = new DEMO<>();//在new对象的时候在类的后面加上泛型,这就是自定义泛型
demo.doSome("这里只能传String");
}
}
//以下是数组使用语法
/*for(元素类型 变量名 :数组或集合){
System.out.println(变量名);
}*/
int[] arr = {2,3,55,32,12,534};
for(int date :arr){//date 就是数组中的元素(数组中的每一个元素)
System.out.println(date);
}
//以下是集合使用语法
List<String> str = new ArrayList<>();
for(String s : str){
System.out.println(s);
}
1、Map和collection没有继承关系
2、Map集合以key和value的方式 存储数据:键值对key和value都是引用数据类型,key和value都是存储对象的内存地址。key起到主导的地位,value是key的一个附属品
返回值类型 | 方法名 | 作用 |
---|---|---|
void | clear() | 从此映射中移出所有映射关系 |
V | put(K key, V value) | 向map集合中添加键值对 |
Value | get(Object key) | 通过key返回其对应的value,没有则返回Null |
V | remove(Object key) | 通过key删除键值对 |
boolean | isEmpty() | 判断集合是否为空 |
int | size() | 获取Map集合中键值对的个数 |
boolean | containsValue(Object value) | 判断是否包含某个Value |
boolean | containsKey(Object key) | 判断是否包含某个key |
Set | keySet() | 获取Map集合所有的key,返回的是一个Set集合 |
Collection | values() | 获取Map集合所有的value,返回的是一个Collection集合 |
Set |
entrySet() | 将Map集合转换成Set集合 |
Set>详解:
假设现在有一个Map1集合: key value
1 zhangsan
2 lisi
3 wangwu
调用转换方法: Set set1 = Map.entrySet(); 返回的是一个Set集合,里面存储:1=zhangsan 2=lisi 3=wangwu
Map方法的运用
//创建Map对象
Map<Integer,String> map = new HashMap<>();
//向Map集合中添加键值对
map.put(1,"zhangsan");//在这里1仍然会自动装箱
map.put(2,"lisi");
map.put(3,"wangwu");
//通过key获取value
String value = map.get(2);
//获取键值对的数量
int size = map.size();
//通过key删除键值对
map.remove(2);
//判断是否包含某个key 注意:contains方法比较的时候,底层都是调用的equals方法进行比较的,所以我们在存自己创建的对象时一定要重写equals方法
boolean b1 = map.containsKey(1);
//判断是否包含某个value
boolean b2 = map.containsValue("wangwu");
//清空Map集合
map.clear();
//判断是否为空
boolean b3 = map.isEmpty();
//获取Map集合中所有的value
Collection<String> values = map.values();
//第一种,获取Map集合所有的key,通过遍历key,来遍历value
//获取所有的key,所有的key是一个Set集合
Set<Integer> keys = map.keySet();
//通过迭代器,遍历key,通过key获取value 通过foreach,遍历key,通过key获取value
Iterator<Integer> it = keys.iterator(); for(Integer key:keys){
while(it.hasNext()){ String value = map.get(key);
Integer key = it.next(); }
String value = map.get(key);
}
//第二种方式:直接把Map集合全部转换成Set集合,Set集合中元素的类型是Map.Entry();这种方式效率比较高
Set<Map.Entry<Integer,String>> set = map.entrySet();
//迭代器遍历Set集合,每一次取出一个Node foreach循环遍历
Iterator<Map.Entry<Integer,String>> it = set.iterator(); for(Map.Entry<Integer,String> node :set){
while(it.hasNext()){ Integer key = node.getKey();
Map.Entry<Integer,String> node = it.next(); String value = node.getValue();
Integer key = node.getKey(); }
String value = node.getValue();
}
什么是哈希表:
哈希表底层实际上是一个一维数组,这个数组中的每个元素都是一个单向链表。它充分发挥了数组和单向链表的优势(底层结构有点像珠珠帘)
底层原理就像查字典
重点:
放在HaashMap集合key部分的元素,以及放在HashSet集合中的元素,需要同时重写hashCode和equals方法,如果equals方法重写了,hashCode方法必须重写,并且如果equals方法返回值是true,hashCode方法返回值也必须是true。
重写直接用idea生成就行了,但是要注意一定要同时生成。
HashMap集合的默认初始画容量是16,默认加载因子是 0.75(当HashMap集合底层数组的容量达到75%的时候,数组开始扩容)
HashMap集合初始化容量必须是2的倍数,这也是官方推荐的,这是因为达到散列分布均匀,为了提高HashMap集合的存储效率,所必须的。
HashMap是非线程安全的,默认初始画容量是16,默认加载因子是 0.75,扩容之后的容量X2,它的key和value可以存储null
HashTable是线程安全的,默认初始画容量是11,默认加载因子是 0.75,扩容之后的容量X2+1,它的key和value不能存储null
Properitise是一个Map集合,继承HashTable, Properitise的 key 和 value 都是 String 类型的
Properitise被称为属性类对象,是线程安全的
需要掌握两个方法:
存:pro.setProperty("username","root");
取:String s =pro.getProperty("username");
1、TreeSet集合底层其实是一个TreeMap,TreeMap底层其实是一个二叉树
2、放到TreeSet集合中的元素,等于放到了treeMasp集合的key部分
3、TreeSet集合中的元素,无序不可重复,但是可以通过元素的大小顺序自动排序
不仅无法排序,而且还会出异常。因为您自定义的类,没有申明排序的规则。
perty(“username”);
#### 5、TreeSet集合
##### 概述
1、TreeSet集合底层其实是一个TreeMap,TreeMap底层其实是一个二叉树
2、放到TreeSet集合中的元素,等于放到了treeMasp集合的key部分
3、TreeSet集合中的元素,无序不可重复,但是可以通过元素的大小顺序自动排序
##### 对自定义的类型来说,TreeSet可以排序吗?
不仅无法排序,而且还会出异常。因为您自定义的类,没有申明排序的规则。
##### (重点)放在TreeSet集合中的元素需要实现java.lang.Comparable 接口,并且实现compareTo方法。equals方法可以不写
#### 6、自平衡二叉树