泛型-Collections工具类-Map双列集合复习

本文详细介绍了Java中的泛型概念及其好处,包括泛型类、泛型方法和泛型接口的实例。此外,还讲解了泛型通配符的三种形式。接着,讨论了Collections工具类的常用功能,如排序、搜索、替换等。最后,深入探讨了Map接口及其主要实现类HashMap、TreeMap、LinkedHashMap,并展示了Map的遍历方法和实际应用案例。
摘要由CSDN通过智能技术生成

泛型

泛型的概述

 广泛的类型,在定义一个类的时候,类型有些方法参数,返回值类型不确定时,就使用一个符号,表示这些尚未确定的类型,就称为泛型。

泛型的好处

提高了数据的安全性,将运行时的问题提前暴露在了编译阶段。

避免了强转的麻烦

泛型

泛型类 泛型方法  泛型接口

说明

 类名后面跟着的泛型类型,是泛型的声明,一旦泛型声明出来,就相当于成为了已知类型,这个类型在整个类中都可以使用。

泛型的声明,只需要一个合法的标识符,常用字母:T E K V Q ..

泛型确定的时机:将来在使用这个类创建对象的时候。

泛型类实例一(自定义队列):

import java.util.LinkedList;

//自定义队列(使用泛型,自定异常)

public class Test01Generic {

public static void main(String[] args) throws Exception {

MyQueue<Integer> mq = new MyQueue<Integer>();

mq.in(12);

mq.in(44);

mq.in(9);

mq.out();

mq.out();

mq.out();

mq.out();

 

}

 

}

 

class MyQueue<E>{

private LinkedList<E> linkedList = new LinkedList<E>();

//必须声明一个链表对象,不然不知道指向哪里,因为要在堆内存中开辟空间存储元素

public void in(E e) {

linkedList.addLast(e);

}

public E out() throws Exception {

if(isEmpty()) {

throw new MyQueueEmptyException("队列空了哦亲");

}

return linkedList.removeFirst();

}

public boolean isEmpty() {

return linkedList.isEmpty();

}

}

 

class MyQueueEmptyException extends Exception{

public MyQueueEmptyException(String str) {

super(str);

}

}

泛型类实例二:

需求:模拟ArrayList定义MyArrayList 完成add、get和size方法

感觉这个题挺牛逼的,就是吧,一直在用ArrayList,感觉用着很棒,然后突然发现其实内部实现很简单,自己也可以写那种感觉

/*需求:模拟ArrayList定义MyArrayList 完成add、get和size方法*/

public class Test02Generic {

 

public static void main(String[] args) {

MyArrayList<Integer> list = new MyArrayList<Integer>();

list.add(123);

list.add(456);

list.add(789);

System.out.println(list.get(0));

System.out.println(list.size());

list.get(5);

 

}

 

}

 

class MyArrayList<E>{

//定义一个对象数组,存储元素

private Object[] objs;

private int size;//定义一个变量,存储数组的大小

public MyArrayList() {

//定义构造方法

//定义,在新建一个MyArrayList类时,默认开辟一个size为10的空间

objs = new Object[10];

}

public void add(E e) {

if(size >= objs.length) {

Object[] oldObjs = objs;

objs = new Object[objs.length+10];

}

objs[size] = e;

size++;

}

public int size() {

return size;

}

public E get(int index) {

if(index>=size) {

throw new RuntimeException("没那么多元素");

}

return (E)objs[index];

}

}

泛型通配符

使用泛型的时候,没有使用具体的泛型声明T,而是使用了和声明过的某个泛型T有关的一类类型,就称为泛型的通配符。三种形式:

第一种形式,使用?来表示可以是任意类型,

例如:Collection<E>接口中的removeAll(Collection<?> c)表示可以接收任意泛型类型的集合,作为该方法的实际参数。参数集合的泛型,可以是与E没有任何关系

第二种形式,使用? extends E来表示必须是某个泛型类型或是该泛型类型的子类,例如:Collection<E>接口中的addAll(Collection<? extends E> c),表示可以接收泛型类型是调用者泛型类型(这里为E)或者其子类的集合,作为该方法的实际参数。参数的泛型和调用者的泛型,必须有关(相同或者是子父类)。确定了泛型的上边界。

第三种形式,使用? super E来表示必须是某个泛型类型或者是该泛型类型的父类,例如:TreeSet<E>集合中,存储的都是E类型的元素,构造方法TreeSet(Comparator<? super E> com),表示可以接收泛型类型是集合元素类型(这里为E)或者是元素类型的父类的比较器,作为构造方法的参数。参数的泛型和集合的泛型必须有关(相同或者是子父类)。确定了泛型的下边界。

