package com.zhou.jihe;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.TreeMap;
public class TestMap {
/**
* Map接口:
* 1.Map和Collection、Iterator并列的顶级接口,并且Map是用来产生集合的,即用Map来定义Collection;
* 2.Map接口的实现类有:HashMap,Hashtable,LinkedHashMap,TreeMap,Properties;
* 3.Map接口用于保存具有映射关系的数据,因此Map集合里保存着两组值,一组值用于保存Map里的Key,另一组用于保存Map里的value;
* 4.Map中的key和value都可以是任何引用类型的数据;
* 5.Map中的key不允许重复,即同一个Map对象的任何两个key通过equals()方法返回false;
* 6.key和value之间存在着单向一对一的关系,即通过指定的key总能找到唯一的,确定的value,但是反过来,用value找不到key;
*/
public static void main(String[] args) throws FileNotFoundException, IOException {
/**
* 一、 Map最典型的实现是HashMap实现类:
* HashMap和HashSet有什么关系(在eclipse中用ctrl+shift+t查找HashSet),可以看出HashSet是用HashMap来进行定义的,我们在创建HashSet的时候实际上它是把这个Map给初始化了,于是我们在进行遍历的时候都是调用的是Map的方法,具体用的是HashMap里面的那个key,那个值就是Object里面的常量值;所以说HashMap和HashSet是一脉相承;
* HashMap定义了HashSet:HashMap里面的键为HashSet里面的元素;
*/
//1.创建一个Map的HashMap实现类对象;
Map map = new HashMap();
//Map<String,Object> map = new HashMap<>();//泛型的方式
//2.Map接口中有一些方法,下面将这些方法作一些归类;
//2.1 向Map中添加元素的方法,关于添加的方法有两个:put(key,value),put(map);
map.put("AA", new Person("AA", 12));//放入一个指定的键值对;
map.put("AA", new Person("AAA", 12));//这样的话其键相同,equals()返回true,第二个会把第一个覆盖掉;
map.put("BB", new Person("BB", 15));
map.put("CC", new Person("CC", 16));
map.put("DD", new Person("AAA", 12));
//2.2 从Map中取出元素的方法(遍历),map是由键和值组成的,所以我可以得到键的集合和值的集合;
//2.2.1 得到键的集合;
Set keyset = map.keySet();//用map的keySet()方法来得到键的集合,这里用到了Set接口;
//我通过遍历键的方式来找到值;
for(Object key:keyset){
Object value = map.get(key);//通过map的get(key)方法得到value;
System.out.println(key+":"+value);//打印出一个键值对的集合;
}
System.out.println("-----------------------------------------");
//2.2.2 直接得到value的集合;
Collection values = map.values();
System.out.println(values.getClass());//看看values是什么,HashMap$Values,values就是HashMap的内部类,它返回的就是values;
//遍历value集合,需要说明是,value可以重复;
for(Object val:values){
System.out.println(val);
}
System.out.println("-----------------------------------------");
// //2.2.3 得到键值对的集合,要求是要使用泛型,不用泛型是不行的;
// for(Map.Entry<String,Object> entry:map.entrySet()){
// String key = entry.getKey();
// Object value = entry.getValue();
// System.out.println(key+":"+value);
// }
//
//2.3 移除元素的方法;
// map.remove("AA");//移除指定的键;
//2.4 工具方法:
//2.4.1 size()方法;
System.out.println(map.size());//移除了之后就4变成3
System.out.println("-----------------------------------------");
System.out.println(map);// 因为Map重写了toString()方法,所以打印时就能看得到:{AA=Person [name=AAA, age=12]}
//2.4.2 contains(),isEmpty()
System.out.println(map.containsKey("BB"));//true
System.out.println(map.containsValue(new Person("CC", 16)));//true
System.out.println(map.isEmpty());//false
/**
* 二、HashMap和Hashtable:
* HashMap和Hashtable是Map接口的两个典型的实现类;
* 区别:
* Hashtable是一个古老的实现类,不建议使用;
* Hashtable是一个线程安全的Map实现,但HashMap是线程不安全的;
* Hashtable不允许使用null作为key和value,而HashMap则可以;
* 与HashSet集合不能保证元素的顺序一样,Hashtable、HashMap也不能保证其中key-value对的顺序,实际上是不能保证那个键的顺序,当然值的顺序也不能保证;
* Hashtable、HashMap判断两个key相等的标准是:两个key通过equals()方法返回true,hashCode值也相等;
* Hashtable、HashMap判断两个value相等的标准是:两个value通过equals()方法返回true;
*
*/
/**
* 三、LinkedHashMap:
* LinkedHashMap是HashMap的子类;
* LinkedHashMap可以维护Map的迭代顺序:迭代顺序与key-value的插入顺序一致;
* LinkedHashSet实际上也是LinkedHashMap来进行定义的,所以所以说LinkedHashMap可以维护Map的迭代顺序;
*/
/**
* 四、TreeMap:(TreeSet是由TreeMap来进行定义的,TreeSet的所有思想在TreeMap里同样适用,只不过TreeSet针对的是所有元素,而TreeMap针对的是所有的key)
* TreeMap存储key-value对时,需要根据key对key-value对进行排序,TreeMap可以保证所有的key-value对处于有序状态;
* TreeMap的key的排序:(跟TreeSet里面对那个Set元素的排序方式一样,对比TreeSet进行使用)
* 自然排序:TreeMap的所有的key必须实现Comparable接口,而且所有的key应该是同一个类的对象,否则将会抛出ClassCastExcertion类型转换异常;
* 定制排序:创建TreeMap时,传入一个Comparator接口对象,该对象负责对TreeMap中所有的key进行排序,此时不需要Map的key实现Comparable接口;
*
*/
Comparator comparator = new Comparator() {//匿名内部类
@Override
public int compare(Object o1, Object o2) {
//这里来比较两个Person对象的age,按年龄排序;
if(o1 instanceof Person && o2 instanceof Person ){
Person p1 = (Person) o1;
Person p2 = (Person) o2;
//return p1.getAge() - p2.getAge();//年龄的升序排列
return -(p1.getAge() - p2.getAge());//按年龄降序排列
}else{
throw new ClassCastException("不能转换为Person类型");
}
}
};
//创建一个TreeMap对象;
TreeMap tm = new TreeMap(comparator);//定制排序:在创建 TreeMap是传入一个Comparator实现类对象进来,如果不传的话它就会把这个键试着转换成Comparable,发生类型转换异常;
//放入一些元素到集合中,这时候我们的键需要是Person对象;
tm.put(new Person("AAA", 12), "AAA");
tm.put(new Person("BBB", 13), "BBB");
tm.put(new Person("CCC", 11), "CCC");
tm.put(new Person("DDD", 9), "DDD");
//遍历上面的元素;
keyset = tm.keySet();//得到一个键的集合
for(Object key:keyset){
Object value = tm.get(key);//通过key得到value;
System.out.println(key+":"+value);
}
/**
* 五、Properties实现类:
* Properties类是Hashtable的子类,该对象用于处理属性文件;
* 由于属性文件里的value。key都是字符串类型,所以Properties里的value和key都是字符串类型的;
* Properties文件在java中对应的是一个Properties类的对象;
*/
//加载我们创建的那个Properties文件的步骤:在JDBC时为了不把数据库的信息写死,一般就把数据库的信息放在这样的属性文件中,处理属性文件的步骤基本就是下面这样的;
//1.创建一个Properties类的对象;
Properties properties = new Properties();
//2.使用IO六加载对应的Properties文件;
properties.load(new FileInputStream("jdbc.properties"));// 需要传入一个FileInputStreamIO流对象,其构造方法是有参数的,参数就是那个属性文件名的全称;
//3.得到对应的属性值,通常情况下这个键是已知的,通过这个键去得到属性值,当然也可以用Map里面的方法同时获取键和值,但是开发的时候都是知道了键,直接去获取值;
String url = properties.getProperty("url");//得到一个url键对应的值
System.out.println(url);
}
}
package com.zhou.jihe;
public class Person {
//当我重写equals方法集合的移除也会失败
//
@Override
//
public boolean equals(Object obj) {
//
// TODO Auto-generated method stub
////
return super.equals(obj);
//
return false;
//
}
//用IDE直接生成hashCode()和equals()方法
//hashCode()方法决定着我们放的这个元素在集合中的位置,如果两个元素比较equals()方法返回fasle的话,那么hashCode()方法返回值应该也不相等,应该放在两个位置;
//反过来,如果equals()方法返回的true的话,那么hashCode()返回值应该也相等,它们是同一个元素,应该放在同一个地方;
/**
* 正常情况下我们这么来做:两个对象的equals()方法返回true,hashCode()方法返回值必相等;
* 通常情况下,我们使用eclipseIDE帮我们生成hashCode()和equals()方法就可以;
* 学习的时候我们可以这样来试一下,不建议开发的时候这样来做,如果equals()方法返回true,它两是同一个元素,但是hashCode()值不一样,那么这两个对象都可以放到这个集合里面去,这个是矛盾的事
*/
/**
* hashCode()方法的要求:
* HashSet集合判断两个元素相等的标准:两个对象通过equals()方法方法比较返回true相等,并且两个对象的hashCode()方法返回值也相等。
* 如果两个对象通过equals()方法返回true,这两个对象的hashCode值也应该相同;
*
* 重写hashCode()方法的基本原则:
* 1.在程序运行时,同一个对象多次调用hashCode()方法应该返回相同的值;
* 2.当两个对象的equals()方法比较返回true时,这两个对象的hashCode()方法的返回值也应该相等;
* 3.对象中用作equals()方法比较的(Field)区域,都应该用来计算hashCode值;
*
*/
//
private static int init = 0;
@Override
public int hashCode() {
//这个hashCode值和age的值联合到一起来返回的一个结果
final int prime = 31;
//用这个素数是为了防止name的hashCode值和age的值不一样,但是有可能age和name的hashCode值相加得到的那个数可能一样的情况;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
//
return init++;//不允许
}
//这个是一个一个属性比的,这个是IDE自动帮我们生成的equals()方法,这个是可信赖的;
@Override
public boolean equals(Object obj) {
if (this == obj)
//如果这两个对象是一个的话,返回true
return true;
if (obj == null)
//如果传的这个对象是空的话,返回fasle
return false;
if (getClass() != obj.getClass())
//如果类型不一致的话,返回false
return false;
Person other = (Person) obj;
//否则,强转
if (age != other.age)
//如果年龄不一样的话,返回false
return false;
if (name == null) {
//如果名字为空
if (other.name != null)
//另外一个的名字不为空返回fasle
return false;
} else if (!name.equals(other.name))
//如果名字不一样的话,返回fasle
return false;
return true;
//否则,最后返回true,表示一样;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public Person() {
super();
}
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;
}
private String name;
private int age;
}
本文出自 “IT技术JAVA” 博客,转载请与作者联系!