推荐先阅读
:JavaSE
Set
Set系列集合:添加的元素是无序(底层采用了哈希表存储元素),不重复,无索引的。
无序,不可重复,最多允许有一个Null元素对象,取元素时只能用Iterator接口取得所有元 素,在逐一遍历各个元素。元素在set中的位置是有该元素的 HashCode 决定的,其位置其实是固定的(加入Set 的 Object 必须定义 equals ()方法)。
迭代方法:迭代器 foreach lambda
查询慢,增删快(因为增删不会引起元素位置改变 )
- HashSet:添加的元素是无序,不重复,无索引的。
- LinkedHashSet:添加的元素是有序,不重复,无索引的。
- TreeSet:不重复,无索引,按照大小默认升序排序!!
JDK 1.8之前:哈希表 = 数组 + 链表 + (哈希算法)
JDK 1.8之后:哈希表 = 数组 + 链表 + 红黑树 + (哈希算法)
当链表长度超过阈值(8)时,将链表转换为红黑树,这样大大减少了查找时间。
Set系列集合是基于哈希表存储数据的
它的增删改查的性能都很好!!但是它是无序不重复的!如果不在意当然可以使用!
List
List系列集合:添加的元素是有序,可重复,有索引。
有序,按对象进入的顺序保存对象,可重复,允许多个Null元素对象,可以使用Iterator取出所有元素,在逐一遍历,还可以使用get(int index)获取指定下标的元素。
迭代方法:迭代器 foreach lambda fori
查询快(通过下标),增删慢(因为会引起其他元素位置改变)
- ArrayList:基于数组存储数据的,添加的元素是有序,可重复,有索引。查询快,增删慢。
- LinekdList:添加的元素是有序,可重复,有索引。
List集合继承了Collection集合的全部功能.
public E remove(int index)
: 移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element)
:用指定元素替换集合中指定位置的元素,返回更新前的元素值。
API
public boolean add(E e)
: 把给定的对象添加到当前集合中 。
public void clear()
:清空集合中所有的元素。
public boolean remove(E e)
: 把给定的对象在当前集合中删除。
public boolean contains(Object obj)
: 判断当前集合中是否包含给定的对象。
public boolean isEmpty()
: 判断当前集合是否为空。
public int size()
: 返回集合中元素的个数。
public Object[] toArray()
: 把集合中的元素,存储到数组中
集合的遍历
迭代器
Iterator<String> it = lists.iterator(); while(it.hasNext()){ String ele = it.next(); System.out.println(ele); }
|
foreach
for (String ele : lists) { System.out.println(ele); }
|
lambda
lists.forEach(s -> System.out.println(s));
|
List集合遍历比Collection集合多一个fori
循环
for(int i = 0 ; i < lists.size() ; i++ ) { String ele = lists.get(i); }
|
常见的数据结构种类
a.队列(queue)
- 先进先出,后进后出。
- 场景:各种排队。叫号系统。
- 有很多集合可以实现队列。
b.栈(stack)
- 后进先出,先进后出
- 压栈 == 入栈
- 弹栈 == 出栈
- 场景:手枪的弹夹。
c.数组
- 数组是内存中的连续存储区域。
- 分成若干等分的小区域(每个区域大小是一样的)
- 元素存在索引
- 特点:查询元素快(根据索引快速计算出元素的地址,然后立即去定位)
增删元素慢(创建新数组,迁移元素)
d.链表
- 元素不是内存中的连续区域存储。
- 元素是游离存储的。每个元素会记录下个元素的地址。
- 特点:查询元素慢
增删元素快(针对于首尾元素,速度极快,一般是双链表)
e.红黑树
二叉树:binary tree 永远只有一个根节点,是每个结点不超过2个节点的树(tree) 。
查找二叉树,排序二叉树:小的左边,大的右边,但是可能树很高,性能变差。
为了做排序和搜索会进行左旋和右旋实现平衡查找二叉树,让树的高度差不大于1
红黑树(就是基于红黑规则实现了自平衡的排序二叉树):
树尽量的保证到了很矮小,但是又排好序了,性能最高的树。
红黑树的增删查改性能都好!!!
LinkedList
LinkedList: 基于链表,增删比较快,查询慢!!
LinkedList是支持双链表,定位前后的元素是非常快的,增删首尾的元素也是最快的
所以提供了很多操作首尾元素的特殊API可以做栈和队列的实现。
public void addFirst(E e)
:将指定元素插入此列表的开头。
public void addLast(E e)
:将指定元素添加到此列表的结尾。
public E getFirst()
:返回此列表的第一个元素。
public E getLast()
:返回此列表的最后一个元素。
public E removeFirst()
:移除并返回此列表的第一个元素。
public E removeLast()
:移除并返回此列表的最后一个元素。
public E pop()
:从此列表所表示的堆栈处弹出一个元素。
public void push(E e)
:将元素推入此列表所表示的堆栈。
用LinkedList做一个队列:先进先出,后进后出。
LinkedList<String> queue = new LinkedList<>();
queue.addLast("1号"); queue.addLast("2号"); queue.addLast("3号"); queue.addLast("4号"); System.out.println(queue);
System.out.println(queue.removeFirst()); System.out.println(queue.removeFirst()); System.out.println(queue);
|
做一个栈
LinkedList<String> stack = new LinkedList<>();
stack.push("第1颗子弹"); stack.push("第2颗子弹"); stack.push("第3颗子弹"); stack.push("第4颗子弹"); System.out.println(stack);
System.out.println(stack.pop()); System.out.println(stack.pop()); System.out.println(stack);
|
LinkedHashSet
LinkedHashSet: HashSet的子类,元素是“有序” 不重复,无索引.
LinkedHashSet底层依然是使用哈希表存储元素的,
但是每个元素都额外带一个链来维护添加顺序!!
不光增删查快,还有序。
缺点是多了一个存储顺序的链会占内存空间!!而且不允许重复,无索引。
集合的使用场景
如果希望元素可以重复,又有索引,查询要快用ArrayList集合。(用的最多)
如果希望元素可以重复,又有索引,增删要快要用LinkedList集合。(适合查询元素比较少的情况,经常要首尾操作元素的情况)
如果希望增删改查都很快,但是元素不重复以及无序无索引,那么用HashSet集合。
如果希望增删改查都很快且有序,但是元素不重复以及无索引,那么用LinkedHashSet集合。
TreeSet
TreeSet: 不重复,无索引,按照大小默认升序排序!!
TreeSet集合称为排序不重复集合,可以对元素进行默认的升序排序。
TreeSet集合自自排序的方式:
1.有值特性的元素直接可以升序排序。(浮点型,整型)
2.字符串类型的元素会按照首字符的编号排序。
3.对于自定义的引用数据类型,TreeSet默认无法排序,执行的时候直接报错,因为人家不知道排序规则。
Collection排序
注意:如果类和集合都存在大小规则,默认使用集合自带的规则进行大小排序!!
a. 类实现Comparable接口
public class Orange implements Comparable { private String name; private double weight; private String price; @Override public String toString() { return "Orange{" + "name='" + name + '\'' + ", weight=" + weight + ", price='" + price + '\'' + '}'+"\n"; } @Override public int compareTo(Object o) { Orange o2 = (Orange) o; if(this.weight > o2.weight) return 1; if(this.weight < o2.weight) return -1; return 0; } }
|
b. TreeSet直接为设置比较器Comparator对象,重写比较方法
public TreeSet(Comparator<? super E> comparator)
Set<Employee> employees1 = new TreeSet<>(new Comparator<Employee>() { @Override public int compare(Employee o1, Employee o2) { return o1.getAge() - o2.getAge(); } }); employees1.add(new Employee("播仔",6500.0,21)); employees1.add(new Employee("播妞",7500.0,19)); employees1.add(new Employee("乔治",4500.0,23)); System.out.println(employees1);
|
Collections集合的方法
List<Orange> oranges1 = new ArrayList<>(); Orange o11 = new Orange("红橘子",654.0 ,"贼便宜~"); Orange o22 = new Orange("黄橘子",454.0 ,"贼便宜~"); Orange o33 = new Orange("黄橘子",454.0 ,"贼便宜~"); Orange o44 = new Orange("青橘子",456.0 ,"贼便宜~"); Collections.addAll(oranges1,o11,o22,o33,o44);
Collections.sort(oranges1, new Comparator<Orange>() { @Override public int compare(Orange o1, Orange o2) { if(o1.getWeight() > o2.getWeight()) return -1; if(o1.getWeight() < o2.getWeight()) return 1; return 0; } }); System.out.println(oranges1);
|
Collections Util
public static <T> boolean addAll(Collection<? super T> c, T... elements)
:给集合对象批量添加元素!
public static void shuffle(List<?> list)
:打乱集合顺序。
public static <T> void sort(List<T> list)
:将集合中元素按照默认规则排序。
public static <T> void sort(List<T> list,Comparator<? super T> )
:将集合中元素按照指定规则排序。
args
可变参数的格式:数据类型… 参数名称
可变参数在方法内部本质上就是一个数组。
可变参数的注意事项:
1.一个形参列表中可变参数只能有一个!!
2.可变参数必须放在形参列表的最后面!!
public class MethodDemo { public static void main(String[] args) { sum(); sum(10); sum(10,20,30); sum(new int[]{10,30,50,70,90}); } public static void sum(int...nums){ System.out.println("元素个数:"+nums.length); System.out.println("元素内容:"+ Arrays.toString(nums)); System.out.println("--------------------------"); } }
|
斗地主游戏的案例开发
/** 目标:斗地主游戏的案例开发。
业务需求分析: 斗地主的做牌,洗牌,发牌,排序(拓展知识), 看牌 业务:总共有54张牌。 点数: "3","4","5","6","7","8","9","10","J","Q","K","A","2" 花色: "♠", "♥", "♣", "♦" 大小王: "👲" , "" 点数分别要组合4种花色,大小王各一张。 斗地主:发出51张牌,剩下3张作为底牌。
功能: 1.做牌。 2.洗牌 3.定义3个玩家。 4.发牌。 5.排序(拓展,了解) 6.看牌。
用面向对象设计案例: a.定义一个牌类,代表牌对象。 一个牌对象代表一张牌。 b.定义一个集合存储54张牌,集合只需要一个(因为牌只需要一副) */
|
public class GameDemo { public static final List<Card> ALL_CARDS = new ArrayList<>();
static { String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"}; String[] colors = { "♠", "♥", "♣", "♦" }; for (String number : numbers) { for (String color : colors) { Card card = new Card(number , color); ALL_CARDS.add(card); } } Collections.addAll(ALL_CARDS , new Card("","🃏") ,new Card("","👲") ); System.out.println("输出新牌:"+ALL_CARDS); }
public static void main(String[] args) {
} }
public class Card { private String number; private String color;
@Override public String toString() { return number+color; } }
|
Map
Map集合的体系: Map<K , V>(接口,Map集合的祖宗类) / \ TreeMap<K , V> HashMap<K , V>(实现类,经典的,用的最多) \ LinkedHashMap<K, V>(实现类)
|
Map集合是另一个集合体系。 Collection是单值集合体系。
Map集合是一种双列集合,每个元素包含两个值。 Map集合的每个元素的格式:key=value(键值对元素)。 Map集合也被称为“键值对集合”。
Map集合的完整格式:{key1=value1 , key2=value2 , key3=value3 , ...}
Map集合有啥用? 1.Map集合存储的信息更加的具体丰富。 Collection: ["苍老师","日本","女","动作演员",23,"广州"] Map : {name="苍老师" , jiaxiang=小日本 , sex="女" , age = 23 , addr=广州}
2.Map集合很适合做购物车这样的系统。 Map: {娃娃=30 , huawei=1 , iphonex=1}
注意:集合和泛型都只能支持引用数据类型,集合完全可以称为是对象容器,存储都是对象。
Map集合的特点: 1.Map集合的特点都是由键决定的。 2.Map集合的键是无序,不重复的,无索引的。 Map集合后面重复的键对应的元素会覆盖前面的整个元素! 3.Map集合的值无要求。 4.Map集合的键值对都可以为null。
HashMap:元素按照键是无序,不重复,无索引,值不做要求。 LinkedHashMap:元素按照键是有序,不重复,无索引,值不做要求。
|
maps.put("娃娃",1); maps.put("huawei",10); maps.put("iphoneXS",2); maps.put(null , null ); maps.put("娃娃",30); maps.put("特仑苏",2); System.out.println(maps);
|
API
- V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。 - Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。 - Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)。 - boolean containKey(Object key):判断该集合中是否有此键。 - boolean containsValue(Object value); - void clear();清空集合 - Collection<V> values();获取全部值的集合 Map集合的值是不做要求的,可能重复,所以值要用Collection集合接收! - void putAll(Map<? extends K, ? extends V> m);
|
Map<String , Integer> maps = new HashMap<>(); maps.put("iphoneX",10); maps.put("iphoneX",100);
|
遍历方式
a.“键找值”
Set<String> keys = maps.keySet(); for (String key : keys) { Integer value = maps.get(key); }
|
b.“键值对”
Set<Map.Entry<String,Integer>> entries = maps.entrySet(); for (Map.Entry<String, Integer> entry : entries) { String key = entry.getKey(); Integer value = entry.getValue(); }
|
c.Lambda表达式
maps.forEach((k , v) -> System.out.println(k+"==>"+v));
|
存储自定义类型
Map集合的键和值都可以存储自定义类型。 如果希望Map集合认为自定义类型的键对象重复了,必须重写对象的hashCode()和equals()方法
|
Map<Orange,String> maps = new HashMap<>(); Orange o1 = new Orange("黄橘子",20.3 , "贼便宜!"); maps.put(o1 , "江西\n"); maps.put(o2 , "赣州\n"); maps.put(o3 , "广州\n"); maps.put(o4 , "广西\n");
public class Orange { private String name; private double weight; private String price; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Orange orange = (Orange) o; return Double.compare(orange.weight, weight) == 0 && Objects.equals(name, orange.name) && Objects.equals(price, orange.price); } @Override public int hashCode() { return Objects.hash(name, weight, price); } public String toString() { return "Orange{name = " + name + ", weight = " + weight + ", price = " + price + "}"; } }
|
LinkedHashMap
HashMap 无序不重复 LinkedHashMap 有序不重复 他们都是基于哈希表存储数据,增删改查都很好。
HashSet集合相当于是HashMap集合的键都不带值。 LinkedHashSet集合相当于是LinkedHashMap集合的键都不带值。
|
TreeMap
TreeMap集合按照键是可排序不重复的键值对集合。(默认升序) TreeMap集合和TreeSet集合都是排序不重复集合
TreeSet集合的底层是基于TreeMap,只是键没有附属值而已。 所以TreeMap集合指定大小规则有2种方式: a.直接为对象的类实现比较器规则接口Comparable,重写比较方法(拓展方式) b.直接为集合设置比较器Comparator对象,重写比较方法
|
Properties
-- public Object setProperty(String key, String value) : 保存一对属性。 -- public String getProperty(String key) :使用此属性列表中指定的键搜索属性值 -- public Set<String> stringPropertyNames() :所有键的名称的集合 -- public void store(OutputStream out, String comments):保存数据到属性文件中去 -- public void store(Writer fw, String comments):保存数据到属性文件中去 -- public synchronized void load(InputStream inStream):加载属性文件的数据到属性集对象中去 -- public synchronized void load(Reader fr):加载属性文件的数据到属性集对象中去
properties.load(new FileInputStream("Day10Demo/src/users.properties")); System.out.println(properties); System.out.println(properties.getProperty("dlei")); System.out.println(properties.getProperty("admin"));
|
输出一个字符串中每个字符出现的次数。(经典面试题)
package com.zx._07Map集合练习;
import java.util.HashMap; import java.util.Map; import java.util.Scanner;
public class MapDemo01 { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); System.out.print("请您输入一个字符串:"); String datas = scanner.nextLine();
Map<Character , Integer> infos = new HashMap<>();
for(int i = 0 ; i < datas.length() ; i++ ){ char ch = datas.charAt(i); if(infos.containsKey(ch)){ infos.put(ch , infos.get(ch) + 1); }else{ infos.put(ch , 1); } } System.out.println("结果:"+infos);
} }
|
斗地主游戏的案例开发-Map集合实现。
package com.zx._08斗地主游戏洗牌发牌看牌;
import java.util.*;
public class GameDemo { public static final Map<Card , Integer> ALL_CARDS_SIZE = new HashMap<>(); public static final List<Card> ALL_CARDS = new ArrayList<>(); static { String[] numbers = {"3","4","5","6","7","8","9","10","J","Q","K","A","2"}; String[] colors = { "♠", "♥", "♣", "♦" };
int index = 0; for (String number : numbers) { for (String color : colors) { Card card = new Card(number , color); ALL_CARDS.add(card); ALL_CARDS_SIZE.put(card , index++); } } Card c1 = new Card("","🃏"); Card c2 = new Card("", "👲");
ALL_CARDS.add(c1); ALL_CARDS.add(c2); ALL_CARDS_SIZE.put(c1 , index++); ALL_CARDS_SIZE.put(c2 , index++); System.out.println("新牌:"+ ALL_CARDS); }
public static void main(String[] args) {
Collections.shuffle(ALL_CARDS); System.out.println("洗牌后:"+ALL_CARDS);
List<Card> lingHuChong = new ArrayList<>(); List<Card> jiuMoZhi = new ArrayList<>(); List<Card> dongfangbubai = new ArrayList<>();
for(int i = 0 ; i < ALL_CARDS.size() - 3 ; i++ ){ Card c = ALL_CARDS.get(i); if(i % 3 == 0 ){ lingHuChong.add(c); }else if(i % 3 == 1){ jiuMoZhi.add(c); }else if(i % 3 == 2){ dongfangbubai.add(c); } }
sortCards(lingHuChong); sortCards(jiuMoZhi); sortCards(dongfangbubai);
System.out.println("令狐冲:"+lingHuChong); System.out.println("鸠摩智:"+jiuMoZhi); System.out.println("东方不败:"+dongfangbubai); List<Card> lastThreeCards = ALL_CARDS.subList(ALL_CARDS.size() -3 , ALL_CARDS.size()); System.out.println("底牌:"+lastThreeCards);
}
private static void sortCards(List<Card> cards) { Collections.sort(cards, new Comparator<Card>() { @Override public int compare(Card o1, Card o2) { return ALL_CARDS_SIZE.get(o2) - ALL_CARDS_SIZE.get(o1); } }); } }
|
图书管理系统的开发
package com.zx._09图书管理案例;
import java.util.*;
public class BookSystem {
public static final Map<String, List<Book>> BOOK_STORE = new HashMap<>(); public static final Scanner SYS_SCANNER = new Scanner(System.in);
public static void main(String[] args) { showCommand(); }
private static void showCommand() { System.out.println("===============欢迎您进入系统==================="); System.out.println("(1)查看全部书籍。query"); System.out.println("(2)添加书本信息。add"); System.out.println("(3)删除书本信息。delete"); System.out.println("(4)修改书本信息。update"); System.out.println("(5)退出系统。 exit"); System.out.print("请您输入您的操作命令:"); String command = SYS_SCANNER.nextLine(); switch (command){ case "query": queryBooks(); break; case "add": addBook(); break; case "delete": break; case "update": updateBook(); break; case "exit": System.out.println("退出成功,期待您下次光临!"); System.exit(0); break; default: System.err.println("您的命令输入有无,请重新确认!"); } showCommand(); }
private static void updateBook() { if(BOOK_STORE.size() == 0 ){ System.out.println("您现在根本没有任何栏目可以修改!"); }else{ queryBooks(); System.out.println("===============欢迎您进入修改书本业务================="); while(true){ System.out.print("请您输入修改书本的栏目:"); String type = SYS_SCANNER.nextLine(); if(BOOK_STORE.containsKey(type)){ while(true){ System.out.print("请您输入修改书本的名称:"); String name = SYS_SCANNER.nextLine(); Book book = getBookByTypeAndName(type , name); if(book == null){ System.err.println("您的输入的书名不存在,,请重新确认!"); }else{ System.out.println("请您输入修改书本的新名称:"); String newName = SYS_SCANNER.nextLine(); System.out.println("请您输入修改书本的新价格:"); String newPrice = SYS_SCANNER.nextLine(); System.out.println("请您输入修改书本的新作者:"); String newAuthor = SYS_SCANNER.nextLine(); book.setName(newName); book.setPrice(Double.valueOf(newPrice)); book.setAuthor(newAuthor); queryBooks(); System.out.println("您修改的书本成功,请看如上信息确认!"); return; } } }else{ System.err.println("您输入的栏目不存在,请重新确认!"); } } }
}
public static Book getBookByTypeAndName(String type , String name){ List<Book> books = BOOK_STORE.get(type); for (Book book : books) { if(book.getName().equals(name)){ return book; } } return null; }
private static void queryBooks() { System.out.println("===============欢迎您进入查询书本业务================="); if(BOOK_STORE.size() == 0){ System.out.println("您的图书馆一本书都没有,请赶紧买书去!"); }else{ System.out.println("类型\t\t\t\t书名\t\t\t\t\t价格\t\t\t作者"); BOOK_STORE.forEach((type , books) -> { System.out.println(type); for (Book book : books) { System.out.println("\t\t\t\t"+book.getName()+"\t\t\t"+book.getPrice()+"\t\t"+book.getAuthor()); } }); } }
private static void addBook() { System.out.println("===============欢迎您进入添加书本业务================="); System.out.print("请您输入添加书本的栏目:"); String type = SYS_SCANNER.nextLine(); List<Book> books = null ; if(BOOK_STORE.containsKey(type)) { books = BOOK_STORE.get(type); }else{ books = new ArrayList<>(); BOOK_STORE.put(type , books); } System.out.println("请您输入添加书本的名称:"); String name = SYS_SCANNER.nextLine(); System.out.println("请您输入添加书本的价格:"); String price = SYS_SCANNER.nextLine(); System.out.println("请您输入添加书本的作者:"); String author = SYS_SCANNER.nextLine(); Book book = new Book(name , Double.valueOf(price) , author); books.add(book); System.out.println("您添加在"+type+"下的书本"+book.getName()+"成功!"); } }
|