常用对象API_01

常用对象API_01

1.Map集合

1.1 特点

  • 存储的是键值对
  • 必须保证键的唯一性

1.2 常用方法

1. 添加

  • value put(key,value):返回前一个和key关联的值,如果没有返回null

2. 删除

  • void clear():清空map集合
  • value remove(key):根据指定的key移除这个键值对

3. 判断

  • boolean containsKey(key)
  • boolean containsValue(value)
  • boolean isEmpty()

4. 获取

  • value get(key):通过键获取值,如果没有该键返回null;也可通过返回null来判断是否包含指定键
  • int size():获取键值对的个数

1.3 基本方法演示

public class MapDemo {

	public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		method(map);
	}

	public static void method(Map<Integer, String> map) {
		// 添加元素
		System.out.println(map.put(8, "wangwu"));// null
		System.out.println(map.put(8, "lisi"));// wangwu 存相同的键,值会被覆盖

		map.put(2, "张三");
		map.put(7, "李四");

		// 删除元素
		System.out.println("移除了:" + map.remove(2));

		// 判断
		System.out.println("包含:" + map.containsKey(7));

		// 获取
		System.out.println("获取:" + map.get(8));

		System.out.println(map);
	}

}

1.4 keySet方法演示一

public class MapDemo {

	public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		method(map);
	}

	public static void method(Map<Integer, String> map) {
		map.put(8, "wangwu");
		map.put(2, "zhangsan");
		map.put(6, "lisi");
		map.put(7, "zhaoliu");

		// 通过keySet方法获取map中所有的键所在的Set集合,
		// 再通过Set的迭代器获取到每一个键,再对每一个键通过map集合的get方法获取其对应的值即可

		Set<Integer> keySet = map.keySet();
		Iterator<Integer> it = keySet.iterator();

		while (it.hasNext()) {
			Integer key = it.next();
			String value = map.get(key);
			System.out.println(key + ":" + value);
		}
	}
}

1.5 keySet方法演示二

public class MapDemo {

	public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		method_3(map);
		
	}

	public static void method_3(Map<Integer, String> map) {
		map.put(8, "wangwu");
		map.put(2, "zhangsan");
		map.put(6, "lisi");
		map.put(7, "zhaoliu");
		/*
		 * 通过map转成set就可以迭代
		 * entrySet方法将键和值的映射关系作为对象存储到了Set集合中,
		 * 而这个映射关系的类型就是Map.Entry类型
		 */
		
		Set<Map.Entry<Integer, String>> entrySet = map.entrySet();
		
		Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
		
		while(it.hasNext()){
			Map.Entry<Integer, String> me = it.next();
			Integer key = me.getKey();
			String value = me.getValue();
			System.out.println(key+":"+value);
		}
	}
}	

1.6 values()演示

public class MapDemo {

	public static void main(String[] args) {
		Map<Integer, String> map = new HashMap<Integer, String>();
		method_4(map);
		
	}

	public static void method_4(Map<Integer, String> map) {
		map.put(8, "wangwu");
		map.put(2, "zhangsan");
		map.put(6, "lisi");
		map.put(7, "zhaoliu");
	
	    Collection<String> values = map.values();
	    
	    Iterator<String> it = values.iterator();
	    while(it.hasNext()){
	        System.out.println(it.next());
	    }
	}
}	

1.7 常见子类对象

  • Hashtable:内部结构是哈希表,是同步的,不允许null作为键,null作为值

Properties:用来存储键值对型的配置文件的信息,可以和IO技术相结合

  • HashMap:内部是哈希表,不是同步的,允许null作为键,null作为值
  • TreeMap:内部结构是二叉树,不是同步的,可以对Map集合中的键进行排序

2.泛型

2.1 为什么需要泛型?

  1. 简化缩写;
  2. 提高安全性
  3. 避免强转的麻烦,提高效率
public class GenericDemo {

	public static void main(String[] args) {
		ArrayList<String> al = new ArrayList<String>();

		al.add("abc");// Object
		// java.lang.Integer cannot be cast to java.lang.String
		// al.add(4);// al.add(new Integer(4));

		Iterator<String> it = al.iterator();
		while (it.hasNext()) {
			String str = it.next();
			System.out.println(str);
		}

	}

}