注:  ? extends E: 接收E类型或者E的子类型。

? super E: 接收E类型或者E的父类型。

泛型方法

1、在方法上声明的泛型,可以在整个方法中,当做已知类型来使用。

  2、如果【非静态】方法上没有任何泛型的声明,那么可以使用类中定义的泛型

  3、如果【静态】方法上没有任何的泛型声明,那么就不能使用泛型,连类中定义的泛型,也不能使用,因为类中的泛型需要在创建对象的时候才能确定。所以【静态】方法想使用泛型,就必须在自己的方法上单独声明。

public class Test03Generic {

 

public static void main(String[] args) {

String x = new Test03Generic().getData("wkaaka");

System.out.println(x);

//输出结果:wkaaka

 

}

private <T> T getData(T data) {

return data;

}

 

}

泛型接口

在接口声明上,定义好的泛型,可以在整个接口中当做已知类型来使用。

  2、泛型接口被其他类实现的时候,有两种实现方式:  

    (1)声明的类不再是一个泛型类,而是一个确定了泛型的类,格式如下:       class 实现类类名 implements 接口名<具体类型> {

        所有的泛型类型都已经被确定

}

    (2)声明的类还是一个泛型类,泛型的类型和接口的泛型一致,格式如下:

      class 实现类类名<泛型标识符1> implements 接口名<泛型标识符1> {

       所有的方法还都是可以使用泛型标识符的方法

}

public class Test04 {

 

public static void main(String[] args) {

MyInter<String> my = new MyInter<String>();

my.print("泛型");

MyInter2 my2 = new MyInter2();

my.print("只能传字符串");

 

}

 

}

 

interface Inter<T>{

void print(T t);

}

 

//实现不知为何类型时,可以这样定义

class MyInter<T> implements Inter<T>{

public void print(T t) {

System.out.println("myprint:" + t);

}

}

 

 

//使用接口时明确具体类型

class MyInter2 implements Inter<String>{

public void print(String t) {

System.out.println("myprint:" + t);

}

}

Collections工具类

Collections常用功能

List排序:sort方法

Collection元素搜索:binarySearch方法

改变Collection中的元素:addAll方法

 

  1. int  binarySearch(List<E> list, E e ):在一个有升序顺序的List集合中,通过二分查找寻找元素e的索引
  2. fill(List<E> list, E e):将list集合中的所有元素都填充为元素e
  3. int frequency(Collection<E> c, E e):返回在集合c中的元素e的个数
  4. max、min:获取集合的最大值或者最小值
  5. replaceAll(List<E> list, E oldVal, E newVal):将集合list中的所有指定旧元素oldVal都替换成新元素newVal
  6. reverse(List<E> list):将参数集合list进行反转
  7. shuffle(List<E> list):将list集合中的元素进行随机置换
  8. swap(List<E> list, int a, int b):将a索引和b索引的元素进行交换
  9. synchronizedXxx方法系列:将一个线程不安全的集合传入方法,返回一个线程安全的集合

import java.util.ArrayList;

import java.util.Collections;

import java.util.List;

 

public class Test01Collections {

 

public static void main(String[] args) {

List<Integer> list = new ArrayList<Integer>();

list.add(11);list.add(15);

list.add(16);list.add(19);

list.add(222);list.add(335);

System.out.println(Collections.binarySearch(list, 12));//针对list集合的方法

//结果-2

//前提:list集合中的元素必须是升序的

//其次,搜索关键字的索引,如果它包含在列表中; 否则, (-(insertion point) - 1)

//Collections.fill(list,10);//针对list集合的方法

//将list集合中所有元素都填充为10

System.out.println(Collections.frequency(list, 11));//针对所有单列集合的方法

//运行结果:1

Collections.replaceAll(list, 10, 8);//针对list集合,返回boolean值

//没有10,返回false

//System.out.println(Collections.replaceAll(list, 10, 8));

System.out.println(Collections.max(list));//针对所有单列集合的方法

//运行结果:335

System.out.println(Collections.min(list));//针对所有单列集合的方法

//运行结果:11

Collections.reverse(list);//针对list集合的方法

System.out.println(list);

//Collections.shuffle(list);//针对list集合的方法

//System.out.println(list);

Collections.swap(list, 0, 1);

System.out.println(list);

}

 

}

Map

Map:双列集合的顶层接口。

Map:单词含义,地图。地图上的每个点,都表示了生活中的一个具体位置。地图的点和生活中的位置,有一个一一对应的关系,这种关系是通过穷举的方式来描述的。

Map是一个以键(key)值(value)对形式存储数据的容器。

Map的特点:

Map 是一个接口,但不是Collection的子接口。

