Map集合
- Map类型的集合称为键值对集合。
Map分为 HashMap,TreeMap ,Hashtable 。
a. HashMap:线程不安全,按照hash码的值进行排序并允许使用 null 值和 null 键 ,hashmap的执行速度要高于TreeMap.
b. TreeMap:键不能为null, 根据键的值使用自然排序的方式升序排序,可以使用Comparator进行手动设置排序方式。
c. Hashtable:线程安全,不允许使用null,键值都不能为null 。
- 键值对 : 一个建对应一个值(键值都是object) ,键不能重复 。
一.HashMap(hashset)
- HashMap ,初始容量16,加载因子0.75,扩容倍数2倍
1.构造方法
- HashMap() 构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。
- HashMap(int initialCapacity) 构造一个带指定初始容量和默认加载因子 (0.75) 的空 HashMap。
- HashMap(int initialCapacity, float loadFactor) 构造一个带指定初始容量和加载因子的空 HashMap。
- HashMap(Map<? extends K,? extends V> m) 构造一个映射关系与指定 Map 相同的 HashMap。
2.常用方法
- V
put(K key, V value) =修改,将指定的值与此映射中的指定键相关联(可选操作)。 - V
remove(Object key) 如果此映射中存在该键的映射关系,则将其删除。 - Collection
values() 返回此映射所包含的值的 collection 视图。 - Set
keySet() 返回此映射中所包含的键的 set 视图。 - V
get(Object key) 返回指定键在此标识哈希映射中所映射的值,如果对于此键来说,映射不包含任何映射关系,则返回 null。 - Set<Map.Entry<K,V>>
entrySet() 返回此映射所包含的映射关系的 collection 视图。 - boolean
isEmpty() 如果此映射不包含键-值映射关系,则返回 true。 - int
size() 返回此映射中的键-值映射关系数。 - boolean
containsKey(Object key) 如果此映射包含对于指定的键的映射关系,则返回 true。 - boolean
containsValue(Object value) 如果此映射将一个或多个键映射到指定值,则返回 true。
接口 Map.Entry<K,V>
- 在遍历时候的时候使用到了
a .存储基本类型
//HashMap实例化
@Test
void map() {
//实例化map集合,先存储基本类型
HashMap<String,Integer> stus=new HashMap<String,Integer>();
// 添加数据,根据键来判断是否更新:有就更新,没有就不更新
//键不能重复,可以为null,值也可以重复可以为null
//按照hash码来存放
stus.put("01",11);
stus.put("02",22);
stus.put("03",33);
stus.put("01",88);//更新数据
stus.put("03",33);
stus.put(null,null);
stus.put("04",null);
System.out.println(stus);
//删除,可以通过键删除,也可以通过键值删除
System.out.println("删除前"+stus);
Integer remove = stus.remove("01");
System.out.println(remove);//返回值是删除的元素的值
//根据键和值同时判断,键有值不相同返回false,只有两个同时相同才返回true
boolean remove2 = stus.remove("01",22);
System.out.println(remove2);
System.out.println("删除后"+stus);
//遍历
//遍历值
//将map集合中的所有的value值保存到一个collection集合中
Collection<Integer> values = stus.values();
for (Integer integer : values) {
System.out.println(integer);
}
//遍历所有的键
Set<String> keySet = stus.keySet();
for (String string : keySet) {
System.out.println(string);
//stus.get(string)根据键获取对应的值
System.out.println("键:"+string+"值:"+stus.get(string));
}
//entry整体遍历
// 使用entry进行遍历,将map集合的键值对关系保存为entry,存放到set集合中
Set<Entry<String,Integer>> entrySet = stus.entrySet();
for (Entry<String, Integer> entry : entrySet) {
System.out.println("键"+entry.getKey()+"值:"+entry.getValue());
}
//判断map和map进行比较
System.out.println(stus.equals(33));
//键值对的个数
System.out.println("集合的长度:"+stus.size());
//判断键值对是否为空
System.out.println(stus.isEmpty());
//判断有没有
System.out.println(stus.containsKey("02"));
System.out.println(stus.containsValue(22));
}
b.存储对象类型
@Test
void map01() {
//实例化map集合,存储对象类型
HashMap<String,Student> stus=new HashMap<String,Student>();
stus.put("java01", new Student("zs"));
stus.put("java02", new Student("ls"));
stus.put("java03", new Student("ww"));
stus.put("java04", null);
System.out.println(stus);//{java04=null, java03=Student [name=ww], java02=Student [name=ls], java01=Student [name=zs]}
//HashMap允许有null值和null键,要注意null值的获取
Collection<Student> values = stus.values();
for (Student student : values) {
if(student!=null) {
System.out.println(student.name);// ww ls zs
}
}
}
}
class Student{
String name;
public Student(String name) {
super();
this.name = name;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Student [name=" + name + "]";
}
}
c.存储集合类型
// hashmap 集合类型
// 一个学校有三个班级,每个班级有三个学生
@Test
void map02() {
HashMap<String,ArrayList<Student>> comp=new HashMap<String,ArrayList<Student>>();
//保存数据,班级
ArrayList<Student> cs=new ArrayList<Student>();
//第一个集合为班级,里面嵌套的为学生,若这样存,班级没办法起名字
//ArrayList<ArrayList<Student>> ass=new ArrayList<ArrayList<Student>>();
//存学生
cs.add(new Student("zs"));
cs.add(new Student("ls"));
cs.add(new Student("ww"));
comp.put("001", cs);
comp.put("002", cs);
comp.put("003", cs);
//遍历
Set<String> keySet = comp.keySet();
for (String cname : keySet) {
System.out.println("班级名字:"+cname);
//获取每一个班级的集合
ArrayList<Student> arrayList = comp.get(cname);
//遍历每一个班级集合中的元素
for (Student stu : arrayList) {
System.out.println(stu);
}
System.out.println("**********************************");
}
}
}
class Student{
String name;
public Student(String name) {
super();
this.name = name;
}
public Student() {
super();
// TODO Auto-generated constructor stub
}
@Override
public String toString() {
return "Student [name=" + name + "]";
}
}
二.Hashtable
- 键和值都不能为null,键和值可以是任意对象类型(自定义对象)
- 为了成功地在哈希表中存储和检索对象,用作键的对象必须实现 hashCode 方法和 equals 方法。
- 如果hashtable的键是对象,该对象重写实现 hashCode 方法和 equals 方法。
- Hashtable的初始默认容量11,加载因子0.75,扩容机制2倍+1。
1.构造方法
- Hashtable() 用默认的初始容量 (11) 和加载因子(0.75)构造一个新的空哈希表。
- Hashtable(int initialCapacity) 用指定初始容量和默认的加载因子(0.75)构造一个新的空哈希表。
- Hashtable(int initialCapacity, float loadFactor) 用指定初始容量和指定加载因子构造一个新的空哈希表。
- Hashtable(Map<? extends K,? extends V> t) 构造一个与给定的 Map 具有相同映射关系的新哈希表。
- 方法使用,以及底层容量获取(反射机制 )
2.常用方法
- 方法与HashMap基本相似
a.键是基本类型 (封装类 )
//hashtable,键是基本类型 (封装类 )
@Test
void hashteble() {
//实例化
Hashtable<Integer,String> nums=new Hashtable<Integer,String>(20);
//循环保存数据
for (int i = 0; i < 20; i++) {
nums.put(i, i+"");
}
//打印数据
System.out.println(nums);
getCp(nums);//集合的容量41
}
private void getCp(Hashtable<Integer, String> map) {
// TODO Auto-generated method stub
Class c = map.getClass();
try {
Field declaredField = c.getDeclaredField("table");
declaredField.setAccessible(true);
//进行强转
Entry[] entry = (Entry[]) declaredField.get(map);
System.out.println("集合的容量"+entry.length);
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
b. 键是对象类型
- Key是对象类型的 ,重写person的hashcode值之后,有可能导致集合的key值重复。
//键是对象类型
//如果hashtable的键是对象,该对象重写实现 hashCode方法和 equals方法。
@Test
void hashteble01() {
//实例化
Hashtable<Person,String> persons=new Hashtable<Person,String>();
persons.put(new Person("zs",20), "中国人");
persons.put(new Person("ls",14), "外国人");
persons.put(new Person("ww",14), "外国人");
persons.put(new Person("ww",14), "外国人");
System.out.println(persons);
System.out.println(persons.size());
System.out.println(persons.toString());
//persons.put(null,null);//不可以存储null键和值 ,会报空指针异常
}
}
class Person{
String name;
int age;
public Person() {
super();
// TODO Auto-generated constructor stub
}
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 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;
}
}
三.TreeMap(treeset) 自然排序
- TreeMap是根据键进行自然排序的键值对集合,可以使用自定义比较器来改变排序规则 。
- TreeMap 键不可以为null,值可以是null。
1.构造函数
- TreeMap() 构造一个新的空映射,该映射按照键的自然顺序排序。
- TreeMap(Comparator<? super K> c) 构造一个新的空映射,该映射根据给定的比较器进行排序。
- TreeMap(Map<? extends K,? extends V> m) 构造一个新映射,包含的映射关系与给定的映射相同,这个新映射按照键的自然顺序 进行排序。
- TreeMap(SortedMap<K,? extends V> m) 构造一个新的映射,包含的映射关系与给定的 SortedMap 相同,该映射按照相同的排序方式进行排序。
2.代码
- 方式一
@Test
void treemap01() {
//实例化,键不能为null,值可以为null
TreeMap<Integer,String> nums=new TreeMap<Integer,String>(new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
if(o1>o2) {
return -1;//逆序
}else if(o1<o2) {
return 1;
}else {
return 0;
}
}
});
nums.put(19, "zs");
nums.put(20, "ls");
nums.put(18, "ww");
System.out.println(nums);
}
- 方式二
@Test
void treemap02() {
//实例化,键不能为null,值可以为null
TreeMap<Integer,String> nums=new TreeMap<Integer,String>(new AscComparator());
nums.put(10, "张三");
nums.put(2, "张三");
nums.put(34, "张三");
nums.put(22, "张三");
nums.put(8, "张三");
System.out.println(nums);//{34=张三, 22=张三, 10=张三, 8=张三, 2=张三}
}
//自定义比较器,比较器可以有多个 逆序
class AscComparator implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
if(o1>o2) {
return -1;//逆序
}else if(o1<o2) {
return 1;
}else {
return 0;
}
}
}
//正序
class DscComparator implements Comparator<Integer>{
@Override
public int compare(Integer o1, Integer o2) {
// TODO Auto-generated method stub
if(o1>o2) {
return 1;
}else if(o1<o2) {
return -1;
}else {
return 0;
}
}
}
其他集合
一.Queue
- 队列集合,先进先出FIFO。 Queue队列集合使用的是LinkedList操作。
1.常用方法
- E
element() 检索,但是不移除此队列的头。 - boolean
offer(E o) 如果可能,将指定的元素插入此队列。 - E
peek() 检索,但是不移除此队列的头,如果此队列为空,则返回 null。 - E
poll() 检索并移除此队列的头,如果此队列为空,则返回 null。 - E
remove() 检索并移除此队列的头。
// 队列集合
@Test
void queue() {
Queue<String> strs = new LinkedList<String>();
strs.add("1111");
strs.add("2222");
strs.add("3333");
strs.add("4444");
System.out.println(strs);//[1111, 2222, 3333, 4444]
for (String string : strs) {
System.out.println(string);// 1111 2222 3333 4444
}
//queue常用方法
System.out.println(strs.peek());//查找第一个元素 1111
System.out.println(strs.poll());//移除第一个元素 并得到第一个元素 1111
System.out.println(strs);//[2222, 3333, 4444]
System.out.println(strs.element());//得到第一个元素 2222
System.out.println(strs);//[2222, 3333, 4444]
}
二.Properties
- Properties是键值对集合,该集合可以使用IO流的操作与properties类型的文件进行数据交互。
- properties文件是以properties后缀的文件。该文件中的数据全是字符串的,并且是键值对形式的。
- Stu01=zs-10-java01, 该文件在日常使用中大多数用来保存账号密码, 保存的是不重复的数据信息。
properties类型文件的标准写法: - user-name=admin
- password=123456
在eclipse中可以直接创建properties文件,该文件必须保存到项目根目录下(此时不允许将文件保存到src下,src是资源文件夹 )
1.构造方法
- Properties() 创建一个无默认值的空属性列表。
- Properties(Properties defaults) 创建一个带有指定默认值的空属性列表。
2.常用方法
- String
getProperty(String key) 用指定的键在此属性列表中搜索属性。 - String
getProperty(String key, String defaultValue) 用指定的键在属性列表中搜索属性。 - Object
setProperty(String key, String value) 调用 Hashtable 的方法 put。
// properties集合 键值对都是String的,键不能重复
@Test
void properties() {
//实例化Properties对象
Properties pt=new Properties();
//存储数据
pt.put("a","100");
pt.setProperty("b", "200");
pt.setProperty("c", "300");
pt.setProperty("d", "500");
pt.setProperty("c", "400");
System.out.println(pt);//{b=200, a=100, d=500, c=400}
//通过键获取
System.out.println(pt.get("c"));//400
}
- void
store(OutputStream out, String comments) 以适合使用 load 方法加载到 Properties 表中的格式,将此 Properties 表中的属性列表(键和元素对)写入输出流。
@Test
void properties01() {
Properties pt=new Properties();
//加载外部文件,将外部文件的内容保存到properties对象中,用load方法
// 参数是InputStream字节输入流
FileInputStream inputstream;
try {
inputstream = new FileInputStream(new File("user.properties"));
pt.load(inputstream);//读取
// 修改数据,此时是properties内存中的数据
pt.setProperty("username", "张三");
pt.setProperty("username1", "zhangsan");
System.out.println(pt);
// 将内存中对象中的数据持久化保存到properties文件中
FileOutputStream outputstream=new FileOutputStream(new File("user.properties"));
pt.store(outputstream, "修改后的账户信息");
System.out.println("数据持久化保存成功");
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//读取
@Test
void propertiesReader() {
Properties pt=new Properties();
FileInputStream inputstream;
try {
inputstream = new FileInputStream(new File("user.properties"));
pt.load(inputstream);//读取
System.out.println(pt);
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@Test
void propertiesWriter() {
Properties pt=new Properties();
pt.setProperty("username", "张三");
pt.setProperty("username1", "zhangsan");
pt.setProperty("password", "111111");
pt.setProperty("password1", "222222");
try {
// 将内存中对象中的数据持久化保存到properties文件中
FileOutputStream outputstream=new FileOutputStream(new File("user.properties"));
pt.store(outputstream, "修改后的账户信息");
System.out.println("数据持久化保存成功");
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Properties总结
- Properties是我们接触第一个持久化数据的技术,该对象中的所有的键值对都是String类型的。
- load方法用来获取流中的数据并保存到properties对象中 。
- store方法是用来将properties对象中的数据写到properties文件中 。每一次写数据到properties文件中,都会将原有文件中的数据全部覆盖。
- 键不能重复, 在properties文件中不要使用username键,可以写user_name
扩容机制
1. Vector 集合扩容机制
- 默认容量为10
- 扩容:扩容因子1,扩容机制 *2
自定义:自定义容量,扩容因子是1,扩容机制,使用构造方法定义
2. ArrayList
- 默认容量是10
- 使用Java反射机制来获取集合中的容量大小
- 扩容:扩容因子是1,扩容机制是原容量* 1.5
public static void main(String[] args) {
ArrayList<Integer> nums=new ArrayList<Integer>(2);
nums.add(100);
nums.add(100);
nums.add(100);//3
nums.add(100);//4.5 4
nums.add(100);
nums.add(100);
nums.add(100);
// 反射
Class c = nums.getClass();
try {
//获取属性对象
Field declaredField = c.getDeclaredField("elementData");
// 获取权限,不是public的属性
declaredField.setAccessible(true);
//从哪个集合中获取,指定的属性内容
Object[] object = (Object[] )declaredField.get(nums);
System.out.println(object.length);
} catch (NoSuchFieldException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
根据需要去选择自己合适的集合进行使用 。
Vactor:初始容量10,加载因子1,扩容机制是原容器的2倍。
ArrayList:初始容量10,加载因子1,扩容机制是原容量的1.5倍。
hashtable:初始容量11,加载因子0.75,扩容机制是原容量的2倍+1。
hashmap:初始容量16,加载因子0.75,扩容机制是原容器的2倍。
Hashset :初始容量16,加载因子0.75,扩容机制是原容器的2倍。
集合总结
一.Collection 单值(对象:自定义对象 封装类 String)
- List: 有序可重复集合
- ArrayList 列表
- Vector 列表
- Linkedlist 链表
- Queue 队列
- Set 无序不可重复
- Treeset 自然排序
- Hashset hash码排序
二. Map键值对集合,键不可以重复,值可以重复,每一个键对应一个值
Hashmap :键值是null
Hashtable:键值都不可以是null
Treemap:键不能为null,值可以是null
- 对于可以排序集合tree:
可以使用comparator比较器来自定义比较规则。
尤其是treeset要比较的对象需要实现Comparable接口,并重写comparTo方法。 - properties集合 : 集合中的键值都是String类型的, 该类可以与properties类型的文件采用IO流进行数据交互。 数据的永久保存,持久化。
- List,Set 集合遍历的方式有基本for循环,foreach循环,iterator迭代器, listiterator,enum(vactor特有的)。
- Map集合遍历的方式:遍历key,遍历value,使用entry键值对的表示
- 注意不要在遍历集合的过程中,对集合进行更新操作。