2.2 泛型的擦除与补偿

泛型用于编译时期,确保了类型的安全;运行时,会将泛型去掉,生成的class文件中是不带泛型的,这称为泛型的擦除。

  • 为什么要擦除呢?

因为为了兼容运行的类加载器

  • 泛型的补偿: 在运行时,通过获取元素的类型进行转换动作,不用使用者再强转了

2.3 泛型在集合中的应用

/*
 * COPYRIGHT (C) 2018 BY HOKI SOFTWARE. ALL RIGHTS RESERVED.
 */
package com.hoki.bean;

/**
 * Person Bean
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class Person implements Comparable<Person> {
	private String name;
	private int age;

	public Person() {
		super();
	}

	public Person(String name, int age) {
		super();
		this.name = name;
		this.age = 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 int compareTo(Person p) {
		int temp = this.age - p.age;
		return temp == 0 ? this.name.compareTo(p.name) : temp;
	}

}

/*
 * COPYRIGHT (C) 2018 BY HOKI SOFTWARE. ALL RIGHTS RESERVED.
 */
package com.hoki.comparator;

import java.util.Comparator;

import com.hoki.bean.Person;

/**
 * 名称比较器
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class ComparatorByName implements Comparator<Person> {

	public int compare(Person o1, Person o2) {
		int temp = o1.getName().compareTo(o2.getName());
		return temp == 0 ? o1.getAge() - o2.getAge() : temp;
	}
}

/*
 * COPYRIGHT (C) 2018 BY HOKI SOFTWARE. ALL RIGHTS RESERVED.
 */
package com.hoki.generic;

import java.util.Iterator;
import java.util.TreeSet;

import com.hoki.bean.Person;
import com.hoki.comparator.ComparatorByName;

/**
 * 泛型示例二
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class GenericDemo2 {

	public static void main(String[] args) {
		TreeSet<Person> ts = new TreeSet<Person>(new ComparatorByName());

		ts.add(new Person("lisi", 21));
		ts.add(new Person("lisi3", 23));
		ts.add(new Person("kisi", 21));
		ts.add(new Person("lis0", 20));
		ts.add(new Person("alis0", 20));

		Iterator<Person> it = ts.iterator();

		while (it.hasNext()) {
			Person p = it.next();
			System.out.println(p.getName() + ":" + p.getAge());

		}

	}

}

2.4 泛型类

在jdk1.5后,使用泛型来接收类中要操作的引用数据类型。
当类中的操作的引用数据类型不确定的时候,就使用泛型来表示。

/*
 * COPYRIGHT (C) 2018 BY HOKI SOFTWARE. ALL RIGHTS RESERVED.
 */
package com.hoki.generic.custom;


/**
 * 自定义泛型类
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class Tool<QQ> {
	
	private QQ q;

	public QQ getObject() {
		return q;
	}

	public void setObject(QQ obj) {
		this.q = obj;
	}
	
}

/*
 * COPYRIGHT (C) 2018 BY HOKI SOFTWARE. ALL RIGHTS RESERVED.
 */
package com.hoki.generic.custom;

import com.hoki.bean.Person;