Map以键值对的形式存储数据,每个键(key)对应一个值(value)。

Map 中的键不能重复(唯一)

Map 中的值可以重复。

主要实现类 HashMap Hashtable TreeMap ...

Map结构图:

 

Map中常用方法:

put(K key, V value)  向Map中添加数据

putAll(Map<? extends K,? extends V> m) 向Map中添加另一个Map集合。

isEmpty()  Map中是否包含数据

size() Map中包含键值对的个数

get(key) 根据key获取value

clear() 清空Map

containsKey(key) 判断Map中是否包含key

containsValue(value) 判断Map中是否包含value

keySet() 返回Map中所有key 组成的Set集合

values() 返回Map中所有value组成的集合 (返回值Collection类型)

entrySet() 返回此映射中包含的映射关系的 Set 视图

HashMap

HashMap是Map接口的最常用实现类,底层是哈希表形式存储的,非线程安全的,允许有null键值对。

Map遍历

方式一:使用keySet()方法

  1. 获取Map集合中的所有键,放到一个Set集合中,遍历该Set集合,获取到每一个键,根据键再来获取对应的值。【根据键获取值】
  2. 获取Map集合中的所有键

Set<K> keySet()

方式二:使用entrySet()方法

获取Map集合中的所有键值对对象(Entry),到Set集合中,遍历Set集合,拿到的是每个键值对对象(Entry),从这个对象中分别获取键和值。【根据键值对对象获取键和值】

 

根据Map集合获取所有的键值对对象,到一个Set集合中

  Set<Map.Entry<K, V>>  entrySet()

Entry是Map接口中的内部接口,访问的方式:Map.Entry

Entry的常用方法:

   getKey()获取当前键值对对象的键

   getValue()获取当前键值对对象的值

案例1编写一个方法,完成英译汉翻译功能。

dog--->狗

cat--->猫

pig--->猪

monkey--->猴

cow---> 牛

import java.util.HashMap;

import java.util.Map;

 

/*编写一个方法,完成英译汉翻译功能。

dog--->狗

cat--->猫

pig--->猪

monkey--->猴

cow---> 牛*/

public class Test01Map {

//分析:英译汉即输入英文,翻译出中文,可以使用Map集合存储数据,相当于一个字典,输入键,得到值

public static void main(String[] args) {

String tran = translate("do");

System.out.println(tran);

}

 

private static String translate(String string) {

Map<String,String> map = new HashMap<String,String>();

map.put("dog", "狗");

map.put("cat", "猫");

map.put("pig", "猪");

map.put("monkey", "猴");

map.put("cow", "牛");

String str = map.get(string);

if(str==null) {

return "词典里面暂时没有收录这个单词哦!";

}

return map.get(string);

}

 

}

 

案例2键盘录入一个字符串,统计每个字符出现的次数

例如,录入aaaabbccddd!@#@#$@#$%cc66ff

打印出来:a有4个,b有2个,c有4个,d有3个,!有1个,@有3个,$有2个,%有1个,6有2个,f有2个

import java.util.HashMap;

import java.util.Map;

import java.util.Map.Entry;

import java.util.Scanner;

 

/*案例2:键盘录入一个字符串,统计每个字符出现的次数

例如,录入aaaabbccddd!@#@#$@#$%cc66ff

打印出来:a有4个,b有2个,c有4个,d有3个,!有1个,@有3个,$有2个,%有1个,6有2个,f有2个*/

public class Test02Map {

/*分析:要存储的数据,有字符和字符个数,优先考虑双列集合Map*/

public static void main(String[] args) {

Scanner sc = new Scanner(System.in);

System.out.println("请输入一个字符串:");

String str = sc.nextLine();

char[] chs = str.toCharArray();

Map<Character,Integer> map = new HashMap<Character,Integer>();

for(int n = 0; n < chs.length;n++) {

char c = chs[n];

map.put(c,map.containsKey(c)?map.get(c)+1:1);

}

StringBuilder sb = new StringBuilder();

for(Entry<Character, Integer> entry : map.entrySet()) {

sb.append(entry.getKey()+"有" +entry.getValue()+"个,");

}

System.out.println(sb.substring(0,sb.length()-1));//返回值为字符串

}

 

}

Hashtable

Hashtable是一个比较古老的类(从JDK1.2开始),特点是线程安全的,不允许有null键值对。用法和HashMap相同,基本被HashMap替代。

面试常见问题HashMap和Hashtable的区别?

HashMap: 线程不安全,允许null键值对

Hashtable: 线程安全,不允许null键值对

TreeMap

 特点:会根据key值进行升序排列。

/*

 * 底层是由红黑数(自平衡的二叉树)来实现的  会根据key升序排序

 * key需要有排序的能力 或传入比较器

 * */

