TreeSet保证元素唯一和自然排序的原理和图解
package com.heima.bean;
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
/*@Override
public boolean equals(Object obj) {
System.out.println("执行了吗");
Person p = (Person)obj;
return this.name.equals(p.name) && this.age == p.age;
}
@Override
public int hashCode() {
final int NUM = 38;
return name.hashCode() * NUM + age;
}*/
/*
* 为什么是31?
* 1,31是一个质数,质数是能被1和自己本身整除的数
* 2,31这个数既不大也不小
* 3,31这个数好算,2的五次方-1,2向左移动5位减一
*/
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + ((name == null) ? 0 : name.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) //调用的对象和传入的对象是同一个对象
return true; //直接返回true
if (obj == null) //传入的对象为null
return false; //返回false
if (getClass() != obj.getClass()) //判断两个对象对应的字节码文件是否是同一个字节码
return false; //如果不是直接返回false
Person other = (Person) obj; //向下转型
if (age != other.age) //调用对象的年龄不等于传入对象的年龄
return false; //返回false
if (name == null) { //调用对象的姓名为null
if (other.name != null) //传入对象的姓名不为null
return false; //返回false
} else if (!name.equals(other.name))//调用对象的姓名不为null,且不等于传入对象的姓名
return false; //返回false
return true; //返回true
}
//按照年龄排序
/*@Override
public int compareTo(Person o) {
int num = this.age - o.age; //年龄是比较的主要条件
return num == 0 ? this.name.compareTo(o.name) : num;
}*/
//按照姓名排序
/*@Override
public int compareTo(Person o) {
int num = this.name.compareTo(o.name); //姓名是比较的主要条件,字符串的compareTo方法
return num == 0 ? this.age - o.age : num;
}*/
//按照姓名长度排序
@Override
public int compareTo(Person o) {
int length = this.name.length() - o.name.length(); //比较长度为主要条件
int num = length == 0 ? this.name.compareTo(o.name) : length; //比较内容为次要条件
return num == 0 ? this.age - o.age : num; //最后比较年龄
}
}
package com.heima.set;
import java.util.TreeSet;
import com.heima.bean.Person;
public class Demo3_TreeSet {
/**
* TreeSet集合是用来对元素进行排序的,同样他也可以保证元素的唯一
* 由于Person没有指定比较,所以需要重写compareTo方法
* 当compareTo方法返回0的时候集合中只有一个元素
* 当compareTo方法返回正数的时候集合会怎么存就怎么取
* 当compareTo方法返回负数的时候集合会倒序存储
*/
public static void main(String[] args) {
System.out.println('周' + 0);
System.out.println('张' + 0);
System.out.println('李' + 0);
System.out.println('王' + 0);
System.out.println('赵' + 0);
demo2();
}
public static void demo2() {
TreeSet<Person> ts = new TreeSet<>();
ts.add(new Person("张三11111", 23));
ts.add(new Person("李四1111", 13));
ts.add(new Person("周七222", 13));
ts.add(new Person("王五11", 43));
ts.add(new Person("赵六1", 33));
System.out.println(ts);
}
public static void demo1() {
TreeSet<Integer> ts = new TreeSet<>();
ts.add(4);
ts.add(1);
ts.add(1);
ts.add(2);
ts.add(2);
ts.add(3);
ts.add(3);
System.out.println(ts);
}
}
TreeSet保证元素唯一和比较器排序的原理及代码实现
package com.heima.set;
import java.util.Comparator;
import java.util.TreeSet;
import com.heima.bean.Person;
public class Demo3_TreeSet {
/**
* TreeSet集合是用来对元素进行排序的,同样他也可以保证元素的唯一
* 由于Person没有指定比较,所以需要重写compareTo方法
* 当compareTo方法返回0的时候集合中只有一个元素
* 当compareTo方法返回正数的时候集合会怎么存就怎么取
* 当compareTo方法返回负数的时候集合会倒序存储
*/
public static void main(String[] args) {
/*System.out.println('周' + 0);
System.out.println('张' + 0);
System.out.println('李' + 0);
System.out.println('王' + 0);
System.out.println('赵' + 0);*/
//demo2();
TreeSet<String> ts = new TreeSet<>(new CompareByLen()); //Comparator c = new CompareByLen()
ts.add("aaaaaaaa");
ts.add("z");
ts.add("wc");
ts.add("nba");
ts.add("cba");
System.out.println(ts);
}
public static void demo2() {
TreeSet<Person> ts = new TreeSet<>();
ts.add(new Person("张三11111", 23));
ts.add(new Person("李四1111", 13));
ts.add(new Person("周七222", 13));
ts.add(new Person("王五11", 43));
ts.add(new Person("赵六1", 33));
System.out.println(ts);
}
public static void demo1() {
TreeSet<Integer> ts = new TreeSet<>();
ts.add(4);
ts.add(1);
ts.add(1);
ts.add(2);
ts.add(2);
ts.add(3);
ts.add(3);
System.out.println(ts);
}
}
class CompareByLen implements Comparator<String> {
//由于CompareByLen默认继承Object类,继承了equals方法,所以不用去重写equals方法
//但是一定要重写compare方法
@Override
public int compare(String s1, String s2) { //按照字符串长度比较
int num = s1.length() - s2.length(); //长度为主要条件
return num == 0 ? s1.compareTo(s2) : num; //内容为次要条件
}
}
TreeSet原理
- 1.特点
- TreeSet是用来排序的,可以指定一个顺序,对象存入之后会按照指定的顺序排列
- 2.使用方式
- a.自然顺序(Comparable)
- TreeSet类的add()方法中会把存入的对象提升为Comparable类型
- 调用对象的compareTo()方法和集合中的对象比较
- 根据compareTo()方法返回的结果进行存储
- 存入谁谁就会调用compareTo()方法,集合中的元素作为参数传入
- b.比较器顺序(Comparator)
- 创建TreeSet的时候可以制定 一个Comparator
- 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器中的顺序排序
- add()方法内部会自动调用Comparator接口中compare()方法排序
*调用add()方法的对象是compare()方法的第一个参数,集合里面的元素就相当于第二个参数
- c.两种方式的区别
- TreeSet构造函数什么都不传,默认按照类中Comparable的顺序(没有就报错classCastException)
- TreeSet如果传入Comparator,就优先按照Comparator
- a.自然顺序(Comparable)
练习
package com.heima.test;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.TreeSet;
public class Test4 {
/**
* 在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
* 1,定义一个List集合,并存储重复的无序的字符串
* 2,定义方法对其排序保留重复
* 3,打印List集合
*/
public static void main(String[] args) {
//1,定义一个List集合,并存储重复的无序的字符串
ArrayList<String> list = new ArrayList<>();
list.add("aaa");
list.add("aaa");
list.add("ccc");
list.add("ddd");
list.add("fffffffffff");
list.add("heima");
list.add("itcast");
list.add("bbbb");
list.add("aaa");
list.add("aaa");
//2,定义方法对其排序保留重复
sort(list);
//3,打印list
System.out.println(list);
}
/*
* 1,创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用比较器
* 2,将List集合中所有的元素添加到TreeSet集合中,对其排序,保留重复
* 3,清空List集合
* 4,将TreeSet集合中排好序的元素添加到list中
*/
public static void sort(List<String> list) {
//1,创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用比较器
TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
//匿名内部类
@Override
public int compare(String s1, String s2) {
int num = s1.compareTo(s2); //比较内容为主要条件
return num == 0 ? 1 : num; //保留重复
}
});
//2,将List集合中所有的元素添加到TreeSet集合中,对其排序,保留重复
ts.addAll(list);
//3,清空List集合
list.clear();
//4,将TreeSet集合中排好序的元素添加到list中
list.addAll(ts);
}
}
package com.heima.test;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class Test5 {
/**
* 从键盘接收一个字符串,程序对其中所有字符进行排序,例如键盘输入:helloitcast程序打印:acehillostt
* 1,键盘录入字符串,Scanner
* 2,将字符串转换为字符数组
* 3,定义TreeSet集合,传入比较器对字符排序并保留重复
* 4,遍历字符数组,将每一个字符存储在TreeSet集合中
* 5,遍历TreeSet集合,打印每一个字符
*/
public static void main(String[] args) {
//1,键盘录入字符串,Scanner
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个字符串");
String line = sc.nextLine();
//2,将字符串转换为字符数组
char[] arr = line.toCharArray();
//3,定义TreeSet集合,传入比较器对字符排序并保留重复
TreeSet<Character> ts = new TreeSet<>(new Comparator<Character>() {
@Override
public int compare(Character c1, Character c2) {
//int num = c1 - c2; //自动拆箱
int num = c1.compareTo(c2);
return num == 0 ? 1 : num;
}
});
//4,遍历字符数组,将每一个字符存储在TreeSet集合中
for (char c : arr) {
ts.add(c); //自动装箱
}
//5,遍历TreeSet集合,打印每一个字符
for (Character c : ts) {
System.out.print(c);
}
}
}
package com.heima.test;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class Test6 {
/**
* 程序启动后,可以从键盘输入接收多个整数,直到输入quit时结束输入.把所有输入的整数倒序排列打印.
* 1,创建Scanner对象,键盘录入
* 2,创建TreeSet集合对象,TreeSet集合中传入比较器
* 3,无限循环不断接收整数,遇到quit退出,因为退出是quit,所以键盘录入的时候应该都以字符串的形式录入
* 4,判断是quit就退出,不是就将其转换为Integer,并添加到集合中
* 5,遍历TreeSet集合并打印每一个元素
*/
public static void main(String[] args) {
//1,创建Scanner对象,键盘录入
Scanner sc = new Scanner(System.in);
//2,创建TreeSet集合对象,TreeSet集合中传入比较器
TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() {
@Override
public int compare(Integer i1, Integer i2) {
//int num = i2 - i1; //自动拆箱
int num = i2.compareTo(i1);
return num == 0 ? 1 : num;
}
});
//3,无限循环不断接收整数,遇到quit退出,因为退出是quit,所以键盘录入的时候应该都以字符串的形式录入
while(true) {
String line = sc.nextLine(); //将键盘录入的字符串存储在line中
//4,判断是quit就退出,不是就将其转换为Integer,并添加到集合中
if("quit".equals(line)) {
break;
}
Integer i = Integer.parseInt(line);
ts.add(i);
}
//5,遍历TreeSet集合并打印每一个元素
for (Integer integer : ts) {
System.out.println(integer);
}
}
}
package com.heima.test;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
import com.heima.bean.Student;
public class Test7 {
/**
* 需求:键盘输入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
* 1,定义一个学生类
* 成员变量:姓名,语文成绩,数学成绩,英语成绩,总成绩
* 成员方法:空参,有参构造,有参构造的参数分别是姓名,语文成绩,数学成绩,英语成绩
* ToString方法,在遍历集合中的Student对象打印对象引用的时候会显示属性值
* 2,键盘录入需要Scanner,创建键盘录入对象
* 3,创建TreeSet集合对象,在TreeSet的构造函数中传入比较器,按照总分比较
* 4,录入五个学生,所以以集合中的学生个数为判断条件,如果size是小于5就存储
* 5,将录入的字符串切割,用逗号切割,会返回一个字符串数组,从第二个元素开始,将字符串数组中的元素转换成int数
* 6,将转换后的结果封装成Student对象,将Student添加到TreeSet集合中
* 7,遍历TreeSet集合打印每一个Student对象
*/
public static void main(String[] args) {
//2,键盘录入需要Scanner,创建键盘录入对象
Scanner sc = new Scanner(System.in);
System.out.println("请输入学生成绩,格式是:姓名,语文成绩,数学成绩,英语成绩");
//3,创建TreeSet集合对象,在TreeSet的构造函数中传入比较器,按照总分比较
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getSum() - s1.getSum();
return num == 0 ? 1 : num;
}
});
//4,录入五个学生,所以以集合中的学生个数为判断条件,如果size是小于5就存储
while(ts.size() < 5) {
//5,将录入的字符串切割,用逗号切割,会返回一个字符串数组,从第二个元素开始,将字符串数组中的元素转换成int数
String line = sc.nextLine();
String[] arr = line.split(",");
int chinese = Integer.parseInt(arr[1]);
int math = Integer.parseInt(arr[2]);
int english = Integer.parseInt(arr[3]);
//6,将转换后的结果封装成Student对象,将Student添加到TreeSet集合中
ts.add(new Student(arr[0], chinese, math, english));
}
//7,遍历TreeSet集合打印每一个Student对象
System.out.println("排序后的学生信息");
for (Student s : ts) {
System.out.println(s);
}
}
}
Map集合概述和特点
- A:Map接口概述
- 查看API可以知道:
- 将键映射到值的对象
- 一个映射不能包含重复的键
- 每个键最多只能映射到一个值
- 查看API可以知道:
- B:Map接口和Collection接口的不同
- Map是双列的,Collection是单列的
- Map的键唯一,Collection的子体系Set是唯一的
- Map集合的数据结构值针对键有效,跟值无关;Collection集合的数据结构是针对元素有效
set底层依赖于map
Map集合的功能概述
- A:Map集合的功能概述
- a:添加功能
- V put(K key,V value):添加元素。
- 如果键是第一次存储,就直接存储元素,返回null
- 如果键不是第一次存在,就用值把以前的值替换掉,返回以前的值
- V put(K key,V value):添加元素。
- b:删除功能
- void clear():移除所有的键值对元素
- V remove(Object key):根据键删除键值对元素,并把值返回
- c:判断功能
- boolean containsKey(Object key):判断集合是否包含指定的键
- boolean containsValue(Object value):判断集合是否包含指定的值
- boolean isEmpty():判断集合是否为空
- d:获取功能
- Set<Map.Entry<K,V>> entrySet():
- V get(Object key):根据键获取值
- Set<K> keySet():获取集合中所有键的集合
- Collection<V> values():获取集合中所有值的集合
- e:长度功能
- int size():返回集合中的键值对的个数
- a:添加功能
package com.heima.map;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
public class Demo1_Map {
/**
* @param args
*/
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六", 23);
Collection<Integer> c = map.values();
System.out.println(c);
System.out.println(map.size());
}
public static void demo2() {
Map<String, Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六", 23);
Integer value = map.remove("张三"); //根据键删除元素,返回键对应的值
System.out.println(value);
System.out.println(map.containsKey("张三")); //判断是否包含传入的键
System.out.println(map.containsValue(100)); //判断是否包含传入的值
System.out.println(map);
}
public static void demo1() {
Map<String, Integer> map = new HashMap<>();
Integer i1 = map.put("张三", 23);
Integer i2 = map.put("李四", 24);
Integer i3 = map.put("王五", 25);
Integer i4 = map.put("赵六", 26);
Integer i5 = map.put("张三", 26); //put方法返回的是被覆盖的值
System.out.println(map);
System.out.println(i1);
System.out.println(i2);
System.out.println(i3);
System.out.println(i4);
System.out.println(i5);
}
}
Map集合的遍历之键找值
- A:键找值思路:
- 获取所有键的集合
- 遍历键的集合,获取到每一个键
- 根据键找值
package com.heima.map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo2_Iterator {
/**
* 通过查看Map集合的api发现没有iterator方法,那么双列集合如何迭代呢?
*/
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六", 26);
Integer i = map.get("111"); //根据键获取值,若没有返回null
System.out.println(i);
//获取所有的键
/*Set<String> keySet = map.keySet(); //获取所有键的集合
Iterator<String> it = keySet.iterator(); //获取迭代器
while(it.hasNext()) { //判断集合中是否有元素
String key = it.next(); //获取每一个键
Integer value = map.get(key); //根据键获取值
System.out.println(key + "=" + value);
}*/
//使用增强for循环遍历
for (String key : map.keySet()) { //map.keySet()是所有键的集合
System.out.println(key + "=" + map.get(key));
}
}
}
Map集合的遍历之键值对对象找键和值
- A:键值对对象找键和值思路:
- 获取所有键值对对象的集合(把双列集合的键值对变成单列集合的键值对对象)
- 遍历键值对对象的集合,获取到每一个键值对对象
- 根据键值对对象找键和值
package com.heima.map;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Demo3_Iterator {
/**
* Entry实现了Map.Entry
*/
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("张三",23);
map.put("李四",24);
map.put("王五",25);
map.put("赵六", 26);
//Map.Entry说明Entry是Map的内部接口,将键和值封装成Entry对象,并存储在Set集合中
/*Set<Map.Entry<String, Integer>> entrySet = map.entrySet();
//获取每一个对象
Iterator<Map.Entry<String, Integer>> it = entrySet.iterator();
while(it.hasNext()) {
//获取每一个Entry对象
Map.Entry<String, Integer> en = it.next(); //父类引用指向子类对象
//Entry<String, Integer> en = it.next(); //直接获取子类对象
String key = en.getKey(); //根据键值对对象获取键
Integer value = en.getValue(); //根据键值对对象获取值
System.out.println(key + "=" + value);
}*/
for (Map.Entry<String, Integer> en : map.entrySet()) {
System.out.println(en.getKey() + "=" + en.getValue());
}
}
}
package com.heima.map;
import java.util.HashMap;
import com.heima.bean.Student;
public class Demo5_HashMap {
/**
* HashMap集合键是Student值是String的案例
*/
public static void main(String[] args) {
HashMap<Student, String> hm = new HashMap<>();
hm.put(new Student("张三", 23), "北京");
hm.put(new Student("张三", 23), "上海");
hm.put(new Student("李四", 23), "广州");
hm.put(new Student("王五", 23), "深圳");
System.out.println(hm);
}
}
LinkedHashMap的概述和使用
package com.heima.map;
import java.util.LinkedHashMap;
public class Demo6_LinkedHashMap {
/**
* 底层是链表实现的可以保证怎么存就怎么取
*/
public static void main(String[] args) {
LinkedHashMap<String, Integer> lhm = new LinkedHashMap<>();
lhm.put("张三", 23);
lhm.put("李四", 24);
lhm.put("赵六", 25);
lhm.put("王五", 26);
System.out.println(lhm);
}
}
TreeMap集合键是Student值是String的案例
package com.heima.map;
import java.util.Comparator;
import java.util.TreeMap;
import com.heima.bean.Student;
public class Demo7_TreeMap {
/**
* @param args
*/
public static void main(String[] args) {
TreeMap<Student, String> tm = new TreeMap<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getName().compareTo(s2.getName()); //按照姓名比较
return num == 0 ? s1.getAge() - s2.getAge() : num;
}
});
tm.put(new Student("李四", 13), "上海");
tm.put(new Student("张三", 23), "北京"); //TreeMap需要对键有比较的方法
tm.put(new Student("王五", 33), "广州"); //或者传入比较器
tm.put(new Student("赵六", 43), "深圳");
System.out.println(tm);
}
public static void demo1() {
TreeMap<Student, String> tm = new TreeMap<>();
tm.put(new Student("张三", 23), "北京"); //TreeMap需要对键有比较的方法
tm.put(new Student("李四", 13), "上海"); //需要重写对象的compareTo方法
tm.put(new Student("王五", 33), "广州");
tm.put(new Student("赵六", 43), "深圳");
System.out.println(tm);
}
}
统计字符串中每个字符出现的次数
package com.heima.test;
import java.util.HashMap;
public class Test1 {
/**
* 需求:统计字符串中每个字符出现的次数
* 1,定义一个需要被统计字符的字符串
* 2,将字符串转换为字符数组
* 3,定义双列集合,存储字符串中字符以及字符出现的次数
* 4,遍历字符数组获取每一个字符,并将字符存储在双列集合中
* 5,存储过程中要做判断,如果集合中不包含这个键,就将该字符当作键,值为1存储,否则就将值加一
* 6,打印双列集合获取字符出现的次数
*/
public static void main(String[] args) {
//1,定义一个需要被统计字符的字符串
String s = "aaaabbbbbccccccccccccc";
//2,将字符串转换为字符数组
char[] arr = s.toCharArray();
//3,定义双列集合,存储字符串中字符以及字符出现的次数
HashMap<Character, Integer> hm = new HashMap<>();
//4,遍历字符数组获取每一个字符,并将字符存储在双列集合中
for(char c: arr) {
//5,存储过程中要做判断,如果集合中不包含这个键,就将该字符当作键,值为1存储,否则就将值加一
/*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);
}
//6,打印双列集合获取字符出现的次数
//System.out.println(hm);
for (Character key : hm.keySet()) { //hm.keySet()代表所有键的集合
System.out.println(key + "=" + hm.get(key)); //hm.get(key)根据键获取值
}
}
}
集合嵌套之HashMap嵌套HashMap
package com.heima.map;
import java.util.HashMap;
import com.heima.bean.Student;
public class Demo8_HashMapHashMap {
/**
* 需求:
* 双元课堂有很多基础班
* 第88期基础班定义成一个双列集合,键是学生对象。值是学生的归属地
* 第99期基础班定义成一个双列集合,键是学生对象。值是学生的归属地
* 无论88期还是99期都是班级对象,所以为了便于统一管理,把这些班级对象添加到双元课堂集合中
*/
public static void main(String[] args) {
//定义88期基础班
HashMap<Student, String> hm88 = new HashMap<>();
hm88.put(new Student("张三", 23), "北京");
hm88.put(new Student("李四", 24), "北京");
hm88.put(new Student("王五", 25), "上海");
hm88.put(new Student("赵六", 26), "广州");
//定义99期基础班
HashMap<Student, String> hm99 = new HashMap<>();
hm99.put(new Student("唐僧", 23), "北京");
hm99.put(new Student("孙悟空", 24), "北京");
hm99.put(new Student("猪八戒", 25), "上海");
hm99.put(new Student("沙和尚", 26), "广州");
//定义双元课堂
HashMap<HashMap<Student, String>, String> hm = new HashMap<>();
hm.put(hm88, "第88期基础班");
hm.put(hm99, "第99期基础班");
//遍历双列集合
for (HashMap<Student, String> h : hm.keySet()) { //hm.keySet()代表的是双列集合中键的集合
String value = hm.get(h); //get(h)根据键对象获取值对象
//遍历键的双列集合对象
for (Student student : h.keySet()) { //h.keySet()获取集合中所有的键(学生)对象
String value2 = h.get(student);
System.out.println(student + "=" + value2 + "=" + value);
}
}
}
}
HashMap和Hashtable的区别
- A:面试题
- HashMap和Hashtable的区别
- Hashtable是JDK1.0版本出现的,是线程安全的,效率低,HashMap是JDK1.2版本出现的,是线程不安全的,效率高
- Hashtable不可以存储null键和null值,HashMap可以存储null键和null值
- HashMap和Hashtable的区别
package com.heima.map;
import java.util.HashMap;
import java.util.Hashtable;
public class Demo9_Hashtable {
/**
* 面试题
* HashMap和Hashtable的区别
* 共同点:
* 底层都是哈希算法,都是双列集合
*/
public static void main(String[] args) {
/*HashMap<String, Integer> hm = new HashMap<>();
hm.put(null, null);
hm.put("张三", null);
hm.put(null,23);
System.out.println(hm);*/
Hashtable<String, Integer> ht = new Hashtable<>();
ht.put("张三", 23);
//ht.put(null, 24); //NullPointerException
ht.put("李四", null);//NullPointerException
System.out.println(ht);
}
}
Collections工具类的概述和常见方法讲解
package com.heima.collections;
import java.util.ArrayList;
import java.util.Collections;
public class Demo1_Collections {
/**
* public static <T> void sort(List<T> list)
public static <T> int binarySearch(List<?> list,T key)
public static <T> T max(Collection<?> coll)
public static void reverse(List<?> list)
public static void shuffle(List<?> list)
*/
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("c");
list.add("a");
list.add("d");
list.add("g");
list.add("f");
System.out.println(Collections.max(list)); //根据默认排序结果获取集合中的最大值
Collections.reverse(list); //反转集合
System.out.println(list);
Collections.shuffle(list); //随机置换,可以用来洗牌
System.out.println(list);
}
public static void demo2() {
ArrayList<String> list = new ArrayList<>();
list.add("a");
list.add("c");
list.add("d");
list.add("f");
list.add("g");
System.out.println(Collections.binarySearch(list,"c"));
System.out.println(Collections.binarySearch(list,"b")); //负的插入点减一
}
public static void demo1() {
ArrayList<String> list = new ArrayList<>();
list.add("c");
list.add("a");
list.add("a");
list.add("b");
list.add("d");
System.out.println(list); //[c, a, a, b, d]
Collections.sort(list); //将集合排序
System.out.println(list); //[a, a, b, c, d]
}
}
模拟斗地主洗牌和发牌
package com.heima.test;
import java.util.ArrayList;
import java.util.Collections;
public class Test2 {
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)); //concat连接两个字符串
}
}
poker.add("小王");
poker.add("大王");
//System.out.println(poker);
//2,洗牌
Collections.shuffle(poker);
//System.out.println(poker);
//3,发牌
ArrayList<String> gaojin = new ArrayList<>();
ArrayList<String> longwu = 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) {
gaojin.add(poker.get(i));
} else if(i % 3 == 2) {
longwu.add(poker.get(i));
} else {
me.add(poker.get(i));
}
}
//4,看牌
System.out.println(me);
System.out.println(gaojin);
System.out.println(longwu);
System.out.println(dipai);
}
}
模拟斗地主洗牌和发牌并对牌进行排序
package com.heima.test;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.TreeSet;
public class Test3 {
/**
* @param args
*/
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) {
hm.put(index, s2.concat(s1));
list.add(index);
index++;
}
}
//将大小王添加到双列集合中
hm.put(index, "小王");
list.add(index);
index++;
hm.put(index, "大王");
list.add(index);
//System.out.println(hm);
//System.out.println(list);
//2,洗牌
Collections.shuffle(list);
//3,发牌
TreeSet<Integer> gaojin = new TreeSet<>();
TreeSet<Integer> longwu = 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) {
gaojin.add(list.get(i));
}else if(i % 3 == 1) {
longwu.add(list.get(i));
}else {
me.add(list.get(i));
}
}
//看牌
lookPoker(hm,gaojin,"高进");
lookPoker(hm,gaojin,"龙五");
lookPoker(hm,me,"aaa");
lookPoker(hm,dipai,"底牌");
}
public static void lookPoker(HashMap<Integer, String> hm,TreeSet<Integer> ts
,String name) {
System.out.print(name + "的牌是");
for (Integer i : ts) { //i代表双列集合中的每一个键
System.out.print(hm.get(i) + " ");
}
System.out.println();
}
}
泛型固定下边界
package com.heima.collections;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.TreeSet;
import com.heima.bean.BaseStudent;
import com.heima.bean.Student;
public class Demo2_Genric {
/**
* 泛型固定下边界
* ? super E
* 泛型固定上边界
* ? extends E
* 都是父类引用指向子类对象
*/
public static void main(String[] args) {
TreeSet<Student> ts1 = new TreeSet<>(new CompareByAge());
ts1.add(new Student("张三",33));
ts1.add(new Student("李四",13));
ts1.add(new Student("王五",23));
ts1.add(new Student("赵六",43));
TreeSet<BaseStudent> ts2 = new TreeSet<>(new CompareByAge());
ts2.add(new BaseStudent("张三",33));
ts2.add(new BaseStudent("李四",13));
ts2.add(new BaseStudent("王五",23));
ts2.add(new BaseStudent("赵六",43));
System.out.println(ts2); //? super E 将子类对象放进比较器作比较
}
public static void demo1() {
ArrayList<Student> list1 = new ArrayList<>();
list1.add(new Student("张三", 23));
list1.add(new Student("李四", 24));
ArrayList<BaseStudent> list2 = new ArrayList<>();
list2.add(new BaseStudent("张三", 23));
list2.add(new BaseStudent("李四", 24));
list1.addAll(list2); //? extends E 将子类对象储存在父类数组中
}
}
class CompareByAge implements Comparator<Student> {
@Override
public int compare(Student s1, Student s2) {
int num = s1.getAge() - s2.getAge();
return num == 0 ? s1.getName().compareTo(s2.getName()) : num;
}
}
总结
package com.heima.collections;
public class Demo3_Collection {
/**
* Collection
* List(存取有序,有索引,可以重复)
* ArrayList
* 底层是数组实现的,线程不安全,查找和修改快,增和删比较慢
* LinkedList
* 底层是链表实现的,线程不安全,增和删比较快,查找和修改比较慢
* Vector
* 底层是数组实现的,线程安全的,无论增删改查都慢
* 如果查找和修改多,用ArrayList
* 如果增和删多,用LinkedList
* 如果都多,用ArrayList
* Set(存取无序,无索引,不可以重复)
* HashSet
* 底层是哈希算法实现
* LinkedHashSet
* 底层是链表实现,但是也是可以保证元素唯一,和HashSet原理一样
* TreeSet
* 底层是二叉树算法实现
* 一般在开发的时候不需要对存储的元素排序,所以在开发的时候大多用HashSet,HashSet的效率比较高
* TreeSet在面试的时候比较多,问你有几种排序方式,和几种排序方式的区别
* Map
* HashMap
* 底层是哈希算法,针对键
* LinkedHashMap
* 底层是链表,针对键
* TreeMap
* 底层是二叉树算法,针对键
* 开发中用HashMap比较多
*/
public static void main(String[] args) {
}
}
异常的概述和分类
- A:异常的概述
- 异常就是Java程序在运行过程中出现的错误。
- B:异常的分类
- 通过API查看Throwable
- Error
- 服务器宕机,数据库崩溃等
- Exception
- C:异常的继承体系
- Throwable
- Error
- Exception
- RuntimeException
- Throwable
JVM默认是如何处理异常的
- A:JVM默认是如何处理异常的
- main函数收到这个问题时,有两种处理方式:
- a:自己将该问题处理,然后继续运行
- b:自己没有针对的处理方式,只有交给调用main的jvm来处理
- jvm有一个默认的异常处理机制,就将该异常进行处理.
- 并将该异常的名称,异常的信息.异常出现的位置打印在了控制台上,同时将程序停止运行
package com.heima.exception;
public class Demo1_Exception {
/**
* @param args
*/
public static void main(String[] args) {
Demo d = new Demo();
int x = d.div(10, 0);
System.out.println(x);
}
}
class Demo {
public int div(int a, int b) { //10 / 0被除数是10,除数是0当除数是0的时候违背算术运算法则,抛出异常
return a / b; //new ArithmeticException("/ by zero");返回这样一个对象
}
}
try...catch的方式处理异常1
- A:异常处理的两种方式
- a:try…catch…finally
- try catch
- try catch finally
- try finally
- b:throws
- a:try…catch…finally
- B:try...catch处理异常的基本格式
- try…catch…finally
package com.heima.exception;
public class Demo2_Exception {
/**
* try:用来检测异常的
* catch:用来捕获异常
* finally:释放资源
* 当通过trycatch将问题处理了,程序会继续执行
*/
public static void main(String[] args) {
Demo2 d = new Demo2();
try {
int x = d.div(10, 0);
System.out.println(x);
}catch(ArithmeticException a) { //ArithmeticException a = new ArithmeticException();
System.out.println("出错了,除数为零了");
}
System.out.println("继续执行");
}
}
class Demo2 { //不能在同一个包下有两个相同名字的类
public int div(int a, int b) { //10 / 0被除数是10,除数是0当除数是0的时候违背算术运算法则,抛出异常
return a / b; //new ArithmeticException("/ by zero");返回这样一个对象
}
}
try...catch的方式处理异常2
- A:案例演示
- try...catch的方式处理多个异常
- JDK7以后处理多个异常的方式及注意事项
package com.heima.exception;
public class Demo3_Exception {
//安卓,服务端开发,如何处理异常?try{}catch(Exception e){}
//ee,服务端开发,一般都是底层开发,从底层向上抛
//try后面如果跟多个catch,那么小的异常放前面,大的异常放后面,根据多态的原理,如果大的放前面,
//就会将所有的子类对象接收,后面的catch就没有意义了
public static void main(String[] args) {
int a = 10;
int b = 0;
int[] arr = {11,22,33,44,55};
//JDK如何处理多个异常
try {
System.out.println(a / b);
System.out.println(arr[10]);
} catch (ArithmeticException | ArrayIndexOutOfBoundsException e) {
System.out.println("出错了");
}
}
public static void demo1() {
int a = 10;
int b = 0;
int[] arr = {11,22,33,44,55};
try {
//System.out.println(a / b);
//System.out.println(arr[10]);
arr = null;
System.out.println(arr[0]);
} catch (ArithmeticException e) {
System.out.println("除数不能为零");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("索引越界了");
} catch (Exception e) { //Exception e = new NullPointerExcption();
System.out.println("出错了"); //父类引用指向子类对象
}
System.out.println("over");
}
}
编译期异常和运行期异常的区别
- A:编译期异常和运行期异常的区别
Java中的异常被分为两大类:编译时异常和运行时异常。
所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常就是编译时异常
-
编译时异常
- Java程序必须显示处理,否则程序就会发生错误,无法通过编译
-
运行时异常
- 无需显示处理,也可以和编译时异常一样处理
package com.heima.exception;
import java.io.FileInputStream;
public class Demo4_Exception {
/**
* 编译时异常有点未雨绸缪的味道(不规范的说法)
* 编译时异常:在编译某个程序的时候,有可能会有一些事情发生,比如文件找不到,这样的异常就必须在编译的时候
* 处理,如果不处理编译通不过 //自己的理解:就是语法不合符规范
* 运行时异常:就是程序员所犯得错误,需要回来修改代码 //自己的理解:就是语法符合规范,但是程序逻辑错误
* 这里的逻辑指的是空指针、除以0等
*/
public static void main(String[] args) {
try {
FileInputStream fis = new FileInputStream("xxx.txt");
} catch(Exception e) {
System.out.println(1);
}
}
}
Throwable的几个常见方法
- A:Throwable的几个常见方法
- a:getMessage()
- 获取异常信息,返回字符串。
- b:toString()
- 获取异常类名和异常信息,返回字符串。
- c:printStackTrace()
- 获取异常类名和异常信息,以及异常出现在程序中的位置。返回值void。
- a:getMessage()
package com.heima.exception;
public class Demo5_Throwable {
/**
* @param args
*/
public static void main(String[] args) {
try {
System.out.println(1/0);
} catch (Exception e) { //Exception e = new ArithmeticException("/by zero")
System.out.println(e.getMessage()); //获取异常信息
System.out.println(e); //调用toString方法,打印异常类名和异常信息
e.printStackTrace(); //JVM默认用这种方式处理异常
}
}
}
throws的方式处理异常
- A:throws的方式处理异常
- 定义功能方法时,需要把出现的问题暴露出来让调用者去处理。
- 那么就通过throws在方法上标识。
package com.heima.exception;
public class Demo6_Exception {
/**
* 编译时异常的抛出必须对其进行处理
* 运行时异常的抛出可以处理也可以不处理
*/
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setAge(-17);
System.out.println(p.getAge());
}
}
class 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) throws Exception {
if(age > 0 && age <= 150) {
this.age = age;
}else {
throw new Exception("年龄非法");//这里是匿名对象,也可以抛出有名字的对象。
}
}
}
throw的概述以及和throws的区别
- A:throw的概述
- 在功能方法内部出现某种情况,程序不能继续运行,需要进行跳转时,就用throw把异常对象抛出。
- C:throws和throw的区别
- a:throws
- 用在方法声明后面,跟的是异常类名
- 可以跟多个异常类名,用逗号隔开
- 表示抛出异常,由该方法的调用者来处理
- b:throw
- 用在方法体内,跟的是异常对象名
- 只能抛出一个异常对象名
- 表示抛出异常,由方法体内的语句处理
- a:throws
finally关键字的特点及作用
A:finally的特点
* 被finally控制的语句体一定会执行
* 特殊情况:在执行到finally之前jvm退出了(比如System.exit(0))
- B:finally的作用
- 用于释放资源,在IO流操作和数据库操作中会见到
package com.heima.exception;
public class Demo7_Finally {
/**
* @param args
*/
public static void main(String[] args) {
try {
System.out.println(10/0);
} catch (Exception e){
System.out.println("除数为零了");
System.exit(0); //退出java虚拟机
return; //会先执行finally
} finally {
System.out.println("看看我执行了吗"); //即使有return语句也会先执行finally
}
}
}
finally关键字的面试题
package com.heima.test;
public class Test1 {
/**
* * A:面试题1
* final,finally和finalize的区别
* final可以修饰类,不能被继承
* 修饰方法,不能被重写
* 修饰变量,只能赋值一次
*
* finally是try语句中的一个语句体,不能单独使用,用来释放资源
*
* finalize是一个方法,当垃圾回收器确定不存在对该对象的更多引用时,由对象的垃圾回收器调用此方法。
* * B:面试题2
* 如果catch里面有return语句,请问finally的代码还会执行吗?如果会,请问是在return前还是return后。
* 无论try里执行了return语句、break语句、还是continue语句,finally语句块还会继续执行
* 如果try语句里有return,那么代码的行为如下:
1.如果有返回值,就把返回值保存到局部变量中
2.执行jsr指令跳到finally语句里执行
3.执行完finally语句后,返回之前保存在局部变量表里的值
*/
public static void main(String[] args) {
Demo d = new Demo();
System.out.println(d.method());
}
}
class Demo {
public int method() {
int x = 10;
try {
x = 20;
System.out.println(1/0);
return x;
} catch (Exception e) {
x =30;
return x;
} finally {
x = 40; //如果finally有return,会覆盖之前的return方法,不要在里面写return语句
}
}
}
自定义异常概述和基本使用
B:自定义异常概述
* 继承自Exception
* 继承自RuntimeException
package com.heima.exception;
public class Demo8_Exception {
/**
* 自定义异常原因:通过名字区分到底是什么异常,有针对的解决办法
*/
public static void main(String[] args) {
}
}
class AgeOutOfBoundsException extends Exception {
public AgeOutOfBoundsException() {
super();
}
public AgeOutOfBoundsException(String message) {
super(message);
}
}
异常的注意事项及如何使用异常处理
- A:异常注意事项
- a:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
- b:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
- c:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
- B:如何使用异常处理
原则:如果该功能内部可以将问题处理,用try,如果处理不了,交由调用者处理,这是用throws
-
区别:
- 后续程序需要继续运行就try
- 后续程序不需要继续运行就throws
如果JDK没有提供对应的异常,需要自定义异常。
练习
package com.heima.test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
public class Test2 {
/**
* 键盘录入一个int类型的整数,对其求二进制表现形式
* 如果录入的整数过大,给予提示,录入的整数过大请重新录入一个整数BigInteger
* 如果录入的是小数,给予提示,录入的是小数,请重新录入一个整数
* 如果录入的是其他字符,给予提示,录入的是非法字符,请重新录入一个整数
*
* 分析:
* 1,创建键盘录入对象
* 2,将键盘录入的结果存储在String类型的字符串中,存储int类型中如果有不符合条件的直接报错,无法进行后续判断
* 3,键盘录入的结果转换成int类型的数据,是正确的还是错误的
* 4,正确的直接转换
* 5,错误的要进行对应判断
* Alt+shitf+z (try catch代码块快捷键)
*/
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("请输入一个整数:");
while(true) {
String line = sc.nextLine(); //将键盘录入的结果存储在line中
try {
int num = Integer.parseInt(line); //将字符串转换为整数
System.out.println(Integer.toBinaryString(num));//将整数转换为二进制
break; //跳出循环
}catch(Exception e) {
try {
new BigInteger(line);
System.out.println("录入错误,您录入的是一个过大整数,请重新输入一个整数");
} catch (Exception e1) {
try {
new BigDecimal(line);
System.out.println("录入错误,您录入的是一个小数,请重新输入一个整数");
} catch (Exception e2) {
System.out.println("录入错误,您录入的是非法字符,请重新输入一个整数");
}
}
}
}
}
}
File类的概述和构造方法
- A:File类的概述
- File更应该叫做一个路径
- 文件路径或者文件夹路径
- 路径分为绝对路径和相对路径
- 绝对路径是一个固定的路径,从盘符开始
- 相对路径相对于某个位置,在eclipse下是指当前项目下,在dos下
- 查看API指的是当前路径
- 文件和目录路径名的抽象表示形式
- File更应该叫做一个路径
- B:构造方法
- File(String pathname):根据一个路径得到File对象
- File(String parent, String child):根据一个目录和一个子文件/目录得到File对象
- File(File parent, String child):根据一个父File对象和一个子文件/目录得到File对象
package com.heima.file;
import java.io.File;
public class Demo1_File {
public static void main(String[] args) {
File parent = new File("D:\\BaiduNetdiskDownload\\01-JavaSE知识(学习27天)\\day01(计算机基础知识&jdk安装&标识符)");
String child = "01.01_计算机基础知识(计算机概述)_rec.avi";
File file = new File(parent, child);
System.out.println(file.exists());
System.out.println(parent.exists());
}
public static void demo2() {
String parent = "D:\\BaiduNetdiskDownload\\01-JavaSE知识(学习27天)\\day01(计算机基础知识&jdk安装&标识符)";
String child = "01.01_计算机基础知识(计算机概述)_rec.avi";
File file = new File(parent, child);
System.out.println(file.exists());
}
public static void demo1() {
File file = new File("D:\\BaiduNetdiskDownload\\01-JavaSE知识(学习27天)" +
"\\day01(计算机基础知识&jdk安装&标识符)\\01.01_计算机基础知识(计算机概述)_rec.avi");
System.out.println(file.exists());
File file2 = new File("xxx.txt");
System.out.println(file2.exists());
File file3 = new File("yyy.txt");
System.out.println(file3.exists());
}
}
File类的创建功能
- A:创建功能
- public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
- public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
- public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
- 注意事项:
- 如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下
package com.heima.file;
import java.io.File;
import java.io.IOException;
public class Demo2_FileMethod {
/**
* @param args
*
*/
public static void main(String[] args) throws IOException {
File dir1 = new File("aaa");
System.out.println(dir1.mkdir());
File dir2 = new File("bbb.txt"); //这样写是可以的,文件夹可以有后缀名
System.out.println(dir2.mkdir());
File dir3 = new File("ccc\\ddd");
System.out.println(dir3.mkdirs()); //创建多级目录
}
public static void demo1() throws IOException {
File file = new File("yyy.txt");
System.out.println(file.createNewFile()); //如果没有就创建,返回true,否则就不创建,返回false
File file2 = new File("zzz"); //没有格式的也可以创建
System.out.println(file2.createNewFile());
}
}
File类的重命名和删除功能
- A:重命名和删除功能
- public boolean renameTo(File dest):把文件重命名为指定的文件路径
- public boolean delete():删除文件或者文件夹
- B:重命名注意事项
- 如果路径名相同,就是改名。
- 如果路径名不同,就是改名并剪切。
- C:删除注意事项:
- Java中的删除不走回收站。
- 要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
package com.heima.file;
import java.io.File;
public class Demo3_FileMethod {
/**
* @param args
*/
public static void main(String[] args) {
File file1 = new File("yyy.txt");
System.out.println(file1.delete());
File file2 = new File("aaa");
System.out.println(file2.delete());
File file3 = new File("ccc"); //如果删除一个文件夹,那么这个文件夹必须是空的
System.out.println(file3.delete());
}
public static void demo1() {
File file1 = new File("ooo.txt");
File file2 = new File("D:\\xxx.txt");
System.out.println(file1.renameTo(file2));
}
}
File类的判断功能
- A:判断功能
- public boolean isDirectory():判断是否是目录
- public boolean isFile():判断是否是文件
- public boolean exists():判断是否存在
- public boolean canRead():判断是否可读
- public boolean canWrite():判断是否可写
- public boolean isHidden():判断是否隐藏
package com.heima.file;
import java.io.File;
public class Demo4_FileMethod {
public static void main(String[] args) {
File file = new File("zzz");
file.setReadable(false);
System.out.println(file.canRead()); //windows系统认为所有的文件都是可读的,一定会返回true
file.setWritable(false);
System.out.println(file.canWrite()); //windows系统可以设置为不可写
}
public static void demo1() {
File dir1 = new File("ccc");
System.out.println(dir1.isDirectory()); //判断是否是文件夹
File dir2 = new File("zzz");
System.out.println(dir2.isDirectory());
System.out.println(dir1.isFile()); //判断是否是文件
System.out.println(dir2.isFile());
}
}
File类的获取功能
- A:获取功能
- public String getAbsolutePath():获取绝对路径
- public String getPath():获取路径
- public String getName():获取名称
- public long length():获取长度。字节数
- public long lastModified():获取最后一次的修改时间,毫秒值
- public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
- public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
package com.heima.file;
import java.io.File;
import java.util.Date;
public class Demo5_FileMethod {
public static void main(String[] args) {
File dir = new File("D:/BaiduNetdiskDownload/01-JavaSE知识(学习27天)");
String[] arr = dir.list(); //仅为了获取文件名
for (String string : arr) {
System.out.println(string);
}
File[] subFiles = dir.listFiles(); //获取文件对象
for (File file : subFiles) {
System.out.println(file);
}
}
public static void demo1() {
File file1 = new File("xxx.txt");
File file2 = new File("D:\\双元课堂\\day19\\xxx.txt");
System.out.println(file1.getAbsolutePath()); //获取绝对路径
System.out.println(file2.getAbsolutePath());
System.out.println(file1.getPath()); //获取构造方法中传入的路径
System.out.println(file2.getPath());
System.out.println(file1.getName()); //获取文件或文件夹的名字
System.out.println(file2.getName());
System.out.println(file1.length());
System.out.println(file1.lastModified()); //文件的最后修改时间
Date d = new Date(file1.lastModified());
System.out.println(d);
}
}
输出指定目录下指定后缀的文件名
package com.heima.test;
import java.io.File;
public class Test3 {
/**
** 需求:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称
*/
public static void main(String[] args) {
File dir = new File("C:/Users/yang/Desktop");
String[] arr = dir.list(); //获取e盘下所有的文件或文件夹
for (String string : arr) {
if(string.endsWith(".jpg")) {
System.out.println(string);
}
}
File[] subFiles = dir.listFiles(); //获取e盘下所有的文件或文件夹对象
for (File file : subFiles) {
if(file.isFile() && file.getName().endsWith(".jpg")) {
System.out.println(file);
}
}
}
}
文件名称过滤器的概述及使用
- A:文件名称过滤器的概述
- public String[] list(FilenameFilter filter)
- public File[] listFiles(FileFilter filter)
- B:文件名称过滤器的使用
- 需求:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称
- C:源码分析
- 带文件名称过滤器的list()方法的源码
package com.heima.test;
import java.io.File;
import java.io.FilenameFilter;
public class Test3 {
/**
** 需求:判断E盘目录下是否有后缀名为.jpg的文件,如果有,就输出该文件名称
*/
public static void main(String[] args) {
File dir = new File("C:/Users/yang/Desktop");
String[] arr1 = dir.list(new FilenameFilter(){
@Override
public boolean accept(File dir, String name) {
//System.out.println(dir);
//System.out.println(name);
File file = new File(dir, name);
return file.isFile() && file.getName().endsWith(".jpg");
}
});
for (String string : arr1) {
System.out.println(string);
}
}
}
IO流概述及其分类
- 1.概念
- IO流用来处理设备之间的数据传输
- Java对数据的操作是通过流的方式
- Java用于操作流的类都在IO包中
- 流按流向分为两种:输入流,输出流。
- 流按操作类型分为两种:
- 字节流 : 字节流可以操作任何数据,因为在计算机中任何数据都是以字节的形式存储的
- 字符流 : 字符流只能操作纯字符数据,比较方便。
- 2.IO流常用父类
- 字节流的抽象父类:
- InputStream
- OutputStream
- 字符流的抽象父类:
- Reader
- Writer
- 字节流的抽象父类:
- 3.IO程序书写
- 使用前,导入IO包中的类
- 使用时,进行IO异常处理
- 使用后,释放资源
FileInputStream
- read()一次读取一个字节
package com.heima.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
public class Demo1_FileInputStream {
/*
*/
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("xxx.txt");//创建一个文件输入流对象,并关联aaa.txt
int b;
while((b = fis.read()) != -1) { //当文件读完输出为-1,所以设置-1为结束标志
System.out.println(b);
}
fis.close();
}
public static void demo1() throws FileNotFoundException, IOException {
FileInputStream fis = new FileInputStream("xxx.txt"); //创建流对象
int x = fis.read(); //从硬盘上读取一个字节
System.out.println(x);
int y = fis.read(); //从硬盘上读取一个字节
System.out.println(y);
int z = fis.read(); //从硬盘上读取一个字节
System.out.println(z);
int a = fis.read(); //从硬盘上读取一个字节
System.out.println(a);
int b = fis.read(); //从硬盘上读取一个字节
System.out.println(b);
fis.close(); //关流释放资源
}
}
read()方法返回值为什么是int
- read()方法读取的是一个字节,为什么返回是int,而不是byte
因为字节输入流可以操作任意类型的文件,比如图片音频等,这些文件底层都是以二进制形式的存储的,如果每次读取都返回byte,有可能在读到中间的时候遇到111111111
那么这11111111是byte类型的-1,我们的程序是遇到-1就会停止不读了,后面的数据就读不到了,所以在读取的时候用int类型接收,如果11111111会在其前面补上24个0凑足4个字节,那么byte类型的-1就变成int类型的255了这样可以保证整个数据读完,而结束标记的-1就是int类型
FileOutputStream以及FileOutputStream的追加
- write()一次写出一个字节
package com.heima.stream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo2_FileOutputStream {
/**
* FileOutputStream在创建对象的时候是如果没有这个文件会帮我创建出来
* 如果有这个文件就会先将文件清空
*/
public static void main(String[] args) throws IOException {
//FileOutputStream fos = new FileOutputStream("yyy.txt"); //创建IO字节输出流对象,如果没有就自动创建一个
FileOutputStream fos = new FileOutputStream("yyy.txt",true); //如果想续写,就在第二个参数传true
fos.write(97); //虽然写出的是一个int数,但是到文件上的是一个字节,会自动去除前3个8位
fos.write(98);
fos.write(99);
fos.close();
}
}
拷贝图片
由于是一个字节一个字节的读,所以效率很低。
package com.heima.stream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo3_Copy {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("Math.jpg"); //创建输入流对象,关联Math.jpg
FileOutputStream fos = new FileOutputStream("copy.jpg"); //创建输出流对象,关联copy.jpg
int b;
while((b = fis.read()) != -1) { //在不断的读取每一个字节
fos.write(b); //将每一个字节写出
}
fis.close(); //关流释放资源
fos.close();
}
}