/**
 * 自定义泛型
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class GenericDefine {
	public static void main(String[] args) {
		Tool<Person> tool = new Tool<Person>();

		tool.setObject(new Person());
		Person p = tool.getObject();
	}
}

2.5 泛型限定

泛型的通配符是?

  • 上限
<? extends E>:只接受E及其E的子类对象
  • 下限
<? super E>:只接受E类型及其E的父类型

一般在存储元素的时候都是用上限,因为这样取出都是按照上限类型来运算的,不会出现类型安全隐患;通常对集合中的元素进行取出操作时,可以使用下限。

3.集合查阅技巧

需要唯一?
    --需要:Set
        --需要执定顺序:
            --需要:TreeSet
            --不需要:HashSet
            --需要一个和存储一致的顺序:LinkedHashSet
    --不需要:List
        --需要频繁增删?
            --需要:LinkedList
            --不需要:ArrayList

前缀名就是该集合所属的体系,后缀名就是该集合的数据结构。

4.Map集合练习-记录字母出现次数

4.1 问题描述

对于一个字符串,记录其中每一个字母出现的次数;

要求打印结果如:a(2)b(1)…

4.2 问题分析

对于结果的分析发现,字母和次数之间存在着映射的关系,而且这种关系很多;意味着需要存储,能存储映射关系的容器有数组和Map集合;没有有序编号,可以使用Map集合;又发现可以保证唯一的一方具备顺序如a,b,c…,所以可以使用TreeMap集合。这个集合最终应该存储的是字母和次数的对应关系。

4.3 解决思路

  1. 因为操作的是字符串中的字母,所以先将字符串变成字符数组
  2. 遍历字符数组,用每一个字母作为键去查Map集合这个表;如果该字母键不存在,就将该字母作为键,1作为值存储到Map集合中;如果该字母键存在,就将该字母键对应值取出并+1,再将该字母和+1后的值存储到Map集合中,键相同的值会覆盖,这样就记录了该字母的出现次数。
  3. 遍历结束,Map集合就记录所有字母的出现的次数

4.4 代码实现

/**
 * 记录字母出现次数
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class HashMapDemo {

	public static void main(String[] args) {
		//定义一个字符串
		String s = "aaaaaabbbbcc";
		//将字符串转为字符数组
		char[] arr = s.toCharArray();
		//定义双列集合,存储字符串中字符以及字符出现的次数
		HashMap<Character,Integer> hm = new HashMap<>();
		//遍历字符数组获取每一个字符,并将字符存储到双列集合中
		for(char c:arr){
			//存储过程中要判断,如果集合中不包含这个键,就将这个字符作为键存入;否则,就将键的值++;
			/*if(!hm.containsKey(c)){
				hm.put(c, 1);
			}else{
				hm.put(c, hm.get(c)+1);
			}*/
			hm.put(c, !hm.containsKey(c)?1:hm.get(c)+1);
		}
		
		//打印双列集合,获取字符出现的次数
		for(Character key:hm.keySet()){
			System.out.println(key+"=="+hm.get(key));
		}
	}

}

5.HashMap和Hashtable的区别(面试题,亲身体验被面过)

HashMapHashtable
线程不安全的线程安全
效率高效率低
since 1.2since 1.0
可存储null键和null值不可存储null键和null值
/**
 * HashMap之所以设计出来就是为了防止Hashtable遇到null键或null值时,程序中断,代码不继续运行的情况
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class HashMap2 {

	public static void main(String[] args) {
		// 可存储null键和null值
		HashMap<String, Integer> hm = new HashMap<>();
		hm.put(null, 23);
		hm.put("hoki", 22);
		System.out.println(hm);

		// 抛出空指针异常,证明不可存储null键和null值
		Hashtable<String, Integer> ht = new Hashtable<>();
		ht.put(null, 23);
		ht.put("hoki", null);
		System.out.println(ht);
	}

}

6.洗牌游戏

模拟斗地主洗牌和发牌,牌没有排序

6.1 分析

  1. 一个扑克集合对象将扑克牌存储进去
  2. 洗牌
  3. 发牌
  4. 看牌

6.2 代码实现

/*
 * COPYRIGHT (C) 2018 BY HOKI SOFTWARE. ALL RIGHTS RESERVED.
 */
package com.hoki.doudizhu;

import java.util.ArrayList;
import java.util.Collections;

/**
 * 模拟斗地主洗牌和发牌,牌没有排序
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class Doudizhu {
	public static void main(String[] args) {
		// 1. 一个扑克集合对象将扑克牌存储进去
		String[] num = { "A", "2", "3", "4", "5", "6", "7", "8", "9", "10",
				"J", "Q", "K" };
		String[] color = { "红桃", "黑桃", "方块", "梅花" };
		ArrayList<String> poker = new ArrayList<>();
		// 拼接花色和数字
		for (String s1 : color) {
			for (String s2 : num) {
				poker.add(s1.concat(s2));
			}
		}
		// 添加大王和小王
		poker.add("大王");
		poker.add("小王");

		// 2. 洗牌
		Collections.shuffle(poker);
		// 3. 发牌
		ArrayList<String> xiaoming = new ArrayList<>();
		ArrayList<String> xiaohong = new ArrayList<>();
		ArrayList<String> me = new ArrayList<>();
		ArrayList<String> dipai = new ArrayList<>();

		for (int i = 0; i < poker.size(); i++) {
			if (i >= poker.size() - 3) {
				dipai.add(poker.get(i));
			} else if (i % 3 == 0) {
				xiaoming.add(poker.get(i));
			} else if (i % 3 == 1) {
				xiaohong.add(poker.get(i));
			} else {
				me.add(poker.get(i));
			}
		}

		// 4. 看牌
		System.out.println(xiaoming);
		System.out.println(xiaohong);
		System.out.println(me);
		System.out.println(dipai);

	}
}

6.3 对牌进行排序

/*
 * COPYRIGHT (C) 2018 BY HOKI SOFTWARE. ALL RIGHTS RESERVED.
 */