TreeMap构造方法:

TreeMap() 

使用其键的自然排序构造一个新的空树状图。

TreeMap(Comparator<? super K> comparator) 

构造一个新的,空的树图,按照给定的比较器排序。

TreeMap(Map<? extends K,? extends V> m) 

构造一个新的树状图,其中包含与给定地图相同的映射,根据其键的 自然顺序进行排序 。

TreeMap(SortedMap<K,? extends V> m) 

构造一个包含相同映射并使用与指定排序映射相同顺序的新树映射。

LinkedHashMap

是HashMap的一个子类。和HashMap的不同之处在于,具有可预知的迭代顺序,存储键值对的顺序和遍历集合时取出键值对的顺序一致。

斗地主练习

斗地主的制牌、洗牌和发牌

思路

  1、制牌:1~K一共13个数字,四个花色,4 * 13张牌,小王、大王

  2、洗牌:shuffle将集合中的字符串随机置换

  3、发牌:将一个集合中的元素,分发到3个集合中

import java.util.ArrayList;

import java.util.Collections;

import java.util.HashMap;

import java.util.List;

import java.util.Map;

import java.util.Set;

 

/*斗地主的制牌、洗牌和发牌

思路

  1、制牌:1~K一共13个数字,四个花色,4 * 13张牌,小王、大王

  2、洗牌:shuffle将集合中的字符串随机置换

  3、发牌:将一个集合中的元素,分发到3个集合中*/

public class Test03 {

public static void main(String[] args) {

//第一种写法

Map<Integer,String> pokerMap = new HashMap<Integer,String>();

String[] colors = {"♥","♠","♣","♦"};

String[] nums = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};

int id = 0;//牌的编号

pokerMap.put(id++, "大王");//编号从0到53,编号最好从0开始,因为数组是从0开始的

/*count与count++的关系区别一下.count+1,结果为count+1;而count++虽然值也为count+1

但在运算的时候,先使用count的值,再count+1,注意区分*/

pokerMap.put(id++, "小王");

for(String color : colors) {

for(String num : nums) {

pokerMap.put(id++, color + num);

}

}

Set<Integer> set = pokerMap.keySet();

List<Integer> listId = new ArrayList<Integer>();

listId.addAll(set);

Collections.shuffle(listId);//Collections的这个方法只有List集合能用

List<Integer> player1Id = new ArrayList<Integer>();

List<Integer> player2Id = new ArrayList<Integer>();

List<Integer> player3Id = new ArrayList<Integer>();

List<Integer> dipaiId = new ArrayList<Integer>();

for(int n = 0; n < listId.size();n++) {

if(n >= 51) {

dipaiId.add(listId.get(n));

}

if(n % 3 == 0) {

player1Id.add(listId.get(n));

}

else if(n % 3 == 1) {

player2Id.add(listId.get(n));

}

else if(n % 3 == 2) {

player3Id.add(listId.get(n));

}

}

 

List<String> player1 = new ArrayList<String>();

List<String> player2 = new ArrayList<String>();

List<String> player3 = new ArrayList<String>();

List<String> dipai = new ArrayList<String>();

for(Integer n : dipaiId) {

dipai.add(pokerMap.get(n));

}

for(Integer n : player1Id) {

player1.add(pokerMap.get(n));

}

for(Integer n : player2Id) {

player2.add(pokerMap.get(n));

}

for(Integer n : player3Id) {

player3.add(pokerMap.get(n));

}

System.out.println(player1);

System.out.println(player2);

System.out.println(player3);

System.out.println(dipai);

 

 

//第二种写法:感觉这种不太好,不过更简单

/*List<String> poker = new ArrayList<String>();

String[] colors = {"♥","♠","♣","♦"};

String[] nums = {"2","A","K","Q","J","10","9","8","7","6","5","4","3"};

for(String color : colors) {

for(String num : nums) {

poker.add(color + num);

}

}

Collections.shuffle(poker);

List<String> player1 = new ArrayList<String>();

List<String> player2 = new ArrayList<String>();

List<String> player3 = new ArrayList<String>();

List<String> dipai= new ArrayList<String>();

for(int i = 1;i <= 3;i++) {

dipai.add(poker.remove(0));

}

while(true) {

if(!poker.isEmpty()) {

player1.add(poker.remove(0));

}

if(!poker.isEmpty()) {

player2.add(poker.remove(0));

}

if(!poker.isEmpty()) {

player3.add(poker.remove(0));

}else {

break;

}

}

System.out.println(player1);

System.out.println(player2);

System.out.println(player3);

System.out.println(dipai);*/

 

}

 

}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值