一、数据结构
1、数据结构
1.1 数据结构作用:
- Java中提供了很丰富的容器技术,这些容器技术在底层都是通过各种各样的数据结构来实现的。
- Java是面向对象的编程语言。
- 我们常见的数据结构:堆栈、队列、数组、链表和红黑树等,作为数据结构的入门。
1.2 常见的数据结构
- 数据存储的常用结构有:栈、队列、数组、链表、红黑树。
2、栈
2.1 概述
- 栈:stack 又称堆栈,它是运算受限的线性表其限制是仅运行在栈的一端进行插入和删除操作,不允许在其他任何位置进行添加、查找、删除等操作
- 简单来说,采用该结构的集合,对元素存储有如下特点:
- 先进后出,即:第一个存储进去的元素,会最后取出来
- 压栈:就是存元素,即:把元素存储到栈的顶端位置,栈中已有元素依次向栈底方向移动一个位置
- 弹栈:就是取元素,即:把栈的顶端位置元素取出,栈中已有的元素向栈顶方向移动一个位置
3、 队列
3.1 概述
- 队列: queue 简称队,它同堆栈一样,也是一种运算受限的线性表,其限制是仅允许在队列的一端进行插入,而在队列的另一端进行删除
- 对元素存取有如下特点:
- 先进先出:第一个存储的元素也会第一个取出来
- 例如:火车过山洞,车尾再进去,车头先出山洞,车尾再出
- 队列的入口、出口各占一侧
4、数组
4.1 概述
- 数组: Array 是有序的元素序列,数组实在内存中开辟一段连续的空间,并在此空间中存放元素,而且是有序的。例如:100个房子,在从1-100中,每个房子都会有编号,可以快速找到房子
- 该结构,对元素存取有如下特点:
- 查找元素快,通过索引,可以快速地访问位置上的元素
- 增删元素慢,通过索引在指定位置添加、删除元素,需要创建一个新的数组,将指定的新元素存储在指定位置,再把原数组中的元素根据索引再添加到相应的位置上
5、链表
5.1 概述
- 链表: linked list 由一系列结点 node(链表中每一个元素称为结点)组成,节点可以在组成时动态生成,每个节点包括两部分:一个存储数据的数据域,一个存储下个结点地址的指针域。
- 分为单向链表、双向链表
- 简单地说,对元素存取有如下特点:
- 多个节点之间,通过节点地址相互连接
- 查找元素慢,想要查找某个元素,就要通过连接的结点,依次向后查找指定元素
- 增删元素快,增删元素只需修改连接下个元素的地址即可
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tSkWZWrU-1600262694791)(C:\Users\Lenovo\Desktop\md\photo\dxlb.png)]
6、 红黑树
6.1 概述
- 二叉树:binary tree是每个结点不超过2的有序树
- 其实可以想象成:我们日常生活中的树,但是每个树杈(结点)上最多只能有两个小树叉(子节点)
- 二叉树是每个节点最多有两个子节点的树结构,顶上的叫根结点,两边的称为左子树和右子树
- 红黑树本身就是二叉树,存放数据必须时可排序的
二、List集合
1、 List集合介绍
1.1 概述
- java.util.List接口继承自Collection 接口,是单列集合的一个重要分支,习惯性的将实现了List接口的对象称为List集合,在List集合中可以出现重复的元素,所有的元素以一种线性方式进行存储,在程序中可以通过索引的方法来访问集合中的指定元素,另外,List集合是有序的,元素的存入和取出顺序一致
1.2 List接口中常用的方法
List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:
- public void add(int index, E element):将指定的元素,添加到集合中指定的位置上
- public E get(int index):返回集合中指定位置上的元素
- public E remove(int index):移除列表中指定位置上的元素,返回的是被移除的元素
- public E set(int index,E element):用指定的元素替换集合中指定位置上的元素,返回值是更新前的元素。
三、List 的实现类
3.1 ArrayList 集合
java.util.ArrayList 集合数据存储的结构时数组结构,而且时一个动态的数组,数组的容量会随着集合的个数自动扩大或缩小
- 添加到ArrayList 集合中的元素,都会有一个整数的序号(索引、下标)从0开始
- 查找元素快,根据索引快速定位
- 增删元素慢,因为增删都会把该位置以后的元素进行索引的调整
- 日常开发中它是使用最多的一个用来查询的结合类
package com.bdit.test;
import java.awt.event.ItemListener;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
//ArrayList
//有序、重复
//有下标,查询快,但增改慢,改变一个下标,后面也会改变
public class Test18 {
public static void main(String[] args) {
ArrayList<Integer> arrayList = new ArrayList<>();
arrayList.add(1);
arrayList.add(2);
arrayList.add(3);
arrayList.add(3);
System.out.println(arrayList);
arrayList.add(0,333);//通过下标值给与赋值
System.out.println(arrayList);
for (int i = 0; i < arrayList.size(); i++) {
// System.out.print(arrayList.get(i) +" ");
System.out.print(arrayList.indexOf(i)+"----");
}
System.out.println();
Iterator<Integer> iterator = arrayList.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
ListIterator listIterator =arrayList.listIterator();
while(listIterator.hasNext()){
System.out.println(listIterator.next());
}
List<String> list = List.of("12","32");
System.out.println(list);
}
}
//https://www.cnblogs.com/taiwan/p/6954135.html
3.2 LinkedList 集合
- java.util.LinkedList 集合数据存储的结构是链表结构,方便元素的添加,删除的集合
- LinkedList 是一个双向链表结构的集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TJJAhO7O-1600262694815)(C:\Users\Lenovo\Desktop\md\photo\Linkedlist.png)]
实际开发中一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法: 【参考API】
package com.bdit.text;
import java.util.LinkedList;
public class Text01 {
public static void main(String[] args) {
LinkedList<String> linkedList = new LinkedList<>();
linkedList.add("张三");
linkedList.add(1,"李四");
linkedList.addFirst("王五");
linkedList.addLast("甲一");
System.out.println(linkedList);
System.out.println(linkedList.get(1));//返回此列表中指定位置的元素。
System.out.println(linkedList.getFirst());//返回此列表中的第一个元素
System.out.println(linkedList.peek());//检索但不删除此列表的头(第一个元素)。
System.out.println(linkedList.peekFirst());//检索但不删除此列表的第一个元素,如果此列表为空,则返回 null 。
System.out.println(linkedList.peekLast());
System.out.println("--------------------------------------------------------------");
System.out.println(linkedList);
System.out.println(linkedList.poll());//检索并删除此列表的头(第一个元素)。
linkedList.pop();//从此列表表示的堆栈中弹出一个元素
System.out.println(linkedList.pop());
}
}
3.3 补充 数字格式化类 DecimalFormat
- java.tetx.DecimalFormat 是针对十进制数字进行格式化的一个类
- 格式化字符串说明:
- 0 就代表一个数字(0也可以代表整体整数)
- #字符也是代表一个数字(#也可以代表整体整数) ,只不过它如果对应的位数上是0,则返回空
- . 小数的分隔符
- ,数字位数的分隔符
- % 代表当前数字所对应的百分比
package com.bdit.text;
import java.text.DecimalFormat;
public class Text02 {
public static void main(String[] args) {
DecimalFormat decimalFormat01 =new DecimalFormat("0,000,000.00");
System.out.println(decimalFormat01.format(1236547.3026));
DecimalFormat decimalFormat02 = new DecimalFormat("#,###,###,####.###");
System.out.println(decimalFormat02.format(32630056.30202));
DecimalFormat decimalFormat03 = new DecimalFormat("0.00");
System.out.println(decimalFormat03.format(23654913.0360));
DecimalFormat decimalFormat04 = new DecimalFormat("#.#");
System.out.println(decimalFormat04.format(36742.362));
// 以上四个 会自动保留小数点后n位(n是在小数点后定义的几个),会四舍五入,小数点前不会改变
DecimalFormat decimalFormat05 = new DecimalFormat("0.0%");
System.out.println(decimalFormat05.format(0.88));
将小数点后一两位,如果没有数字则输出,输出以 0% 结尾,如果后面还有数字则进行四舍五入一位最后在以%结尾。
DecimalFormat decimalFormat01 = new DecimalFormat("");
System.out.println(decimalFormat01.format(0.88));
System.out.println(decimalFormat01.format(1.88));
System.out.println(decimalFormat01.format(21.88));
System.out.println(decimalFormat01.format(123456.361852147));
// 如果0开头则会自动省略0然后输出后面的,其余的则正常输出
DecimalFormat decimalFormat01 = new DecimalFormat("0");
System.out.println(decimalFormat01.format(0.88));
System.out.println(decimalFormat01.format(1.88));
System.out.println(decimalFormat01.format(21.88));
System.out.println(decimalFormat01.format(123456.361852147));
// 只输出小数点前的后的则会四舍五入自动取消
}
}
四、练习
4.1 斗地主
- 按照斗地主的规则,完成洗牌发牌的功能:
- 具体规则:
- 使用54张牌打乱顺序,三个玩家参与游戏,三人交替摸牌,每人17张牌,最后三张留作底牌。
- 提示:【洗牌可以使用Collections类中的shuffle方法完成】
4.1.2 分析
- 准备牌
- 牌可以设计为一个ArrayList集合,每个字符串为一张牌
- 每张牌由花色数字两部分组成,我们可以使用花色集合与数字集合,然后嵌套迭代完成每张牌的组装。
- 然后再由Collections.shuffle()
- 发牌
- 将每个人以及底牌设计为ArrayList,将最后3张牌直接存储于底牌,剩余牌通过对3取余依次发牌
- 看牌
- 直接打印每个集合
package com.bdit.text;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
public class Text01 {
public static void main(String[] args) {
int zz = 0;
//准备牌
//牌可以设计为一个ArrayList集合,每个字符串为一张牌(牌盒子)
ArrayList<String> baccara = new ArrayList<>();
//每张牌由花色数字两部分组成,我们可以使用花色集合与数字集合,然后嵌套迭代完成每张牌的组装。
ArrayList<String> flower = new ArrayList<>();
flower.add("黑桃"); flower.add("红桃");flower.add("梅花");flower.add("方片");
ArrayList<String> nums = new ArrayList<>();
nums.add("2");nums.add("A");nums.add("K");nums.add("Q");
nums.add("J");nums.add("10");nums.add("9");nums.add("8");
nums.add("7");nums.add("6");nums.add("5");nums.add("4");
nums.add("3");
// List<String> flower = List.of("黑桃","红桃","梅花","方片");
// List<String> nums = List.of("2","A","K","Q","J","10","9","8","7","6","5","4","3");
// Iterator<String> it = flower.listIterator();
// Iterator<String> itt = nums.listIterator();
//遍历两个,输出除王之外的其余的牌
for (int i = 0; i < flower.size(); i++) {
for (int j = 0; j < nums.size(); j++) {
// add.baccara(flower.get(i)+nums.get(j)));
// zz++;
//存入牌盒子
baccara.add(flower.get(i)+nums.get(j));
}
}
// System.out.println(baccara);
//将王存入牌中
baccara.add("大王");
baccara.add("小王");
// System.out.println("一套牌,规律排放:"+baccara);
// 然后再由Collections.shuffle()洗牌
Collections.shuffle(baccara);
// System.out.println("使用 Collections.shuffle() 后的牌:"+baccara);
// 发牌
// 将每个人以及底牌设计为ArrayList,将最后3张牌直接存储于底牌,剩余牌i通过对3取余依次发牌
ArrayList<String> playerOne = new ArrayList<>();
ArrayList<String> playerTwo = new ArrayList<>();
ArrayList<String> playerThree = new ArrayList<>();
ArrayList<String> Cards = new ArrayList<>();
for (int i = 0; i < baccara.size(); i++) {
if(i>=51){
Cards.add(baccara.get(i));
}else if(i%3==0){
playerOne.add(baccara.get(i));
}else if(i%3==1){
playerTwo.add(baccara.get(i));
}else if(i%3==2){
playerThree.add(baccara.get(i));
}
}
System.out.println(baccara);
System.out.println("农名一的手牌:"+playerOne);
System.out.println("农名二的手牌:"+playerTwo);
System.out.println("地主牌为:"+Cards);
System.out.println("地主的手牌:"+playerThree);
playerThree.addAll(Cards);
System.out.println("地主的最终手牌:"+playerThree);
/* System.out.print("农名一的手牌:");
Iterator it = playerOne.iterator();
while (it.hasNext()){
System.out.print(it.next()+" ");
}*/
}
}
4.2 人民币小写转大写的功能
五、Set接口
5.1 概述
- java.util.Set 接口同样继承自 Collection 接口,Set接口中元素无序,存入的元素不会重复出现
- set集合在数据存储和检索,效率都比较高
5.2 HashSet 集合
- 它所存储的元素不可重复,并且元素都是无序的即存取的顺序不一致,java.util.HashSet底层的实现类其实是一个java.util.HashMap。
package com.bdit.text;
import java.util.HashSet;
public class Text03 {
public static void main(String[] args) {
HashSet<String> hashSet = new HashSet<>();
hashSet.add("张三");
hashSet.add("张1三");
hashSet.add("张2三");
hashSet.add("张3三");
hashSet.add("李四");
hashSet.add("王五");
System.out.println(hashSet);
}
}
5.3 HashSet 集合存储数据的结构
- 哈希表
- 在JDK1.8之前,哈希表底层采用数组+链表实现。
- 在JDK1.8中,哈希表存储采用数组+链表+红黑树结构实现。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-T6TVnq6R-1600262694827)(C:\Users\Lenovo\Desktop\md\photo\HsahSet.png)]
package com.bdit.text;
import java.util.Objects;
public class Text04 {
public String name;
public int age;
public Text04(){}
public Text04(String name,int age){
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Text04 text04 = (Text04) o;
return age == text04.age &&
Objects.equals(name, text04.name);
}
@Override
public int hashCode() {
return Objects.hash(name, age);
}
}
package com.bdit.text;
import java.util.HashSet;
import java.util.Iterator;
//set 集合无序不能重复
//但是 在调用对象时 就会变成无序但可重复,所以要在加equals() 和 hashCode()
public class Text04_01 {
public static void main(String[] args) {
HashSet<Text04> hashSet = new HashSet<>();
hashSet.add(new Text04("张三",25));
hashSet.add(new Text04("李四",26));
hashSet.add(new Text04("王五",27));
hashSet.add(new Text04("王五",27));
for (Text04 text04:hashSet){
System.out.println(text04);
}
System.out.println("--------------------------------------------------------");
//此时最后一条信息也能输出,需要加equals() 和 hashCode()
Iterator it = hashSet.iterator();
while (it.hasNext()){
System.out.println(it.next());
}
}
}
【如果两个对象相同,则他们的hashCode值就一定相同;但是两个对象的hashCode值相同,但是这两个对象不一定相同】
5.4 LinkedHashSet
- HashSet 是元素无序的
- 在HashSet下面有一个类java.util.LinkedHashSet,它可以记录元素存储的顺序,并且能够按照所记录的顺序进行输出
package com.bdit.verification;
import java.util.LinkedList;
public class Verifi01 {
public static void main(String[] args){
LinkedList<Integer> linkedList =new LinkedList<>();
linkedList.add(1);
linkedList.add(2);
linkedList.add(3);
linkedList.add(4);
System.out.println(linkedList);
System.out.println("---------------------------");
for (Integer int01 : linkedList){
System.out.println(int01);
}
}
}
5.5 Set集合无序不重复原因:
- 不重复:
- 对于基本数据类型来说,Set集合会直接比较是否相等,相等就去掉重复
- 对于引用数据类型
- Set集合每次添加元素的时候,会自动提取两个对象
- 然后这个两个对象调用自己的hashCode()方法(继承自Object)得到彼此的哈希值
- 然后判断两个对象的哈希值是否相同,如果不同则保留
- 如果两个对象的哈希值一致,就会进行equlas比较,如果equlas结果一致,则会保留一个
- 无序的
- Set集合底层基于哈希表存储
- jdk1.8 之前,哈希表由数组和链表组成,jdk1.8之后哈希表由数组链表和二叉树组成,如果链表的长度超过获取等于了阈值(7)的时候会自动转成红黑树,性能进一步提高了
六、 可变参数
6.1 多个参数
- 在JDK5.0 之后,我们定义一个方法需要接受多个参数,并且多个参数的数据类型一致,我们可以对其写成如下:
- 修饰符 返回值类型 方法名(参数类型… 参数名){ }
其实等价于:
- 修饰符 返回值类型 方法名(参数类型[] 数组名){ }
只是后面这种定义,在调用时必须传递数组,而前者可以直接传递数据即可。
JDK1.5后,出现的这种简化操作,…用在参数上,称为可变参数。
package com.bdit.verification;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
public class Verifi01 {
public static void main(String[] args){
variable(1,2,3,4,5,6);
}
public static void variable(int... a){
for (int int01:a){
System.out.print(int01+" ");
}
}
}
七、Collections
- Collections 是一个集合的工具类,不同于Collection
7.1 常用功能
- public static boolean addAll(Collection<? super T> c, T… elements):往集合中添加一些元素
- public static void shuffle(List<?> list):对集合中的元素进行随机排列
- public void static <T extends Comparable<? super T>> sort(List list) :升序排列
package com.bdit.text;
import java.security.cert.CertificateParsingException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class Text06 {
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(9);
list.add(8);
System.out.println(list);
Collections.addAll(list,4,5,6);
System.out.println(list);
Collections.sort(list);//升序
System.out.println(list);
Collections.shuffle(list);//随机排序
System.out.println(list);
//复制
List<Integer> list99 = new ArrayList<>();
list99.add(12);
list99.add(22);
list99.add(33);
List<Integer> listco = new ArrayList<>(Arrays.asList(new Integer[list99.size()]));
Collections.copy(listco,list99);
System.out.println(listco);
}
}
7.2 Comparator 比较器
- 进行元素的排序,其实就是两个对象之间比较大小,在Java中提供了两种比较的方式,一种是比较死板的 java.lang.Comparable 接口实现,一种是灵活的可以指定排序规则的 jva.util.Comparator 接口完成
- 第一种是:实现Comparable接口完成的操作,但是这种方法会把规则给写死
package com.bdit.text;
//comp
//因为 TreeSet 无法排序对象 所以在对象这 继承Comparable 并且,在其的抽象方法内,重写规则
public class Test07 implements Comparable{
private String name;
private int age;
public Test07(){}
public Test07(String name,int age){
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;
}
@Override
public String toString() {
return "Test07{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//排序规则
@Override
public int compareTo(Object o) {
Test07 test07 = (Test07) o;
if(this.age>test07.age){
return -1;
}else if(this.age<test07.age){
return 1;
}else {
return 0;
}
}
}
package com.bdit.text;
import java.util.ArrayList;
import java.util.TreeSet;
public class Test07_01 {
public static void main(String[] args) {
ArrayList<Test07> arrayList = new ArrayList<>();
arrayList.add(new Test07("张三",20));
arrayList.add(new Test07("李四",21));
arrayList.add(new Test07("王五",22));
arrayList.add(new Test07("王算术",22));
Collections.sort(arrayList);
System.out.println(arrayList);
}
}
如果想要改变条件,就要更改一次源代码,这肯定是不合适的,所以这就有了第二种方法、
- Comparator 接口,代表一个比较器,一般比较方法为:
- public int compare(T o1,T o2):比较两个参数的顺序
- 两个对象比较的结果有三种:大于,等于,小于
- 如果按照升序排列,则o1小于o2返回负数,相等返回0,o1大于o2返回正数;
- 如果按照降序排列,则o1小于o2返回正数,相等返回0,o1大于o2返回负数
Comparator比较器
*/
public class Test9 {
public static void main(String[] args) {
ArrayList<String> list2=new ArrayList<>();
list2.add("cba");
list2.add("abc");
list2.add("bca");
list2.add("123");
list2.add("true");
Collections.sort(list2, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//升序排列
// if(o1.charAt(0)<o2.charAt(0)){
// return -1;
// }else if(o1.charAt(0)==o2.charAt(0)){
// return 0;
// }else{
// return 1;
// }
//降序排列
if(o1.charAt(0)<o2.charAt(0)){
return 1;
}else if(o1.charAt(0)==o2.charAt(0)){
return 0;
}else{
return -1;
}
}
});
System.out.println(list2);
}
}
package com.bdit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*
对自定义对象进行升序或降序排列
*/
public class Test10 {
public static void main(String[] args) {
ArrayList<Student> list=new ArrayList<>();
list.add(new Student(1001,"zhangsan"));
list.add(new Student(1002,"lisi"));
list.add(new Student(1003,"wangwu"));
list.add(new Student(1004,"haha"));
//根据id降序
//Collections.sort(list,new MyComparator1());
//根据name升序
Collections.sort(list,new MyComparator2());
for(Student stu:list){
System.out.println(stu);
}
}
}
//根据id降序排列的比较器
class MyComparator1 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
if(o1.getId()<o2.getId()){
return 1;
}else if(o1.getId()==o2.getId()){
return 0;
}else{
return -1;
}
}
}
//根据name 进行升序排列
class MyComparator2 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
if(o1.getName().charAt(0)<o2.getName().charAt(0)){
return -1;
}else if(o1.getName().charAt(0)==o2.getName().charAt(0)){
return 0;
}else{
package com.bdit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*
Comparator比较器
*/
public class Test9 {
public static void main(String[] args) {
ArrayList<String> list2=new ArrayList<>();
list2.add("cba");
list2.add("abc");
list2.add("bca");
list2.add("123");
list2.add("true");
Collections.sort(list2, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
//升序排列
// if(o1.charAt(0)<o2.charAt(0)){
// return -1;
// }else if(o1.charAt(0)==o2.charAt(0)){
// return 0;
// }else{
// return 1;
// }
//降序排列
if(o1.charAt(0)<o2.charAt(0)){
return 1;
}else if(o1.charAt(0)==o2.charAt(0)){
return 0;
}else{
return -1;
}
}
});
System.out.println(list2);
}
}
package com.bdit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
/*
对自定义对象进行升序或降序排列
*/
public class Test10 {
public static void main(String[] args) {
ArrayList<Student> list=new ArrayList<>();
list.add(new Student(1001,"zhangsan"));
list.add(new Student(1002,"lisi"));
list.add(new Student(1003,"wangwu"));
list.add(new Student(1004,"haha"));
//根据id降序
//Collections.sort(list,new MyComparator1());
//根据name升序
Collections.sort(list,new MyComparator2());
for(Student stu:list){
System.out.println(stu);
}
}
}
//根据id降序排列的比较器
class MyComparator1 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
if(o1.getId()<o2.getId()){
return 1;
}else if(o1.getId()==o2.getId()){
return 0;
}else{
return -1;
}
}
}
//根据name 进行升序排列
class MyComparator2 implements Comparator<Student>{
@Override
public int compare(Student o1, Student o2) {
if(o1.getName().charAt(0)<o2.getName().charAt(0)){
return -1;
}else if(o1.getName().charAt(0)==o2.getName().charAt(0)){
return 0;
}else{
return 1;
}
}
}
7.3 Comparable和Comparator接口的区别
Comparable:强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的compareTo方法被称为它的自然比较方法。只能在类中实现compareTo方法一次,不能经常修改类的代码实现自己想要的排序。实现此接口的对象可以通过Collection.sort()方法进行自动排序。
Comparator强行对某个对象进行整体排序,可以将Comparator传递给sort方法,从而允许在排序顺序上实现自定义控制。
八 、MAP集合
8.1 概述
- 在生活中,常常有:IP地址与主机名,身份证与个人,系统用户名和系统对象等,这种一一对应的关系,叫做映射,Java中提供了专门的集合类用来存放这种关系,即 java.util.Map 接口
- Map接口 不是Collection 接口的子接口,它存储的数据形似与Collection 接口也不同
- Map接口 存储数据的形式是:双列集合的规则 Map<K,V> K 代表的是键的类型,V代表的是值的类型,往 Map 接口中存储数据时,存储的是一对元素
- Map 接口中键是唯一的,值可以重复
- Map 可以用null最为键和值
- Map 集合中的元素也是无序的
- Map 集合中的 KEY 是通过Set集合来存储的,如果用自定义对象作为键,必须重写hasCode 和 equals 方法
8.2 Map 常用子类
- HashMap:存储数据采用的是哈希表结构,元素的顺序无序,要保证键的唯一、不重复,需要重写建的l hashCode方法和equals方法。
- LinkHashMap:它是HashMap的子列,存储数据采用的是哈希表+链表,通过链表可以保证元素的存取顺序一致,但是要保证键的唯一不重复要重写l hashCode方法和equals方法。
- 【Map集合有两个泛型变量,这两个都要赋予数据类型,可以相同也可不同】
8.3 Map接口的常用方法
- public V put(V key,V value):把指定的键与指定的值添加到Map集合中
- public V remove(Object key):把指定的键所对应的键值对元素在Map集合中删除,返回被删除元素的值
- public V get(Object key):根据指定的键,在Map集合中获取对应的值
- public Set keyset():获取Map集合中所有的键,存储到Set集合中
- public Set<Map.Entry<K,V>> entrySet():获取到Map集合中所有键值对对象的集合
package com.bdit;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
/**
* Map集合接口 HashMap
*/
public class Test18 {
public static void main(String[] args) {
HashMap<String,String> map=new HashMap<>();
map.put("a","zhangsan");
map.put("b","李四");
map.put("c","小明");
map.put("a","小红");
map.put(null,null);
//map.remove("c");
System.out.println(map);
System.out.println(map.get("b"));
//
Set<String> set=map.keySet();
for(String key:set){
System.out.println("----->"+map.get(key));
}
System.out.println(map.size());
/**
* Entry表示Map集合中的每个键值对的对象
*/
Set<Map.Entry<String,String>> set2=map.entrySet();
for(Map.Entry<String,String> entry:set2){
System.out.println(entry.getKey()+"------>"+entry.getValue());
}
}
}
8.4 HashMap 存储之定义类型键值对
package com.bdit;
import java.util.HashMap;
import java.util.Map;
/* HashMap存储自定义类型的键值对 */
public class Test2 {
public static void main(String[] args) { Map<Student,String> map=new HashMap<>(); map.put(new Student("张三",21),"北京");
map.put(new Student("李四",22),"上海");
map.put(new Student("王五",23),"山东"); for(Map.Entry<Student,String> entry:map.entrySet()){ System.out.println(entry.getKey()+"---->"+entry.getValue());
}
}
}
8.5 LinkedHashMap
- 我们知道HashMap元素无序,但是查询速度快,如果要保证添加元素的顺序,还要有速度怎么办呢?LinkedHashMap就可以保证元素的顺序,而且同样查询速度比较快。
package com.bdit;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
public class Test3 {
public static void main(String[] args) {
Map<String,String> map=new LinkedHashMap<>();
map.put("a","张三");
map.put("b","李四");
map.put("c","王五");
map.put(null,null);
System.out.println(map);
for(Map.Entry<String,String> entry:map.entrySet()){
System.out.println(entry.getKey()+"---->"+entry.getValue());
}
}
}
8.6 练习
要求:
计算一个字符串中每个字符出现的次数
package com.bdit.test;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
//用Map接口实现计算一个字符串中每个字符出现的次数
public class Test02 {
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
System.out.println("输入一个字符串:");
String str = sc.next();
Map<Character,Integer> map = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
Character c =str.charAt(i);
if (!map.containsKey(c)){
map.put(c,1);
}else{
int num = map.get(c);
map.put(c,num+1);
}
}
System.out.println(map);
}
}
ll,null);
System.out.println(map);
for(Map.Entry<String,String> entry:map.entrySet()){
System.out.println(entry.getKey()+“---->”+entry.getValue());
}
}
}
#### 8.6 练习
要求:
计算一个字符串中每个字符出现的次数
package com.bdit.test;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Scanner;
//用Map接口实现计算一个字符串中每个字符出现的次数
public class Test02 {
public static void main(String[] args) {
Scanner sc =new Scanner(System.in);
System.out.println("输入一个字符串:");
String str = sc.next();
Map<Character,Integer> map = new HashMap<>();
for (int i = 0; i < str.length(); i++) {
Character c =str.charAt(i);
if (!map.containsKey(c)){
map.put(c,1);
}else{
int num = map.get(c);
map.put(c,num+1);
}
}
System.out.println(map);
}
}
File类、递归
九、 File 类
9.1 概述
- java.io.File 类是文件和目录路径名的抽象表示,主要用于文件和目录的创建,查找,删除等操作
9.2 构造方法
- public File (String name):通过将给定的路径字符串转换为抽象路径名来创建File对象
- public File(String parent,String child):从父路径名字符串和子路径名字符串创建新的File对象
- public File(File parent,String child):从父路径名字符串和子路径名字符串创建新的File对象
package com.bdit;
import java.io.File;
/*
File对象创建
*/
public class Demo1 {
public static void main(String[] args) {
File file1=new File("e:\\a.txt");
File file2=new File("d:\\","abc\\b.txt");
File file3=new File("e:\\");
File file4=new File(file3,"bdit");
}
}
【1、一个File 对象代表的是某个路径下的一个文件或者目录
2、无论该目录下是否存在文件或目录。都不影响File对象的创建】
9.3常用方法
- public String getAbsolutePath():返回此File的绝对路径名字符串
- public String getPath():将此File转换为路径名字符串
- public String getName():返回由此File表示的文件或目录名
- public long length():返回由此File表示的文件的长度
- public String getParent():返回由此File对象表示的路径的父目录
package com.bdit;
import java.io.File;
public class Demo2 {
public static void main(String[] args) {
File f=new File("e:/aaa/bbb/c.txt");
System.out.println("文件的绝对路径:"+f.getAbsolutePath());
System.out.println("文件的构造路径:"+f.getPath());
System.out.println("文件名称:"+f.getName());
System.out.println("文件父目录:"+f.getParent());
System.out.println("文件长度:"+f.length());
}
}
9.4 绝对路径和相对路径
- 绝对路径:从盘符开始的路径,是一个完整的路径
- 相对路径:相对于某个路径的路径,这是一个便捷的路径
9.5 判断功能的方法
- public boolean exists():此File表示的文件或目录是否真的存在
- public boolean isDirectory():此File表示的是否为目录
- public boolean isFile():此File表示的是否为文件
- public boolean isHidden():此FIle表示的是否为隐藏文件
package com.bdit;
import java.io.File;
/*
File判断相关的方法
*/
public class Demo3 {
public static void main(String[] args) {
File file=new File("E:\\aaa\\bbb");
System.out.println("是否存在:"+file.exists());
System.out.println("是否为目录:"+file.isDirectory());
System.out.println("是否为文件:"+file.isFile());
System.out.println("是否为隐藏:"+file.isHidden());
}
9.6 创建删除功能的方法
- public boolean createNewFile():如果不存在就创建一个空的文件
- public boolean delete():删除由此File表示的文件或目录
- public boolean mkdir():创建由此File表示的目录
- public boolean mkdirs():创建由此File表示的目录,包括任何必须但不存在的父目录
- public boolean renameTo(File dest):重命名
package com.bdit;
import java.io.File;
/*
创建删除功能的方法
*/
public class Demo4 {
public static void main(String[] args) {
File f1=new File("E:\\aaa\\bbb\\d.txt");
try{
if(!f1.exists()) {
f1.createNewFile();
}
}catch (Exception se){
se.printStackTrace();
}
f1.delete();
File f2=new File("E:\\bdit");
if(!f2.exists()) {
f2.mkdir();
}
f2.delete();
File f3=new File("E:\\java","javase");
f3.mkdirs();
File f4=new File("E:\\bdit");
f4.renameTo(new File("E:\\newbdit"));
}
}
9.7 目录的遍历
- public String[] list():返回一个String数组,表四该File目录中所有子文件或目录
- 遍历给出的目录,会把目录中所有的文件/文件夹放在一个String集合中
- 遍历一个空文件、路径有问题时都会爆出空指针异常的问题
- 可以遍历隐藏文件、文件夹
- public File[] listFiles():返回一个File数组,表示该File目录中所有的子文件或目录。
- 遍历构造方法中给出的目录,会获取目录中所有的文件/文件夹名称,把获取的文件/文件夹都封装成一个File对象,将多个File对象,存储在File数组中
package com.bdit;
import java.io.File;
import java.io.FilenameFilter;
/*
目录的遍历
*/
public class Demo5 {
public static void main(String[] args) {
File f=new File("E:\\");
String[]names=f.list();
for(String n:names){
System.out.println(n);
}
System.out.println("==================================");
File[]files=f.listFiles(new MyFileNameFilter());
for(File ff:files){
System.out.println("------>"+ff.getName());
}
}
}
class MyFileNameFilter implements FilenameFilter{
/**
*
* @param dir 表示当前过滤的File对象
* @param name 表示当前过滤的文件名
* @return
*/
@Override
public boolean accept(File dir, String name) {
if(name.endsWith(".txt")){
return true;
}
return false;
}
}
十、递归
10.1 概述
- 递归:就是在当前方法内调用自己的现象
- 分类:
- 直接递归:自己在方法中自己调用自己
- 间接递归:通过第三方但本质还是自己调用自己,如:A调用B,B调用C,C调用A
- 注意事项
- 递归一定要有条件限定,保证递归能停止下来,否则发生内存溢出
- 递归即使有条件限定,但递归次数也不能太多,否则会发生超出栈的内存,溢出
- 在构造方法中禁止递归。
- 构造方法是创建对象的,如果一直递归则会创建无数对象
- 使用前提
- 调用方法时,方法的主体不变,每次调用方法的参数不同,可以使用递归
10.2 练习
计算1-n的和
package com.bdit.vifition;
//1-n的和
//----->Verfie03
/**
* 1-n的和 也能看成 n-1 的和
* 已知:
* 最大值:n
* 最小值:1
* 使用递归必须明确:
* 1. 递归的结束条件 (获取到1的时候)
* 2.递归的目的 (获取下一个被加的数字)
* 假如:1-5(n):1 2 3 4 5
* 5(n)-1: 5 4 3 2 1
* : n n-1 n-2 n-3 ...... n
* 每次的参数会变化
* */
public class Verifi02 {
public static void main(String[] args) {
int su = sum(3);
System.out.println(su);
}
private static int sum(int n){
if (n == 1){
return 1;
}
/* System.out.println(n+"---");
System.out.println(sum(n-1)+"===");*/
// 递归的目的 (获取下一个被加的数字)
return n + sum(n-1);
}
}
10.3 练习
求5的阶乘
package com.bdit.vifition;
//求阶乘
//例:5的阶乘 5!= 5*(5-1)*(5-2)*(5-3)*(5-4)=5*4*3*2*1
public class Verfie03 {
public static void main(String[] args) {
int a =show01(5);
System.out.println(a);
}
private static int show01(int n) {
if (n == 1){
return n;
}
//获取下个被乘的数字
return n * show01(n-1);
}
}
10.4 练习
搜索某个目录中.java的文件,例如IDEA的工作空间:D:\2019-10\ideawork
package com.bdit.vifition;
/*
搜索某个目录中.java的文件,例如IDEA的工作空间:D:\2019-10\ideawork
分析:
1、 目录搜索,无法判断多少级目录,所以使用递归,遍历所有的目录
2、 遍历目录时,获取的子文件,通过文件名,判断是否符合条件
*/
import java.io.File;
public class Text02_01 {
public static void main(String[] args) {
File file01 = new File("f://bdit");
getfb(file01);
}
private static void getfb(File file01) {
File[] files01 = file01.listFiles();
for (File file: files01){
if (file.isDirectory()){
getfb(file);
}else{
String str01 = file.getName();//将File对象file转换成字符串对象
boolean bool = str01.endsWith(".java");
if (bool){
System.out.println(file);
}
}
}
}
}