package com.hoki.doudizhu;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;

/**
 * 模拟斗地主洗牌和发牌,并对牌进行排序
 * 
 * @author Hoki_Lin
 * @since 1.0
 */
public class Doudizhu_Sort {
	public static void main(String[] args) {
		// 1. 一个扑克集合对象将扑克牌存储进去
		String[] num = { "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q",
				"K", "A", "2", };
		String[] color = { "红桃", "黑桃", "方块", "梅花" };
		HashMap<Integer, String> hm = new HashMap<>();
		ArrayList<Integer> list = new ArrayList<>();
		int index = 0;
		// 拼接扑克牌并将索引和扑克牌存储到hm中
		for (String s1 : num) {// 获取数字
			for (String s2 : color) {// 获取颜色
				list.add(index);// 将0~51添加到list集合中
				hm.put(index++, s2.concat(s1));

			}
		}

		// 将大王和小王都添加进hm中
		list.add(index);// 将52添加到list集合中
		hm.put(index++, "小王");
		list.add(index);// 将53添加到list集合中
		hm.put(index, "大王");

		// 2.洗牌
		Collections.shuffle(list);
		// System.out.println(list);

		// 3.发牌
		TreeSet<Integer> xiaoming = new TreeSet<>();
		TreeSet<Integer> xiaohong = new TreeSet<>();
		TreeSet<Integer> me = new TreeSet<>();
		TreeSet<Integer> dipai = new TreeSet<>();

		for (int i = 0; i < list.size(); i++) {
			if (i >= list.size() - 3) {
				dipai.add(list.get(i));
			} else if (i % 3 == 0) {
				xiaoming.add(list.get(i));
			} else if (i % 3 == 1) {
				xiaohong.add(list.get(i));
			} else {
				me.add(list.get(i));
			}
		}

		// 4.看牌
		showPoker(hm, xiaoming, "小明");
		showPoker(hm, xiaohong, "小红");
		showPoker(hm, me, "我");
		showPoker(hm, dipai, "底牌");
	}

	public static void showPoker(HashMap<Integer, String> hm,
			TreeSet<Integer> ts, String name) {
		System.out.print(name + "的牌是:");
		for (Integer i : ts) {
			System.out.print(hm.get(i) + " ");
		}
		System.out.println();
	}
}

7.总结

Collection
		List(存取有序,有索引,可重复)
			ArrayList
				底层是数组实现的,线程不安全,查找和修改快,增和删比较慢
			LinkedList
				底层是链表实现的,线程不安全,增和删比较快,查找和修改比较慢
			Vector
				底层是数组实现的,线程安全,无论增删查改都慢

			如果查找和修改多的话,用ArrayList
			如果增和删多的话,用LinkedList
			如果都多,用ArrayList
		Set(存取无序,无索引,不可重复)
			HashSet
				底层是哈希算法实现
				LinkedHashSet
					底层是链表实现的,但是也是可以保证元素唯一,和HashSet原理一样
			TreeSet
				底层是二叉树算法实现的
			一般在开发中不需要对存储的元素进行排序,所以在开发的时候大多用HashSet
Map
		HashMap
			底层是哈希算法,针对键
			LinkedHashMap
				底层是链表,针对键
		TreeMap	
			底层是二叉树算法,针对键
		开发中用HashMap比较多

  • 0
    点赞
  • 0
    评论
  • 0
    收藏
  • 打赏
    打赏
  • 扫一扫,分享海报

参与评论
请先登录 后发表评论~
©️2021 CSDN 皮肤主题: 技术黑板 设计师:CSDN官方博客 返回首页

打赏作者

Hoki Lin

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值