Day16
List 的子類ArrayList,Vector澄耍,LinkedLis
ArrayList
用法跟List相同
Vector
Vector的特有功能:
添加功能
public void addElement(Object obj)---------被add()替代
獲取功能
public Object elementAt(int index)-----------被get()替代
public Enumeration elements()---------------被Iterator iterator()迭代器替代
boolean hasMoreElements()------------------被hasNext()替代
Object nextElement()----------------------------被next()替代
LinkedList
添加功能
public void addFirst(Object e) 在第一個(gè)位置添加元素
public void addLast(Object e) 在最后一個(gè)位置添加元素
獲取功能
public Object getFirst() 獲取第一個(gè)元素
public Obejct getLast()獲取最后一個(gè)元素
刪除功能
public Object removeFirst()刪除第一個(gè)元素并返回第一個(gè)元素
public Object removeLast()刪除最后一個(gè)元素并返回最后一個(gè)元素
注意:contains()方法的底層依賴的是equals()方法
/*ArrayList去除集合中字符串的重復(fù)值(字符串的內(nèi)容相同)
* 分析:
* 創(chuàng)建集合對象
* 添加多個(gè)字符串元素(包含內(nèi)容相同的)
* 創(chuàng)建新集合
* 遍歷舊集合,獲取得到每一個(gè)元素
* 拿這個(gè)元素到新集合去找淹真,看有沒有
* 有:不搭理它
* 沒有:就添加到新集合
* 遍歷新集合
*/
import java.util.ArrayList;
public class SanGe {
public static void main(String[] args) {
//創(chuàng)建集合對象
ArrayList al = new ArrayList();
//添加多個(gè)字符串元素(包含內(nèi)容相同的)
al.add("he");
al.add("nihao");
al.add("nihao");
al.add("he");
al.add("nihao");
al.add("world");
al.add("world");
//創(chuàng)建新集合
ArrayList newAl = new ArrayList();
//遍歷舊集合,獲取得到每一個(gè)元素
for (int i = 0; i < al.size(); i++) {
//拿這個(gè)元素到新集合去找检激,看有沒有
if (!newAl.contains(al.get(i))){
//沒有:就添加到新集合
newAl.add(al.get(i));
}
}
//遍歷新集合
for (int i = 0; i < newAl.size(); i++) {
System.out.println(newAl.get(i)+" ");
}
}
}
ArrarList去重升級(jí)版
/*
* 需求:ArrayList去除集合中字符串的重復(fù)值(字符串的內(nèi)容相同)
* 要求:不能創(chuàng)建新的集合,就在以前的集合上做
*/
public class ArrayListDemo2 {
public static void main(String[] args) {
// 創(chuàng)建集合對象
ArrayList array = new ArrayList();
// 添加多個(gè)字符串元素(包含內(nèi)容相同的)
al.add("he");
al.add("nihao");
al.add("nihao");
al.add("he");
al.add("nihao");
al.add("world");
al.add("world");
// 由選擇排序思想引入领跛,我們就可以通過這種思想做這個(gè)題目
// 拿0索引的依次和后面的比較乏德,有就把后的干掉
// 同理,拿1索引...
for (int i = 0; i < array.size() - 1; i++) {
for (int j = i + 1; j < array.size(); j++) {
if (array.get(i).equals(array.get(j))) {
array.remove(j);
j--;
}
}
}
// 遍歷集合
Iterator it = array.iterator();
while (it.hasNext()) {
String s = (String) it.next();
System.out.println(s);
}
}
}
泛型
是一種把類型明確的工作推遲到創(chuàng)建對象或者調(diào)用方法的時(shí)候才去明確的特殊的類型吠昭,參數(shù)化類型喊括,把類型當(dāng)作參數(shù)一樣的傳遞
格式:
<數(shù)據(jù)類型>
此處的數(shù)據(jù)類型只能是引用類型
好處:
把運(yùn)行時(shí)期的問題提前到了編譯期間
避免了強(qiáng)制類型轉(zhuǎn)換
優(yōu)化了程序設(shè)計(jì),解決了黃色警告線
泛型在哪些地方使用矢棚,看API郑什,如果類,接口蒲肋,抽象類后面跟的有<E>就說要使用泛型蘑拯,一般來說就是在集合中使用
public class GenericDemo {
public static void main(String[] args) {
// 創(chuàng)建
ArrayList<String> array = new ArrayList<String>();
// 添加元素
array.add("hello");
array.add("world");
array.add("java");
// 遍歷
Iterator<String> it = array.iterator();
while (it.hasNext()) {
// String s = (String) it.next();
//因?yàn)镮terator后邊跟了String,默認(rèn)就是String類型兜粘,不需要強(qiáng)轉(zhuǎn)
String s = it.next();
System.out.println(s);
}
}
}
泛型應(yīng)用
泛型類
把泛型定義在類上
格式:public class 類名<泛型類型1,…>
注意:泛型類型必須是引用類型
泛型方法
把泛型定義在方法上
格式:public <泛型類型> 返回類型 方法名(泛型類型 .)
泛型接口
把泛型定義在接口上
格式:public interface 接口名<泛型類型1…>
泛型類
/*
* 泛型類:把泛型定義在類上
*/
public class ObjectTool<T> {
private T obj;
public T getObj() {
return obj;
}
public void setObj(T obj) {
this.obj = obj;
}
}
/*
* 泛型類的測試
*/
public class ObjectToolDemo {
public static void main(String[] args) {
// ObjectTool ot = new ObjectTool();
//
// ot.setObj(new String("張三"));
// String s = (String) ot.getObj();
// System.out.println("姓名是:" + s);
//
// ot.setObj(new Integer(30));
// Integer i = (Integer) ot.getObj();
// System.out.println("年齡是:" + i);
// ot.setObj(new String("李四"));
// // ClassCastException
// Integer ii = (Integer) ot.getObj();
// System.out.println("姓名是:" + ii);
System.out.println("-------------");
ObjectTool<String> ot = new ObjectTool<String>();
// ot.setObj(new Integer(27)); //這個(gè)時(shí)候編譯期間就過不去
ot.setObj(new String("張三"));
String s = ot.getObj();
System.out.println("姓名是:" + s);
ObjectTool<Integer> ot2 = new ObjectTool<Integer>();
// ot2.setObj(new String("李四"));//這個(gè)時(shí)候編譯期間就過不去
ot2.setObj(new Integer(27));
Integer i = ot2.getObj();
System.out.println("年齡是:" + i);
}
}
泛型方法
/*
* 泛型方法:把泛型定義在方法上
*/
public class ObjectTool {
//誰調(diào)用就傳誰的類型給show方法
public <T> void show(T t) {
System.out.println(t);
}
}
public class ObjectToolDemo {
public static void main(String[] args) {
// 定義泛型方法后
ObjectTool ot = new ObjectTool();
ot.show("hello");//String調(diào)用,show就接受String類型
ot.show(100);
ot.show(true);
}
}
泛型接口
/*
* 泛型接口:把泛型定義在接口上
*/
public interface Inter<T> {
public abstract void show(T t);
}
//實(shí)現(xiàn)類在實(shí)現(xiàn)接口的時(shí)候
//第一種情況:已經(jīng)知道該是什么類型的了
//public class InterImpl implements Inter<String> {
//
// @Override
// public void show(String t) {
// System.out.println(t);
// }
// }
//第二種情況:還不知道是什么類型的
public class InterImpl<T> implements Inter<T> {
@Override
public void show(T t) {
System.out.println(t);
}
}
//測試類
public class InterDemo {
public static void main(String[] args) {
// 第一種情況的測試
// Inter<String> i = new InterImpl();
// i.show("hello");
// 第二種情況的測試
Inter<String> i = new InterImpl<String>();
i.show("hello");
Inter<Integer> ii = new InterImpl<Integer>();
ii.show(100);
}
}
泛型高級(jí)(通配符)
?:任意類型申窘,如果沒有明確,那么就是Object以及任意的Java類了
? extends E:向下限定孔轴,E及其子類
? super E:向上限定剃法,E極其父類
public class GenericDemo {
public static void main(String[] args) {
// 泛型如果明確的寫的時(shí)候,前后必須一致
Collection<Object> c1 = new ArrayList<Object>();
// Collection<Object> c2 = new ArrayList<Animal>();
// Collection<Object> c3 = new ArrayList<Dog>();
// Collection<Object> c4 = new ArrayList<Cat>();
// ?表示任意的類型都是可以的
Collection<?> c5 = new ArrayList<Object>();
Collection<?> c6 = new ArrayList<Animal>();
Collection<?> c7 = new ArrayList<Dog>();
Collection<?> c8 = new ArrayList<Cat>();
// ? extends E:向下限定距糖,E及其子類
// Collection<? extends Animal> c9 = new ArrayList<Object>();
Collection<? extends Animal> c10 = new ArrayList<Animal>();
Collection<? extends Animal> c11 = new ArrayList<Dog>();
Collection<? extends Animal> c12 = new ArrayList<Cat>();
// ? super E:向上限定玄窝,E極其父類
Collection<? super Animal> c13 = new ArrayList<Object>();
Collection<? super Animal> c14 = new ArrayList<Animal>();
// Collection<? super Animal> c15 = new ArrayList<Dog>();
// Collection<? super Animal> c16 = new ArrayList<Cat>();
}
}
class Animal {
}
class Dog extends Animal {
}
class Cat extends Animal {
}
增強(qiáng)for
是for循環(huán)的一種
格式:
for(元素?cái)?shù)據(jù)類型 變量 : 數(shù)組或者Collection集合) {
使用變量即可,該變量就是元素
}
好處:簡化了數(shù)組和集合的遍歷,在集合方面就是替代了迭代器
弊端: 增強(qiáng)for的目標(biāo)不能為null,可以先對增強(qiáng)for的目標(biāo)先進(jìn)行不為null的判斷悍引,然后在使用
public class ForDemo {
public static void main(String[] args) {
// 定義一個(gè)int數(shù)組
int[] arr = { 1, 2, 3, 4, 5 };
for (int x = 0; x < arr.length; x++) {
System.out.println(arr[x]);
}
System.out.println("---------------");
// 增強(qiáng)for
for (int x : arr) {
System.out.println(x);
}
System.out.println("---------------");
// 定義一個(gè)字符串?dāng)?shù)組
String[] strArray = { "張三", "李四", "王五", "劉六" };
// 增強(qiáng)for
for (String s : strArray) {
System.out.println(s);
}
System.out.println("---------------");
// 定義一個(gè)集合
ArrayList<String> array = new ArrayList<String>();
array.add("hello");
array.add("world");
array.add("java");
// 增強(qiáng)for
for (String s : array) {
System.out.println(s);
}
System.out.println("---------------");
List<String> list = null;
// NullPointerException
// 這個(gè)s是我們從list里面獲取出來的恩脂,在獲取前,它肯定還好做一個(gè)判斷
// 說白了趣斤,這就是迭代器的功能
if (list != null) {
for (String s : list) {
System.out.println(s);
}
}
}
}
靜態(tài)導(dǎo)入
格式:import static 包名….類名.方法名; 可以直接導(dǎo)入到方法的級(jí)別
靜態(tài)導(dǎo)入的注意事項(xiàng):
方法必須是靜態(tài)的
如果有多個(gè)同名的靜態(tài)方法俩块,容易不知道使用誰?這個(gè)時(shí)候要使用,必須加前綴
可變參數(shù)
定義方法的時(shí)候不知道該定義多少個(gè)參數(shù)
格式:
修飾符 返回值類型 方法名(數(shù)據(jù)類型… 變量名){
方法體語句;
}
注意:
這里的變量其實(shí)是一個(gè)數(shù)組
如果一個(gè)方法有可變參數(shù),并且有多個(gè)參數(shù)玉凯,那么势腮,可變參數(shù)肯定是最后一個(gè)
public class ArgsDemo {
public static void main(String[] args) {
// 2個(gè)數(shù)據(jù)求和
int a = 10;
int b = 20;
int result = sum(a, b);
System.out.println("result:" + result);
// 3個(gè)數(shù)據(jù)的求和
int c = 30;
result = sum(a, b, c);
System.out.println("result:" + result);
// 4個(gè)數(shù)據(jù)的求和
int d = 30;
result = sum(a, b, c, d);
System.out.println("result:" + result);
// 需求:我要寫一個(gè)求和的功能,到底是幾個(gè)數(shù)據(jù)求和呢漫仆,我不太清楚捎拯,但是我知道在調(diào)用的時(shí)候我肯定就知道了
// 為了解決這個(gè)問題,Java就提供了一個(gè)東西:可變參數(shù)
result = sum(a, b, c, d, 40);
System.out.println("result:" + result);
result = sum(a, b, c, d, 40, 50);
System.out.println("result:" + result);
}
public static int sum(int... a) {
int sum1 = 0;
for(int x : a){
sum1 +=x;
}
return sum1;
}
// public static int sum(int a, int b, int c, int d) {
// return a + b + c + d;
// }
//
// public static int sum(int a, int b, int c) {
// return a + b + c;
// }
//
// public static int sum(int a, int b) {
// return a + b;
// }
}
asLis
public static <T> List<T> asList(T... a):把數(shù)組轉(zhuǎn)成集合
注意事項(xiàng):
雖然可以把數(shù)組轉(zhuǎn)成集合盲厌,但是集合的長度不能改變
public class ArraysDemo {
public static void main(String[] args) {
// 定義一個(gè)數(shù)組
// String[] strArray = { "hello", "world", "java" };
// List<String> list = Arrays.asList(strArray);
List<String> list = Arrays.asList("hello", "world", "java");
// UnsupportedOperationException
// list.add("javaee");
// UnsupportedOperationException
// list.remove(1);
list.set(1, "javaee");
for (String s : list) {
System.out.println(s);
}
}
}
集合嵌套的存儲(chǔ)和遍歷元素
需求:
我們班有學(xué)生署照,每一個(gè)學(xué)生是不是一個(gè)對象,所以我們可以使用一個(gè)集合表示我們班級(jí)的學(xué)生,ArrayList<Student>
但是呢周蹭,我們旁邊是不是還有班級(jí)溉瓶,每個(gè)班級(jí)是不是也是一個(gè)ArrayList<Student>
而我現(xiàn)在有多個(gè)ArrayList<Student>,也要用集合存儲(chǔ)或渤,ArrayList<ArrayList<Student>>
public class ArrayListDemo {
public static void main(String[] args) {
// 創(chuàng)建大集合
ArrayList<ArrayList<Student>> bigArrayList = new ArrayList<ArrayList<Student>>();
// 創(chuàng)建第一個(gè)班級(jí)的學(xué)生集合
ArrayList<Student> firstArrayList = new ArrayList<Student>();
// 創(chuàng)建學(xué)生
Student s1 = new Student("唐僧", 30);
Student s2 = new Student("孫悟空", 29);
Student s3 = new Student("豬八戒", 28);
Student s4 = new Student("沙僧", 27);
Student s5 = new Student("白龍馬", 26);
// 學(xué)生進(jìn)班
firstArrayList.add(s1);
firstArrayList.add(s2);
firstArrayList.add(s3);
firstArrayList.add(s4);
firstArrayList.add(s5);
// 把第一個(gè)班級(jí)存儲(chǔ)到學(xué)生系統(tǒng)中
bigArrayList.add(firstArrayList);
// 創(chuàng)建第二個(gè)班級(jí)的學(xué)生集合
ArrayList<Student> secondArrayList = new ArrayList<Student>();
// 創(chuàng)建學(xué)生
Student s11 = new Student("諸葛亮", 30);
Student s22 = new Student("司馬懿", 28);
Student s33 = new Student("周瑜", 26);
// 學(xué)生進(jìn)班
secondArrayList.add(s11);
secondArrayList.add(s22);
secondArrayList.add(s33);
// 把第二個(gè)班級(jí)存儲(chǔ)到學(xué)生系統(tǒng)中
bigArrayList.add(secondArrayList);
// 創(chuàng)建第三個(gè)班級(jí)的學(xué)生集合
ArrayList<Student> thirdArrayList = new ArrayList<Student>();
// 創(chuàng)建學(xué)生
Student s111 = new Student("宋江", 40);
Student s222 = new Student("吳用", 35);
Student s333 = new Student("高俅", 30);
Student s444 = new Student("李師師", 22);
// 學(xué)生進(jìn)班
thirdArrayList.add(s111);
thirdArrayList.add(s222);
thirdArrayList.add(s333);
thirdArrayList.add(s444);
// 把第三個(gè)班級(jí)存儲(chǔ)到學(xué)生系統(tǒng)中
bigArrayList.add(thirdArrayList);
// 遍歷集合
for (ArrayList<Student> array : bigArrayList) {
for (Student s : array) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
}
獲取不重復(fù)的隨機(jī)數(shù)
/*
* 獲取10個(gè)1-20之間的隨機(jī)數(shù)扬卷,要求不能重復(fù)
*
* 用數(shù)組實(shí)現(xiàn)瘸洛,但是數(shù)組的長度是固定的烁落,長度不好確定萍程。
* 所以我們使用集合實(shí)現(xiàn)葫录。
*
* 分析:
* 創(chuàng)建產(chǎn)生隨機(jī)數(shù)的對象
* 創(chuàng)建一個(gè)存儲(chǔ)隨機(jī)數(shù)的集合阀湿。
* 定義一個(gè)統(tǒng)計(jì)變量赶熟。從0開始。
* 判斷統(tǒng)計(jì)遍歷是否小于10
* 是:先產(chǎn)生一個(gè)隨機(jī)數(shù)炕倘,判斷該隨機(jī)數(shù)在集合中是否存在钧大。
* 如果不存在:就添加,統(tǒng)計(jì)變量++罩旋。
* 如果存在:就不搭理它啊央。
* 否:不搭理它
* 遍歷集合
*/
public class RandomDemo {
public static void main(String[] args) {
// 創(chuàng)建產(chǎn)生隨機(jī)數(shù)的對象
Random r = new Random();
// 創(chuàng)建一個(gè)存儲(chǔ)隨機(jī)數(shù)的集合。
ArrayList<Integer> array = new ArrayList<Integer>();
// 定義一個(gè)統(tǒng)計(jì)變量涨醋。從0開始瓜饥。
int count = 0;
// 判斷統(tǒng)計(jì)遍歷是否小于10
while (count < 10) {
//先產(chǎn)生一個(gè)隨機(jī)數(shù)
int number = r.nextInt(20) + 1;
//判斷該隨機(jī)數(shù)在集合中是否存在。
if(!array.contains(number)){
//如果不存在:就添加浴骂,統(tǒng)計(jì)變量++乓土。
array.add(number);
count++;
}
}
//遍歷集合
for(Integer i : array){
System.out.println(i);
}
}
}
Day17
集合版登錄
//user類
public class User {
// 用戶名
private String username;
// 密碼
private String password;
public User() {
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
//定義接口,登錄和注冊
public interface UserDao {
//用戶登錄功能溯警,username用戶名趣苏,password密碼,return 返回登錄是否成功
public abstract boolean isLogin(String username, String password);
//用戶注冊功能梯轻,user食磕,要注冊的用戶信息
public abstract void regist(User user);
}
//接口的實(shí)現(xiàn)類
public class UserDaoImpl implements UserDao {
// 為了讓多個(gè)方法能夠使用同一個(gè)集合,就把集合定義為成員變量
// 為了不讓外人看到喳挑,用private
// 為了讓多個(gè)對象共享同一個(gè)成員變量彬伦,用static
private static ArrayList<User> array = new ArrayList<User>();
@Override
public boolean isLogin(String username, String password) {
// 遍歷集合滔悉,獲取每一個(gè)用戶,并判斷該用戶的用戶名和密碼是否和傳遞過來的匹配
boolean flag = false;
for (User u : array) {
if (u.getUsername().equals(username)
&& u.getPassword().equals(password)) {
flag = true;
break;
}
}
return flag;
}
@Override
public void regist(User user) {
// 把用戶信息存儲(chǔ)集合
// ArrayList<User> array = new ArrayList<User>();登錄也需要单绑,所以定義為成員變量
array.add(user);
}
}
public class UserTest {
public static void main(String[] args) {
// 為了能夠回來
while (true) {
// 歡迎界面回官,給出選擇項(xiàng)
System.out.println("--------------歡迎光臨--------------");
System.out.println("1 登錄");
System.out.println("2 注冊");
System.out.println("3 退出");
System.out.println("請輸入你的選擇:");
// 鍵盤錄入選擇,根據(jù)選擇做不同的操作
Scanner sc = new Scanner(System.in);
// 為了后面的錄入信息的方便搂橙,我所有的數(shù)據(jù)錄入全部用字符接收
String choiceString = sc.nextLine();
// switch語句的多個(gè)地方要使用歉提,我就定義到外面
UserDao ud = new UserDaoImpl();
// 經(jīng)過簡單的思考,我選擇了switch
switch (choiceString) {
case "1":
// 登錄界面区转,請輸入用戶名和密碼
System.out.println("--------------登錄界面--------------");
System.out.println("請輸入用戶名:");
String username = sc.nextLine();
System.out.println("請輸入密碼:");
String password = sc.nextLine();
// 調(diào)用登錄功能
// UserDao ud = new UserDaomImpl();
boolean flag = ud.isLogin(username, password);
if (flag) {
System.out.println("登錄成功");
} else {
System.out.println("用戶名或者密碼有誤,登錄失敗");
}
break;
case "2":
// 歡迎界面唯袄,請輸入用戶名和密碼
System.out.println("--------------注冊界面--------------");
System.out.println("請輸入用戶名:");
String newUsername = sc.nextLine();
System.out.println("請輸入密碼:");
String newPassword = sc.nextLine();
// 把用戶名和密碼封裝到一個(gè)對象中
User user = new User();
user.setUsername(newUsername);
user.setPassword(newPassword);
// 調(diào)用注冊功能
// 多態(tài)
// UserDao ud = new UserDaoImpl();
// 具體類使用
// UserDaoImpl udi = new UserDaoImpl();
ud.regist(user);
System.out.println("注冊成功");
break;
case "3":
default:
System.out.println("謝謝使用,歡迎下次再來");
System.exit(0);
break;
}
}
}
}
Sat
Collection
List
有序(存儲(chǔ)順序和取出順序一致),可重復(fù)
Set
無序(存儲(chǔ)順序和取出順序不一致),唯一
HashSet
它不保證 set 的迭代順序蜗帜;特別是它不保證該順序恒久不變
注意:雖然Set集合的元素?zé)o序,但是资厉,作為集合來說厅缺,它肯定有它自己的存儲(chǔ)順序,而你的順序恰好和它的存儲(chǔ)順序一致宴偿,這代表不了有序湘捎,你可以多存儲(chǔ)一些數(shù)據(jù),就能看到效果
public class SetDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
Set<String> set = new HashSet<String>();
// 創(chuàng)建并添加元素
set.add("hello");
set.add("java");
set.add("world");
set.add("java");
set.add("world");
//只會(huì)輸出hello,world,java窄刘,順序不固定
// 增強(qiáng)for
for (String s : set) {
System.out.println(s);
}
}
}
問題:為什么存儲(chǔ)字符串的時(shí)候窥妇,字符串內(nèi)容相同的只存儲(chǔ)了一個(gè)呢?
通過查看add方法的源碼,我們知道這個(gè)方法底層依賴 兩個(gè)方法:hashCode()和equals()
步驟:
首先比較哈希值
如果相同娩践,繼續(xù)走活翩,比較地址值或者走equals()
如果不同,就直接添加到集合中
按照方法的步驟來說:
先看hashCode()值是否相同
相同:繼續(xù)走equals()方法
返回true: 說明元素重復(fù),就不添加
返回false:說明元素不重復(fù)翻伺,就添加到集合
不同:就直接把元素添加到集合
如果類沒有重寫這兩個(gè)方法材泄,默認(rèn)使用的Object(),一般來說不同相同吨岭,而String類重寫了hashCode()和equals()方法拉宗,所以,它就可以把內(nèi)容相同的字符串去掉辣辫,只留下一個(gè)
public class Student {
private String name;
private int age;
public Student(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 boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Student)) return false;
Student student = (Student) o;
return getAge() == student.getAge() && Objects.equals(getName(), student.getName());
}
@Override
public int hashCode() {
return Objects.hash(getName(), getAge());
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class StrudentTest {
public static void main(String[] args) {
HashSet<Student> hs = new HashSet<Student>();
Student s1 = new Student("張三",17);
Student s2 = new Student("李四",15);
Student s3 = new Student("張三",17);
Student s4 = new Student("王五",15);
Student s5 = new Student("張",18);
hs.add(s1);
hs.add(s2);
hs.add(s3);
hs.add(s4);
hs.add(s5);
for (Student s :hs){
System.out.println(s);
}
}
}
LinkedHashSet
底層數(shù)據(jù)結(jié)構(gòu)由哈希表和鏈表組成
哈希表保證元素的唯一性
鏈表保證元素有素(存儲(chǔ)和取出是一致)
public class LinkedHashSetDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
LinkedHashSet<String> hs = new LinkedHashSet<String>();
// 創(chuàng)建并添加元素
hs.add("hello");
hs.add("world");
hs.add("java");
hs.add("world");
hs.add("java");
// 遍歷
for (String s : hs) {
System.out.println(s);
}
}
}
TreeSet
能夠?qū)υ匕凑漳撤N規(guī)則進(jìn)行排序
排序有兩種方式
自然排序的構(gòu)造方法TreeSet<Student> ts = new TreeSet<Student>()
比較器排序的構(gòu)造方法public TreeSet(Comparator comparator)
TreeSet集合的特點(diǎn):排序和唯一
通過觀察TreeSet的add()方法旦事,我們知道最終要看TreeMap的put()方法
compareTo方法
字符串與對象進(jìn)行比較 int compareTo(Object o) o -- 要比較的對象
按字典順序比較兩個(gè)字符串 int compareTo(String anotherString) anotherString -- 要比較的字符串
返回值是整型,它是先比較對應(yīng)字符的大小(ASCII碼順序)急灭,如果第一個(gè)字符和參數(shù)的第一個(gè)字符不等姐浮,結(jié)束比較,返回他們之間的長度差值化戳,如果第一個(gè)字符和參數(shù)的第一個(gè)字符相等单料,則以第二個(gè)字符和參數(shù)的第二個(gè)字符做比較埋凯,以此類推,直至比較的字符或被比較的字符有一方結(jié)束
如果參數(shù)字符串等于此字符串,則返回值 0
如果此字符串小于字符串參數(shù)扫尖,則返回一個(gè)小于 0 的值
如果此字符串大于字符串參數(shù)白对,則返回一個(gè)大于 0 的值
說明:
如果第一個(gè)字符和參數(shù)的第一個(gè)字符不等,結(jié)束比較换怖,返回第一個(gè)字符的ASCII碼差值
如果第一個(gè)字符和參數(shù)的第一個(gè)字符相等甩恼,則以第二個(gè)字符和參數(shù)的第二個(gè)字符做比較,以此類推,直至不等為止沉颂,返回該字符的ASCII碼差值条摸, 如果兩個(gè)字符串不一樣長,可對應(yīng)字符又完全一樣铸屉,則返回兩個(gè)字符串的長度差值
自然排序
public class TreeSetDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
// 自然順序進(jìn)行排序
TreeSet<Integer> ts = new TreeSet<Integer>();
// 創(chuàng)建元素并添加
// 20,18,23,22,17,24,19,18,24
ts.add(20);
ts.add(18);
ts.add(23);
ts.add(22);
ts.add(17);
ts.add(24);
ts.add(19);
ts.add(18);
ts.add(24);
// 遍歷
for (Integer i : ts) {
System.out.println(i);
}
}
}
要想使用TreeSet方法(自然排序)存儲(chǔ)自定義對象钉蒲,首先要將對象所屬的類去實(shí)現(xiàn)Comparable接口,然后根據(jù)給出的排序條件去重寫Comparable接口的compareTo方法滿足排序的條件彻坛,還要注意隱含的條件
/*
* 需求:請按照姓名的長度排序
*/
//如果一個(gè)類的元素要想能夠進(jìn)行自然排序顷啼,元素所屬的類就必須實(shí)現(xiàn)自然排序接口,根據(jù)條件重寫compareTo方法
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
super();
}
public Student(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 int compareTo(Student s) {
// 主要條件 姓名的長度
int num = this.name.length() - s.name.length();
// 姓名的長度相同昌屉,不代表姓名的內(nèi)容相同
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
// 姓名的長度和內(nèi)容相同钙蒙,不代表年齡相同,所以還得繼續(xù)判斷年齡
int num3 = num2 == 0 ? this.age - s.age : num2;
return num3;
}
}
public class TreeSetDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
TreeSet<Student> ts = new TreeSet<Student>();
// 創(chuàng)建元素
Student s1 = new Student("linqingxia", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wanglihong", 23);
Student s4 = new Student("linqingxia", 27);
Student s5 = new Student("liushishi", 22);
Student s6 = new Student("wuqilong", 40);
Student s7 = new Student("fengqingy", 22);
Student s8 = new Student("linqingxia", 29);
// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);
// 遍歷
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
比較器排序
/*
* 需求:請按照姓名的長度排序
*
* TreeSet集合保證元素排序和唯一性的原理
* 唯一性:是根據(jù)比較的返回是否是0來決定间驮。
* 排序:
* A:自然排序(元素具備比較性)
* 讓元素所屬的類實(shí)現(xiàn)自然排序接口 Comparable
* B:比較器排序(集合具備比較性)
* 讓集合的構(gòu)造方法接收一個(gè)比較器接口的子類對象 Comparator
*/
public class TreeSetDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
// TreeSet<Student> ts = new TreeSet<Student>(new MyComparator());比較器排序
// 如果一個(gè)方法的參數(shù)是接口躬厌,那么真正要的是接口的實(shí)現(xiàn)類的對象
// 而匿名內(nèi)部類就可以實(shí)現(xiàn)這個(gè)東西
TreeSet<Student> ts = new TreeSet<Student>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 姓名長度
int num = s1.getName().length() - s2.getName().length();
// 姓名內(nèi)容
int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
: num;
// 年齡
int num3 = num2 == 0 ? s1.getAge() - s2.getAge() : num2;
return num3;
}
});
// 創(chuàng)建元素
Student s1 = new Student("linqingxia", 27);
Student s2 = new Student("zhangguorong", 29);
Student s3 = new Student("wanglihong", 23);
Student s4 = new Student("linqingxia", 27);
Student s5 = new Student("liushishi", 22);
Student s6 = new Student("wuqilong", 40);
Student s7 = new Student("fengqingy", 22);
Student s8 = new Student("linqingxia", 29);
// 添加元素
ts.add(s1);
ts.add(s2);
ts.add(s3);
ts.add(s4);
ts.add(s5);
ts.add(s6);
ts.add(s7);
ts.add(s8);
// 遍歷
for (Student s : ts) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
獲取10個(gè)1-20之間的隨機(jī)數(shù)集合版
public class RandomTest {
public static void main(String[] args) {
HashSet<Integer> hs = new HashSet<Integer>();
Random r = new Random();
while (hs.size() < 10) {
int num = r.nextInt(20) + 1;
hs.add(num);
}
for (Integer i : hs) {
System.out.println(i);
}
}
}
Day18
Map
特點(diǎn):將鍵映射到值的對象,一個(gè)映射不能包含重復(fù)的鍵竞帽;每個(gè)鍵最多只能映射到一個(gè)值扛施,參考學(xué)號(hào)和學(xué)生,一個(gè)學(xué)號(hào)對應(yīng)一個(gè)學(xué)生屹篓,學(xué)號(hào)不可以重復(fù)煮嫌,學(xué)生的姓名可以重復(fù),學(xué)號(hào)為鍵抱虐,學(xué)生為值
Map集合和Collection集合的區(qū)別
Map集合存儲(chǔ)元素是成對出現(xiàn)的昌阿,Map集合的鍵是唯一的,值是可重復(fù)的
Collection集合存儲(chǔ)元素是單獨(dú)出現(xiàn)的恳邀,Collection的兒子Set是唯一的懦冰,List是可重復(fù)的
Map集合的功能概述:
添加功能
V put(K key,V value):添加元素,如果鍵是第一次存儲(chǔ)谣沸,就直接存儲(chǔ)元素刷钢,返回null,如果鍵不是第一次存在乳附,就用值把以前的值替換掉内地,返回以前的值
刪除功能
void clear():移除所有的鍵值對元素
V remove(Object key):根據(jù)鍵刪除鍵值對元素伴澄,并把值返回
判斷功能
boolean containsKey(Object key):判斷集合是否包含指定的鍵
boolean containsValue(Object value):判斷集合是否包含指定的值
boolean isEmpty():判斷集合是否為空
獲取功能
Set<Map.Entry<K,V>> entrySet()返回的是鍵值對對象的集合
V get(Object key):根據(jù)鍵獲取值
Set<K> keySet():獲取集合中所有鍵的集合
Collection<V> values():獲取集合中所有值的集合
長度功能
int size():返回集合中的鍵值對的對數(shù)
public class MapDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
Map<String, String> map = new HashMap<String, String>();
// 添加元素
// V put(K key,V value):添加元素
// System.out.println("put:" + map.put("文章", "馬伊俐"));
// System.out.println("put:" + map.put("文章", "姚笛"));
map.put("鄧超", "孫儷");
map.put("黃曉明", "楊穎");
map.put("周杰倫", "蔡依林");
map.put("劉愷威", "楊冪");
// void clear():移除所有的鍵值對元素
// map.clear();
// V remove(Object key):根據(jù)鍵刪除鍵值對元素,并把值返回
// System.out.println("remove:" + map.remove("黃曉明"));
// System.out.println("remove:" + map.remove("黃曉波"));
// boolean containsKey(Object key):判斷集合是否包含指定的鍵
// System.out.println("containsKey:" + map.containsKey("黃曉明"));
// System.out.println("containsKey:" + map.containsKey("黃曉波"));
// boolean isEmpty():判斷集合是否為空
// System.out.println("isEmpty:"+map.isEmpty());
//int size():返回集合中的鍵值對的對數(shù)
System.out.println("size:"+map.size());
// 輸出集合名稱
System.out.println("map:" + map);
}
}
Map集合的遍歷
方式一
獲取所有的鍵
遍歷鍵的集合阱缓,獲取得到每一個(gè)鍵
根據(jù)鍵去找值
方式二
獲取所有鍵值對對象的集合
遍歷鍵值對對象的集合非凌,得到每一個(gè)鍵值對對象
根據(jù)鍵值對對象獲取鍵和值
public class MapPrint {
public static void main(String[] args) {
//創(chuàng)建集合
Map<Integer, String> map = new HashMap<>();
//添加元素
map.put(201801, "張三");
map.put(201802, "李四");
map.put(201803, "王五");
map.put(201804, "趙六");
map.put(201805, "付七");
//遍歷集合方式一
//先獲取所有的鍵的集合
Set<Integer> set = map.keySet();
//遍歷鍵的集合,得到每一個(gè)鍵
for (Integer key : set) {
//根據(jù)鍵去找值
String value = map.get(key);
//輸出鍵和值
System.out.println(key+value);
}
//遍歷集合方式二
//Set<Map.Entry<K,V>> entrySet():返回的是鍵值對對象的集合
//獲取鍵值對對象
Set <Map.Entry<Integer,String>> sm = map.entrySet();
// 遍歷鍵值對對象的集合荆针,得到每一個(gè)鍵值對對象
for (Map.Entry<Integer,String> me : sm){
// 根據(jù)鍵值對對象獲取鍵和值
Integer key = me.getKey();
String value = me.getValue();
System.out.println(key+value);
}
}
}
HashMap
/*
* HashMap<Student,String>
* 鍵:Student
* 要求:如果兩個(gè)對象的成員變量值都相同敞嗡,則為同一個(gè)對象需要重寫方法
* 值:String
*/
public class HashMapDemo4 {
public static void main(String[] args) {
// 創(chuàng)建集合對象
HashMap<Student, String> hm = new HashMap<Student, String>();
// 創(chuàng)建學(xué)生對象
Student s1 = new Student("貂蟬", 27);
Student s2 = new Student("王昭君", 30);
Student s3 = new Student("西施", 33);
Student s4 = new Student("楊玉環(huán)", 35);
Student s5 = new Student("貂蟬", 27);
// 添加元素
hm.put(s1, "8888");
hm.put(s2, "6666");
hm.put(s3, "5555");
hm.put(s4, "7777");
hm.put(s5, "9999");
// 遍歷
Set<Student> set = hm.keySet();
for (Student key : set) {
String value = hm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---"
+ value);
}
}
}
public class Student {
private String name;
private int age;
public Student() {
super();
}
public Student(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 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;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Student other = (Student) obj;
if (age != other.age)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
return true;
}
}
LinkedHashMap
是Map接口的哈希表和鏈接列表實(shí)現(xiàn),具有可預(yù)知的迭代順序
由哈希表保證鍵的唯一性
由鏈表保證鍵盤的有序(存儲(chǔ)和取出的順序一致)
TreeMap
是基于紅黑樹的Map接口的實(shí)現(xiàn)\
public class TreeMapDemo2 {
public static void main(String[] args) {
// 創(chuàng)建集合對象
TreeMap<Student, String> tm = new TreeMap<Student, String>(
new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
// 主要條件
int num = s1.getAge() - s2.getAge();
// 次要條件
int num2 = num == 0 ? s1.getName().compareTo(
s2.getName()) : num;
return num2;
}
});
// 創(chuàng)建學(xué)生對象
Student s1 = new Student("潘安", 30);
Student s2 = new Student("柳下惠", 35);
Student s3 = new Student("唐伯虎", 33);
Student s4 = new Student("燕青", 32);
Student s5 = new Student("唐伯虎", 33);
// 存儲(chǔ)元素
tm.put(s1, "宋朝");
tm.put(s2, "元朝");
tm.put(s3, "明朝");
tm.put(s4, "清朝");
tm.put(s5, "漢朝");
// 遍歷
Set<Student> set = tm.keySet();
for (Student key : set) {
String value = tm.get(key);
System.out.println(key.getName() + "---" + key.getAge() + "---"+ value);
}
}
}
鍵盤錄入一串字符航背,例如"aababcabcdabcde",獲取字符串中每一個(gè)字母出現(xiàn)的次數(shù)要求結(jié)果:a(5)b(4)c(3)d(2)e(1)
/*
* 定義一個(gè)字符串喉悴,鍵盤獲取
* 定義一個(gè)TreeMap集合
* 鍵:Character
* 值:Integer
* 把字符串轉(zhuǎn)換為字符數(shù)組
* 遍歷字符數(shù)組,得到每一個(gè)字符
* 拿剛才得到的字符作為鍵到集合中去找值玖媚,看返回值
* 是null:說明該鍵不存在箕肃,就把該字符作為鍵,1作為值存儲(chǔ)
* 不是null:說明該鍵存在今魔,就把值加1突雪,然后重寫存儲(chǔ)該鍵和值
* 定義字符串緩沖區(qū)變量,或者直接遍歷集合
* 遍歷集合,得到鍵和值涡贱,進(jìn)行按照要求拼接
* 把字符串緩沖區(qū)轉(zhuǎn)換為字符串輸出
*
* */
public class StrudentTest {
public static void main(String[] args) {
//創(chuàng)建鍵盤獲取對象
Scanner sc = new Scanner(System.in);
//定義字符串接受鍵盤錄入
String s = sc.nextLine();
//創(chuàng)建集合
TreeMap<Character,Integer> tm = new TreeMap<>();
//將鍵盤獲取的字符串轉(zhuǎn)換成字符數(shù)組
char chs[] = s.toCharArray();
//遍歷字符數(shù)組
for (Character ch :chs){
//得到每一個(gè)元素
Integer i = tm.get(ch);
//比較
if (i == null){
tm.put(ch,1);
}else{
i++;
tm.put(ch,i);
}
}
//遍歷集合
Set<Character> set = tm.keySet();
for (Character c :set){
Integer value = tm.get(c);
System.out.print(c+"("+value+")");//如果直接輸出c+value,會(huì)把字符轉(zhuǎn)換成ascll碼表的值相加
}
System.out.println("------------");
//創(chuàng)建字符緩沖區(qū)對象
StringBuilder sb= new StringBuilder();
//遍歷集合惹想,得到鍵和值问词,進(jìn)行按照要求拼接
Set<Character> set2 = tm.keySet();
for(Character key : set2){
Integer value = tm.get(key);
sb.append(key).append("(").append(value).append(")");
}
//把字符串緩沖區(qū)轉(zhuǎn)換為字符串輸出
String result = sb.toString();
System.out.println("result:"+result);
}
}
集合嵌套的遍歷
HashMap嵌套HashMap
/*
*需求 :乒乓球教學(xué)班分為基礎(chǔ)班和進(jìn)階班
* 基礎(chǔ)班 張三 20
* 李四 22
* 進(jìn)階班 王五 18
* 趙六 19
* 利用集合嵌套輸出
*分析:乒乓球教學(xué)班作為一個(gè)集合<基礎(chǔ)班 (張三,20)> ==<String HashMap<String,Integer>>
* 基礎(chǔ)班作為一個(gè)集合<String,Integer>
* 進(jìn)階班作為一個(gè)集合<String,Integer>
* */
public class Test {
public static void main(String[] args) {
//創(chuàng)建大集合乒乓教學(xué)班
HashMap<String,HashMap<String,Integer>> ppmap = new HashMap<String,HashMap<String,Integer>>();
//創(chuàng)建基礎(chǔ)班集合
HashMap<String,Integer> jcmap = new HashMap<String ,Integer>();
//添加基礎(chǔ)班元素
jcmap.put("張三",20);
jcmap.put("李四",22);
//添加大集合乒乓球教學(xué)班元素
ppmap.put("基礎(chǔ)班",jcmap);
//創(chuàng)建進(jìn)階班集合
HashMap<String,Integer> jjmap = new HashMap<String ,Integer>();
//添加基礎(chǔ)班元素
jjmap.put("王五",18);
jjmap.put("趙六",19);
//添加大集合乒乓球教學(xué)班元素
ppmap.put("進(jìn)階班",jjmap);
//遍歷
//先得到大集合所有的主鍵
Set<String> ppmapset = ppmap.keySet();
//增強(qiáng)for遍歷大循環(huán)
for (String ppmapkey :ppmapset){
HashMap<String,Integer> ppvalue = ppmap.get(ppmapkey);
System.out.println(ppmapkey);
//遍歷內(nèi)集合基礎(chǔ)班嘀粱,進(jìn)階班
Set<String> ppvalueset = ppvalue.keySet();
for (String key : ppvalueset){
Integer value = ppvalue.get(key);
System.out.println('\t'+key + " "+value);
}
}
}
}
HashMap嵌套ArrayList
*需求:
*假設(shè)HashMap集合的元素是ArrayList有3個(gè)
*每一個(gè)ArrayList集合的值是字符串
*結(jié)果:
* 三國演義
* 呂布
* 周瑜
* 笑傲江湖
* 令狐沖
* 林平之
* 神雕俠侶
* 郭靖
* 楊過
*/
public class HashMapIncludeArrayListDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
HashMap<String, ArrayList<String>> hm = new HashMap<String, ArrayList<String>>();
// 創(chuàng)建元素集合1
ArrayList<String> array1 = new ArrayList<String>();
array1.add("呂布");
array1.add("周瑜");
hm.put("三國演義", array1);
// 創(chuàng)建元素集合2
ArrayList<String> array2 = new ArrayList<String>();
array2.add("令狐沖");
array2.add("林平之");
hm.put("笑傲江湖", array2);
// 創(chuàng)建元素集合3
ArrayList<String> array3 = new ArrayList<String>();
array3.add("郭靖");
array3.add("楊過");
hm.put("神雕俠侶", array3);
//遍歷集合
Set<String> set = hm.keySet();
for(String key : set){
System.out.println(key);
ArrayList<String> value = hm.get(key);
for(String s : value){
System.out.println("\t"+s);
}
}
}
}
ArrayList集合嵌套HashMap
/*
* 需求:
*假設(shè)ArrayList集合的元素是HashMap有3個(gè)
*每一個(gè)HashMap集合的鍵和值都是字符串
*結(jié)果:
* 周瑜---小喬
* 呂布---貂蟬
*
* 郭靖---黃蓉
* 楊過---小龍女
*
* 令狐沖---任盈盈
* 林平之---岳靈珊
*/
public class ArrayListIncludeHashMapDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
ArrayList<HashMap<String, String>> array = new ArrayList<HashMap<String, String>>();
// 創(chuàng)建元素1
HashMap<String, String> hm1 = new HashMap<String, String>();
hm1.put("周瑜", "小喬");
hm1.put("呂布", "貂蟬");
// 把元素添加到array里面
array.add(hm1);
// 創(chuàng)建元素1
HashMap<String, String> hm2 = new HashMap<String, String>();
hm2.put("郭靖", "黃蓉");
hm2.put("楊過", "小龍女");
// 把元素添加到array里面
array.add(hm2);
// 創(chuàng)建元素1
HashMap<String, String> hm3 = new HashMap<String, String>();
hm3.put("令狐沖", "任盈盈");
hm3.put("林平之", "岳靈珊");
// 把元素添加到array里面
array.add(hm3);
// 遍歷
for (HashMap<String, String> hm : array) {
Set<String> set = hm.keySet();
for (String key : set) {
String value = hm.get(key);
System.out.println(key + "---" + value);
}
}
}
}
Hashtable和HashMap的區(qū)別
Hashtable:線程安全激挪,效率低,不允許null鍵和null值
HashMap:線程不安全锋叨,效率高垄分,允許null鍵和null值
HashMap是1.2版本用來替代Hashtable的,用法相同娃磺,只是允許使用空鍵和空值
List,Set,Map等接口是否都繼承子Map接口
List薄湿,Set不是繼承自Map接口,它們繼承自Collection接口
Map接口本身就是一個(gè)頂層接口
Collections
是針對集合進(jìn)行操作的工具類偷卧,都是靜態(tài)方法
方法:
public static <T> void sort(List<T> list):排序 默認(rèn)情況下是自然順序豺瘤。
public static <T> int binarySearch(List<?> list,T key):二分查找
public static <T> T max(Collection<?> coll):最大值
public static void reverse(List<?> list):反轉(zhuǎn)
public static void shuffle(List<?> list):隨機(jī)置換
Collection和Collections的區(qū)別
Collection:是單列集合的頂層接口,有子接口List和Set
Collections:是針對集合操作的工具類听诸,有對集合進(jìn)行排序和二分查找的方法
//Collections方法的用法
public class CollectionsDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
List<Integer> list = new ArrayList<Integer>();
// 添加元素
list.add(30);
list.add(20);
list.add(50);
list.add(10);
list.add(40);
System.out.println("list:" + list);
// public static <T> void sort(List<T> list):排序 默認(rèn)情況下是自然順序坐求。
// Collections.sort(list);
// System.out.println("list:" + list);
// [10, 20, 30, 40, 50]
// public static <T> int binarySearch(List<?> list,T key):二分查找
// System.out
// .println("binarySearch:" + Collections.binarySearch(list, 30));
// System.out.println("binarySearch:"
// + Collections.binarySearch(list, 300));
// public static <T> T max(Collection<?> coll):最大值
// System.out.println("max:"+Collections.max(list));
// public static void reverse(List<?> list):反轉(zhuǎn)
// Collections.reverse(list);
// System.out.println("list:" + list);
//public static void shuffle(List<?> list):隨機(jī)置換
Collections.shuffle(list);
System.out.println("list:" + list);
}
}
Collections存儲(chǔ)自定義對象的排序
public class Student implements Comparable<Student> {
private String name;
private int age;
public Student() {
super();
}
public Student(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 int compareTo(Student s) {
int num = this.age - s.age;
int num2 = num == 0 ? this.name.compareTo(s.name) : num;
return num2;
}
}
public class CollectionsDemo {
public static void main(String[] args) {
// 創(chuàng)建集合對象
List<Student> list = new ArrayList<Student>();
// 創(chuàng)建學(xué)生對象
Student s1 = new Student("林青霞", 27);
Student s2 = new Student("風(fēng)清揚(yáng)", 30);
Student s3 = new Student("劉曉曲", 28);
Student s4 = new Student("武鑫", 29);
Student s5 = new Student("林青霞", 27);
// 添加元素對象
list.add(s1);
list.add(s2);
list.add(s3);
list.add(s4);
list.add(s5);
// 排序
// 自然排序
// Collections.sort(list);
// 比較器排序
// 如果同時(shí)有自然排序和比較器排序,以比較器排序?yàn)橹? Collections.sort(list, new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getAge() - s1.getAge();
int num2 = num == 0 ? s1.getName().compareTo(s2.getName())
: num;
return num2;
}
});
// 遍歷集合
for (Student s : list) {
System.out.println(s.getName() + "---" + s.getAge());
}
}
}
斗地主發(fā)牌案例
/*
*需求 :實(shí)現(xiàn)斗地主發(fā)牌
* 分析:創(chuàng)建一個(gè)HashMap集合晌梨,存儲(chǔ)牌的編號(hào)和牌(0 -- ?3桥嗤,1 -- ?3须妻,2 -- ?3,3 -- ?3.....按照斗地主的大小順序存)
* 創(chuàng)建一個(gè)ArrayList集合存儲(chǔ)牌的編號(hào)泛领,方便使用public static void shuffle(List<?> list)隨機(jī)置換功能
* 創(chuàng)建花色和點(diǎn)數(shù)數(shù)組
* 從編號(hào)0開始往HashMap中存儲(chǔ)元素荒吏,并把編號(hào)放到ArrayList中
* 洗牌,對ArrayList進(jìn)行置換功能师逸,打亂順序
* 發(fā)牌司倚,發(fā)的是牌的編號(hào),用TreeSet接收篓像,方便排序
* 看牌动知,遍歷TreeSet集合得到編號(hào),到HashMap中找對應(yīng)的值
* */
public class Test {
public static void main(String[] args) {
//創(chuàng)建一個(gè)HashMap集合
HashMap<Integer,String> hm = new HashMap<Integer,String>();
//創(chuàng)建一個(gè)ArrayList
ArrayList<Integer> array = new ArrayList<Integer>();
//創(chuàng)建花色和點(diǎn)數(shù)數(shù)組
String []colors = {"?","?","?","?"};
//要根據(jù)斗地主的規(guī)則來定義順序员辩,方便存儲(chǔ)
String []numbers = {"3","4","5","6","7", "8","9","10","J","Q","K","A","2",};
//定義索引盒粮,并遍歷花色和點(diǎn)數(shù)數(shù)組,存儲(chǔ)元素
int index = 0;
for (String num :numbers){
for (String color :colors){
//將花色和點(diǎn)數(shù)拼接
String poker = color.concat(num);
//把編號(hào)和牌放入HashMap集合
hm.put(index,poker);
//將編號(hào)放入ArrayList
array.add(index);
index++;
}
}
//存儲(chǔ)大小王
hm.put(index,"小王");
array.add(index);
index++;
hm.put(index,"大王");
array.add(index);
//洗牌,將ArrayList中的編號(hào)打亂
Collections.shuffle(array);
//發(fā)牌奠滑,定義TreeSet接收丹皱,方便排序
//定義三個(gè)玩家和底牌的集合
TreeSet<Integer> zhangSan =new TreeSet<Integer>();
TreeSet<Integer> liSi =new TreeSet<Integer>();
TreeSet<Integer> zhaoWu =new TreeSet<Integer>();
TreeSet<Integer> diPai =new TreeSet<Integer>();
//遍歷ArrayList集合,讓每個(gè)玩家得到編號(hào)以及底牌
for (int i = 0; i < array.size(); i++) {
if (i >= array.size()-3){
diPai.add(array.get(i));
}else if (i % 3 ==0){
zhangSan.add(array.get(i));
}else if (i % 3 ==1){
liSi.add(array.get(i));
}else if (i%3 ==2){
zhaoWu.add(array.get(i));
}
}
//看牌
lookPoker("張三",zhangSan,hm);
lookPoker("李四",liSi,hm);
lookPoker("趙五",zhaoWu,hm);
lookPoker("底牌",diPai,hm);
}
//看牌宋税,遍歷TreeSet集合得到編號(hào)摊崭,到HashMap中找對應(yīng)的值,需要遍歷三個(gè)集合所以定義為方法
public static void lookPoker(String name,TreeSet<Integer> set,HashMap<Integer,String> hm){
System.out.print(name+"的牌是");
for (Integer in :set){
System.out.print(hm.get(in)+" ");
}
System.out.println();
}
}
集合知識(shí)點(diǎn)總結(jié)
Collection(單列集合)分為List和Set
List(有序,可重復(fù))分為ArrayList,Vector杰赛,LinkedList
ArrayList
底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢
線程不安全,效率高
Vector
底層數(shù)據(jù)結(jié)構(gòu)是數(shù)組,查詢快,增刪慢
線程安全,效率低
LinkedList
底層數(shù)據(jù)結(jié)構(gòu)是鏈表,查詢慢,增刪快
線程不安全,效率高
Set(無序,唯一)分為HashSet呢簸,LinkedHashSet,TreeSet
HashSet
底層數(shù)據(jù)結(jié)構(gòu)是哈希表
哈希表依賴兩個(gè)方法:hashCode()和equals()
執(zhí)行順序:
首先判斷hashCode()值是否相同
是:繼續(xù)執(zhí)行equals(),看其返回值
是true:說明元素重復(fù)乏屯,不添加
是false:就直接添加到集合
否:就直接添加到集合
最終:
自動(dòng)生成hashCode()和equals()即可
LinkedHashSet
底層數(shù)據(jù)結(jié)構(gòu)由鏈表和哈希表組成
由鏈表保證元素有序
由哈希表保證元素唯一
TreeSet
底層數(shù)據(jù)結(jié)構(gòu)是紅黑樹根时。(是一種自平衡的二叉樹)
如何保證元素唯一性呢?根據(jù)比較的返回值是否是0來決定
如何保證元素的排序呢?
兩種方式
自然排序(元素具備比較性)
讓元素所屬的類實(shí)現(xiàn)Comparable接口
比較器排序(集合具備比較性)
讓集合接收一個(gè)Comparator的實(shí)現(xiàn)類對象
Map(雙列集合)分為HashMap,LinkedHashMap辰晕,Hashtable蛤迎,TreeMap
Map集合的數(shù)據(jù)結(jié)構(gòu)僅僅針對鍵有效,與值無關(guān)
存儲(chǔ)的是鍵值對形式的元素含友,鍵唯一替裆,值可重復(fù)
HashMap
底層數(shù)據(jù)結(jié)構(gòu)是哈希表。線程不安全窘问,效率高
哈希表依賴兩個(gè)方法:hashCode()和equals()
執(zhí)行順序:
首先判斷hashCode()值是否相同
是:繼續(xù)執(zhí)行equals(),看其返回值
是true:說明元素重復(fù)扎唾,不添加
是false:就直接添加到集合
否:就直接添加到集合
最終:
自動(dòng)生成hashCode()和equals()即可
LinkedHashMap
底層數(shù)據(jù)結(jié)構(gòu)由鏈表和哈希表組成,由鏈表保證元素有序南缓,由哈希表保證元素唯一
Hashtable
底層數(shù)據(jù)結(jié)構(gòu)是哈希表胸遇。線程安全,效率低
哈希表依賴兩個(gè)方法:hashCode()和equals()
執(zhí)行順序:
首先判斷hashCode()值是否相同
是:繼續(xù)執(zhí)行equals(),看其返回值
是true:說明元素重復(fù)汉形,不添加
是false:就直接添加到集合
否:就直接添加到集合
最終:
自動(dòng)生成hashCode()和equals()即可
TreeMap
底層數(shù)據(jù)結(jié)構(gòu)是紅黑樹纸镊。(是一種自平衡的二叉樹)
如何保證元素唯一性呢?根據(jù)比較的返回值是否是0來決定
如何保證元素的排序呢?
兩種方式
自然排序(元素具備比較性)
讓元素所屬的類實(shí)現(xiàn)Comparable接口
比較器排序(集合具備比較性)
讓集合接收一個(gè)Comparator的實(shí)現(xiàn)類對象
到底使用那種集合要看需求
是否是鍵值對象形式:
是:Map
鍵是否需要排序:
是:TreeMap
否:HashMap
不知道倍阐,就使用HashMap
否:Collection
元素是否唯一:
是:Set
元素是否需要排序:
是:TreeSet
否:HashSet
不知道,就使用HashSet
否:List
要安全嗎:
是:Vector(其實(shí)我們也不用它,后面我們講解了多線程以后逗威,我在給你回顧用誰)
否:ArrayList或者LinkedList
增刪多:LinkedList
查詢多:ArrayList
不知道峰搪,就使用ArrayList
不知道,就使用ArrayList
集合的常見方法及遍歷方式
Collection:
方法
add() 甜加
remove()刪除
contains()判斷
iterator()迭代器
size()長度
遍歷:
增強(qiáng)for
迭代器
List(方法繼承自Collection)
get()
遍歷:
普通for
增強(qiáng)for
迭代器
Set(方法繼承自Collection)
遍歷
增強(qiáng)for
迭代器
Map:
put() 添加
remove() 刪除
containskey()判斷鍵
containsValue()判斷值
keySet()獲取鍵
get()
value()
entrySet()
size()長度
遍歷:
根據(jù)鍵找值
根據(jù)鍵值對對象分別找鍵和值
ArrayList,LinkedList,HashSet,HashMap(掌握)
存儲(chǔ)字符串和自定義對象數(shù)據(jù)并遍歷
Day19
IO流
異常:程序出現(xiàn)了不正常的情況
程序的異常:Throwable
嚴(yán)重問題:Error 我們不處理凯旭。這種問題一般都是很嚴(yán)重的概耻,比如說內(nèi)存溢出
問題:Exception
編譯期問題:不是RuntimeException的異常 必須進(jìn)行處理的,因?yàn)槟悴惶幚砉藓簦幾g就不能通過
運(yùn)行期問題:RuntimeException 這種問題我們也不處理鞠柄,因?yàn)槭悄愕膯栴},而且這個(gè)問題出現(xiàn)肯定是我們的代碼不夠嚴(yán)謹(jǐn)嫉柴,需要修正代碼的
如何程序出現(xiàn)了問題厌杜,我們沒有做任何處理,最終jvm會(huì)做出默認(rèn)的處理,把異常的名稱计螺,原因及出現(xiàn)的問題等信息輸出在控制臺(tái),同時(shí)會(huì)結(jié)束程序
異常處理
-try...catch...finally
-throws 拋出
try...catch...finally的處理格式:
try {
可能出現(xiàn)問題的代碼;
}catch(異常名 變量) {
針對問題的處理;
}finally {
釋放資源;
}
變形格式:
try {
可能出現(xiàn)問題的代碼;
}catch(異常名 變量) {
針對問題的處理;
}
注意:
try里面的代碼越少越好
catch里面必須有內(nèi)容夯尽,哪怕是給出一個(gè)簡單的提示
public class ExceptionDemo {
public static void main(String[] args) {
// 第一階段
int a = 10;
// int b = 2;
int b = 0;
try {
System.out.println(a / b);
} catch (ArithmeticException ae) {
System.out.println("除數(shù)不能為0");
}
// 第二階段
System.out.println("over");
}
}
兩個(gè)及以上的異常的處理
-每一個(gè)寫一個(gè)try...catch
〉锹-寫一個(gè)try匙握,多個(gè)catch
try{
...
}catch(異常類名 變量名) {
...
}
catch(異常類名 變量名) {
...
}
...
注意事項(xiàng)
能明確的盡量明確,不要用大的來處理
平級(jí)關(guān)系的異常誰前誰后無所謂陈轿,如果出現(xiàn)了子父關(guān)系圈纺,父必須在后面
注意:
一但try里面出了問題,就會(huì)在這里把問題給拋出去济欢,然后和catch里面的問題進(jìn)行匹配
一但有匹配的,就執(zhí)行catch里面的處理小渊,然后結(jié)束了try...catch
繼續(xù)執(zhí)行后面的語句
public class ExceptionDemo2 {
public static void main(String[] args) {
// method1();
// method2();
// method3();
method4();
}
public static void method4() {
int a = 10;
int b = 0;
int[] arr = { 1, 2, 3 };
// Exception在最后
try {
System.out.println(a / b);
System.out.println(arr[3]);
System.out.println("這里出現(xiàn)了一個(gè)異常法褥,你不太清楚是誰,該怎么辦呢?");
} catch (ArithmeticException e) {
System.out.println("除數(shù)不能為0");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("你訪問了不該的訪問的索引");
} catch (Exception e) {
System.out.println("出問題了");
}
// Exception在前面是不可以的
// try {
// System.out.println(a / b);
// System.out.println(arr[3]);
// System.out.println("這里出現(xiàn)了一個(gè)異常酬屉,你不太清楚是誰半等,該怎么辦呢?");
// } catch (Exception e) {
// System.out.println("出問題了");
// } catch (ArithmeticException e) {
// System.out.println("除數(shù)不能為0");
// } catch (ArrayIndexOutOfBoundsException e) {
// System.out.println("你訪問了不該的訪問的索引");
// }
System.out.println("over");
}
// 兩個(gè)異常的處理
public static void method3() {
int a = 10;
int b = 0;
int[] arr = { 1, 2, 3 };
try {
System.out.println(arr[3]);
System.out.println(a / b);
// System.out.println(arr[3]);
} catch (ArithmeticException e) {
System.out.println("除數(shù)不能為0");
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("你訪問了不該的訪問的索引");
}
System.out.println("over");
}
// 兩個(gè)異常
public static void method2() {
int a = 10;
int b = 0;
try {
System.out.println(a / b);
} catch (ArithmeticException e) {
System.out.println("除數(shù)不能為0");
}
int[] arr = { 1, 2, 3 };
try {
System.out.println(arr[3]);
} catch (ArrayIndexOutOfBoundsException e) {
System.out.println("你訪問了不該的訪問的索引");
}
System.out.println("over");
}
// 一個(gè)異常
public static void method1() {
// 第一階段
int a = 10;
// int b = 2;
int b = 0;
try {
System.out.println(a / b);
} catch (ArithmeticException ae) {
System.out.println("除數(shù)不能為0");
}
// 第二階段
System.out.println("over");
}
}
JDK7出現(xiàn)了一個(gè)新的異常處理方案
try{
...
}catch(異常名1 | 異常名2 | ... 變量 ) {
...
}
注意:這個(gè)方法雖然簡潔,但是也不夠好
處理方式是一致的(實(shí)際開發(fā)中呐萨,好多時(shí)候可能就是針對同類型的問題杀饵,給出同一個(gè)處理)
多個(gè)異常間必須是平級(jí)關(guān)系
編譯時(shí)異常和運(yùn)行時(shí)異常的區(qū)別
-編譯期異常:Java程序必須顯示處理谬擦,否則程序就會(huì)發(fā)生錯(cuò)誤切距,無法通過編譯
-運(yùn)行期異常:無需顯示處理惨远,也可以和編譯時(shí)異常一樣處理
異常中要了解的幾個(gè)方法
public String getMessage():異常的消息字符串
public String toString():返回異常的簡單信息描述
此對象的類的 name(全路徑名)
": "(冒號(hào)和一個(gè)空格)
調(diào)用此對象 getLocalizedMessage()方法的結(jié)果 (默認(rèn)返回的是getMessage()的內(nèi)容)
printStackTrace() 獲取異常類名和異常信息谜悟,以及異常出現(xiàn)在程序中的位置,返回值void,把信息輸出在控制臺(tái)
public class ExceptionDemo {
public static void main(String[] args) {
String s = "2014-11-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date d = sdf.parse(s); // 創(chuàng)建了一個(gè)ParseException對象话肖,然后拋出去,和catch里面進(jìn)行匹配
System.out.println(d);
} catch (ParseException e) { // ParseException e = new ParseException();
// ParseException
// e.printStackTrace();
// getMessage()
// System.out.println(e.getMessage());
// Unparseable date: "2014-11-20"
// toString()
// System.out.println(e.toString());
// java.text.ParseException: Unparseable date: "2014-11-20"
e.printStackTrace();
}
System.out.println("over");
}
}
拋出
格式
throws 異常類名
注意:這個(gè)格式必須跟在方法的括號(hào)后面葡幸,盡量不要在main方法上拋出異常
編譯期異常拋出最筒,將來調(diào)用者必須處理
運(yùn)行期異常拋出,將來調(diào)用可以不用處理
public class ExceptionDemo {
public static void main(String[] args) {
System.out.println("今天天氣很好");
try {
method();
} catch (ParseException e) {
e.printStackTrace();
}
System.out.println("但是就是不該有霧霾");
method2();
}
// 運(yùn)行期異常的拋出
public static void method2() throws ArithmeticException {
int a = 10;
int b = 0;
System.out.println(a / b);
}
// 編譯期異常的拋出
// 在方法聲明上拋出蔚叨,是為了告訴調(diào)用者床蜘,你注意了,我有問題蔑水。
public static void method() throws ParseException {
String s = "2014-11-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(s);
System.out.println(d);
}
}
throw
在功能方法內(nèi)部出現(xiàn)某種情況邢锯,程序不能繼續(xù)運(yùn)行,需要進(jìn)行跳轉(zhuǎn)時(shí)肤粱,就用throw把異常對象拋出
throws和throw的區(qū)別
throws
用在方法聲明后面弹囚,跟的是異常類名
可以跟多個(gè)異常類名,用逗號(hào)隔開
表示拋出異常领曼,由該方法的調(diào)用者來處理
throws表示出現(xiàn)異常的一種可能性鸥鹉,并不一定會(huì)發(fā)生這些異常
throw
用在方法體內(nèi),跟的是異常對象名
只能拋出一個(gè)異常對象名
表示拋出異常庶骄,由方法體內(nèi)的語句處理
throw則是拋出了異常毁渗,執(zhí)行throw則一定拋出了某種異常
如何選擇
原則:如果該功能內(nèi)部可以將問題處理,用try,如果處理不了,交由調(diào)用者處理,這是用throws
區(qū)別:
后續(xù)程序需要繼續(xù)運(yùn)行就try
后續(xù)程序不需要繼續(xù)運(yùn)行就throws
public class ExceptionDemo {
public static void main(String[] args) {
// method();
try {
method2();
} catch (Exception e) {
e.printStackTrace();
}
}
public static void method() {
int a = 10;
int b = 0;
if (b == 0) {
throw new ArithmeticException();
} else {
System.out.println(a / b);
}
}
public static void method2() throws Exception {
int a = 10;
int b = 0;
if (b == 0) {
throw new Exception();
} else {
System.out.println(a / b);
}
}
}
finally
被finally控制的語句體一定會(huì)執(zhí)行
注意:如果在執(zhí)行到finally之前jvm退出了(比如System.exit(0))就不能執(zhí)行了
格式
try...catch...finally...
用于釋放資源,在IO流操作和數(shù)據(jù)庫操作中會(huì)見到
public class FinallyDemo {
public static void main(String[] args) {
String s = "2014-11-20";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = null;
try {
// System.out.println(10 / 0);
d = sdf.parse(s);
} catch (ParseException e) {
e.printStackTrace();
//System.exit(0);加了這個(gè)finally就不能執(zhí)行了
} finally {
System.out.println("這里的代碼是可以執(zhí)行的");
}
System.out.println(d);
}
}
面試題
final,finally和finalize的區(qū)別
final:最終的意思单刁,可以修飾類灸异,成員變量,成員方法
修飾類羔飞,類不能被繼承
修飾變量肺樟,變量是常量
修飾方法,方法不能被重寫
finally:是異常處理的一部分逻淌,用于釋放資源
一般來說么伯,代碼肯定會(huì)執(zhí)行益兄,特殊情況:在執(zhí)行到finally之前jvm退出了
finalize:是Object類的一個(gè)方法卡辰,用于垃圾回收
如果catch里面有return語句,請問finally里面的代碼還會(huì)執(zhí)行嗎,如果會(huì)耀石,請問是在return前骨望,還是return后
會(huì),前,準(zhǔn)確的說硬爆,應(yīng)該是在中間
try...catch...finally的格式變形
try...catch...finally
try...catch
try...catch...catch...
try...catch...catch...finally
try...finally,這種做法的目前是為了釋放資源
自定義異常
要想你的類是一個(gè)異常類,就必須繼承自Exception或者RuntimeException
兩種方式:
繼承Exception
繼承RuntimeException
//異常類
public class MyException extends Exception {
public MyException() {
}
public MyException(String message) {
super(message);//用于給出消息提示
}
}
public class Teacher {
public void check(int score) throws MyException {
if (score > 100 || score < 0) {
throw new MyException("分?jǐn)?shù)必須在0-100之間");
} else {
System.out.println("分?jǐn)?shù)沒有問題");
}
}
/*
* 自定義異常測試類
*/
public class StudentDemo {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
System.out.println("請輸入學(xué)生成績:");
int score = sc.nextInt();
Teacher t = new Teacher();
try {
t.check(score);
} catch (MyException e) {
e.printStackTrace();
}
}
}
異常注意事項(xiàng)
子類重寫父類方法時(shí)擎鸠,子類的方法必須拋出相同的異匙嚎模或父類異常的子類
如果父類拋出了多個(gè)異常,子類重寫父類時(shí),只能拋出相同的異常或者是他的子集,子類不能拋出父類沒有的異常
如果被重寫的方法沒有異常拋出,那么子類的方法絕對不可以拋出異常,如果子類方法內(nèi)有異常發(fā)生,那么子類只能try,不能throws
File類
我們要想實(shí)現(xiàn)IO的操作,就必須知道硬盤上文件的表現(xiàn)形式虐骑,而Java就提供了一個(gè)類File供我們使用
File:文件和目錄(文件夾)路徑名的抽象表示形式
構(gòu)造方法:
File(String pathname):根據(jù)一個(gè)路徑得到File對象
File(String parent, String child):根據(jù)一個(gè)目錄和一個(gè)子文件/目錄得到File對象
File(File parent, String child):根據(jù)一個(gè)父File對象和一個(gè)子文件/目錄得到File對象
public class FileDemo {
public static void main(String[] args) {
// File(String pathname):根據(jù)一個(gè)路徑得到File對象
// 把e:\\demo\\a.txt封裝成一個(gè)File對象
File file = new File("E:\\demo\\a.txt");
// File(String parent, String child):根據(jù)一個(gè)目錄和一個(gè)子文件/目錄得到File對象
File file2 = new File("E:\\demo", "a.txt");
// File(File parent, String child):根據(jù)一個(gè)父File對象和一個(gè)子文件/目錄得到File對象
File file3 = new File("e:\\demo");
File file4 = new File(file3, "a.txt");
// 以上三種方式其實(shí)效果一樣
}
}
File類的創(chuàng)建功能
public boolean createNewFile():創(chuàng)建文件返回true 如果存在這樣的文件准验,就不創(chuàng)建了返回false
public boolean mkdir():創(chuàng)建文件夾返回true 如果存在這樣的文件夾,就不創(chuàng)建了返回false
public boolean mkdirs():創(chuàng)建文件夾,如果父文件夾不存在廷没,會(huì)幫你創(chuàng)建出來糊饱,返回true ,如果存在這樣的文件夾颠黎,就不創(chuàng)建了返回false
注意:確定好要?jiǎng)?chuàng)建文件還是文件夾另锋,mkdirs雖然方便,但是只能創(chuàng)建文件夾狭归,例File file = new File("e:\aaa\a.txt"); System.out.println("mkdirs:" + file.mkdirs());會(huì)創(chuàng)建e盤的aaa文件夾以及aaa文件夾下的a.txt文件夾夭坪,只有createNewFile()是創(chuàng)建文件的
如果創(chuàng)建文件或者文件夾時(shí)沒有加盤符,不會(huì)報(bào)錯(cuò)过椎,默認(rèn)在當(dāng)前項(xiàng)目路徑下
public class FileDemo {
public static void main(String[] args) throws IOException {
// 需求:我要在e盤目錄下創(chuàng)建一個(gè)文件夾demo
File file = new File("e:\\demo");
System.out.println("mkdir:" + file.mkdir());
// 需求:我要在e盤目錄demo下創(chuàng)建一個(gè)文件a.txt
File file2 = new File("e:\\demo\\a.txt");
System.out.println("createNewFile:" + file2.createNewFile());
// 需求:我要在e盤目錄test下創(chuàng)建一個(gè)文件b.txt
// Exception in thread "main" java.io.IOException: 系統(tǒng)找不到指定的路徑室梅。
// 注意:要想在某個(gè)目錄下創(chuàng)建內(nèi)容,該目錄首先必須存在疚宇。
// File file3 = new File("e:\\test\\b.txt");
// System.out.println("createNewFile:" + file3.createNewFile());
// 需求:我要在e盤目錄test下創(chuàng)建aaa目錄
// File file4 = new File("e:\\test\\aaa");
// System.out.println("mkdir:" + file4.mkdir());
// File file5 = new File("e:\\test");
// File file6 = new File("e:\\test\\aaa");
// System.out.println("mkdir:" + file5.mkdir());
// System.out.println("mkdir:" + file6.mkdir());
// 其實(shí)我們有更簡單的方法
File file7 = new File("e:\\aaa\\bbb\\ccc\\ddd");
System.out.println("mkdirs:" + file7.mkdirs());
// 看下面的這個(gè)東西:
File file8 = new File("e:\\aaa\\a.txt");
System.out.println("mkdirs:" + file8.mkdirs());
}
}
File類的刪除功能
public boolean delete(),刪除文件或文件夾亡鼠,逐級(jí)刪除
注意:
如果你創(chuàng)建文件或者文件夾忘了寫盤符路徑,那么敷待,默認(rèn)在項(xiàng)目路徑下
Java中的刪除不走回收站
要?jiǎng)h除一個(gè)文件夾间涵,請注意該文件夾內(nèi)不能包含文件或者文件夾
public class FileDemo {
public static void main(String[] args) throws IOException {
// 創(chuàng)建文件
// File file = new File("e:\\a.txt");
// System.out.println("createNewFile:" + file.createNewFile());
// 我不小心寫成這個(gè)樣子了
File file = new File("a.txt");
System.out.println("createNewFile:" + file.createNewFile());
// 繼續(xù)玩幾個(gè)
File file2 = new File("aaa\\bbb\\ccc");
System.out.println("mkdirs:" + file2.mkdirs());
// 刪除功能:我要?jiǎng)h除a.txt這個(gè)文件
File file3 = new File("a.txt");
System.out.println("delete:" + file3.delete());
// 刪除功能:我要?jiǎng)h除ccc這個(gè)文件夾
File file4 = new File("aaa\\bbb\\ccc");
System.out.println("delete:" + file4.delete());
// 刪除功能:我要?jiǎng)h除aaa文件夾
// File file5 = new File("aaa");
// System.out.println("delete:" + file5.delete());
File file6 = new File("aaa\\bbb");
File file7 = new File("aaa");
System.out.println("delete:" + file6.delete());
System.out.println("delete:" + file7.delete());
}
}
File類的重命名功能
public boolean renameTo(File dest)
如果路徑名相同,就是改名
如果路徑名不同榜揖,就是改名并剪切
路徑以盤符開始:絕對路徑 c:\a.txt
路徑不以盤符開始:相對路徑 a.txt
public class FileDemo {
public static void main(String[] args) {
// 創(chuàng)建一個(gè)文件對象
// File file = new File("張三.jpg");
// // 需求:我要修改這個(gè)文件的名稱為"李四.jpg"
// File newFile = new File("東方不敗.jpg");
// System.out.println("renameTo:" + file.renameTo(newFile));
File file2 = new File("李四.jpg");
File newFile2 = new File("e:\\張三.jpg");
System.out.println("renameTo:" + file2.renameTo(newFile2));
}
}
File判斷功能
public boolean isDirectory():判斷是否是目錄
public boolean isFile():判斷是否是文件
public boolean exists():判斷是否存在
public boolean canRead():判斷是否可讀
public boolean canWrite():判斷是否可寫
public boolean isHidden():判斷是否隱藏
public class FileDemo {
public static void main(String[] args) {
// 創(chuàng)建文件對象
File file = new File("a.txt");
System.out.println("isDirectory:" + file.isDirectory());// false
System.out.println("isFile:" + file.isFile());// true
System.out.println("exists:" + file.exists());// true
System.out.println("canRead:" + file.canRead());// true
System.out.println("canWrite:" + file.canWrite());// true
System.out.println("isHidden:" + file.isHidden());// false
}
}
File類獲取功能
public String getAbsolutePath():獲取絕對路徑
public String getPath():獲取相對路徑
public String getName():獲取名稱
public long length():獲取長度,字節(jié)數(shù)
public long lastModified():獲取最后一次的修改時(shí)間勾哩,毫秒值
public String[] list():獲取指定目錄下的所有文件或者文件夾的名稱數(shù)組
public File[] listFiles():獲取指定目錄下的所有文件或者文件夾的File數(shù)組,返回的是File對象,可以調(diào)用File類的其他方法
public class FileDemo {
public static void main(String[] args) {
// 創(chuàng)建文件對象
File file = new File("demo\\test.txt");
System.out.println("getAbsolutePath:" + file.getAbsolutePath());
System.out.println("getPath:" + file.getPath());
System.out.println("getName:" + file.getName());
System.out.println("length:" + file.length());
System.out.println("lastModified:" + file.lastModified());
// 1416471971031,將毫秒數(shù)轉(zhuǎn)換為時(shí)間
Date d = new Date(1416471971031L);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String s = sdf.format(d);
System.out.println(s);
}
}
public class FileDemo {
public static void main(String[] args) {
// 指定一個(gè)目錄
File file = new File("e:\\");
// public String[] list():獲取指定目錄下的所有文件或者文件夾的名稱數(shù)組
String[] strArray = file.list();
for (String s : strArray) {
System.out.println(s);
}
System.out.println("------------");
// public File[] listFiles():獲取指定目錄下的所有文件或者文件夾的File數(shù)組
File[] fileArray = file.listFiles();
for (File f : fileArray) {
System.out.println(f.getName());
}
}
}
判斷E盤目錄下是否有后綴名為.jpg的文件举哟,如果有思劳,就輸出此文件名稱
* 分析:
* A:封裝e判斷目錄
* B:獲取該目錄下所有文件或者文件夾的File數(shù)組
* C:遍歷該File數(shù)組,得到每一個(gè)File對象妨猩,然后判斷
* D:是否是文件
* 是:繼續(xù)判斷是否以.jpg結(jié)尾
* 是:就輸出該文件名稱
* 否:不管
* 否:不管
*/
public class FileDemo {
public static void main(String[] args) {
// 封裝e判斷目錄
File file = new File("e:\\");
// 獲取該目錄下所有文件或者文件夾的File數(shù)組
File[] fileArray = file.listFiles();
// 遍歷該File數(shù)組潜叛,得到每一個(gè)File對象,然后判斷
for (File f : fileArray) {
// 是否是文件
if (f.isFile()) {
// 繼續(xù)判斷是否以.jpg結(jié)尾
if (f.getName().endsWith(".jpg")) {
// 就輸出該文件名稱
System.out.println(f.getName());
}
}
}
}
}
文件名稱過濾器
public String[] list(FilenameFilter filter)
public File[] listFiles(FilenameFilter filter)
/*
* 判斷E盤目錄下是否有后綴名為.jpg的文件册赛,如果有钠导,就輸出此文件名稱
* 先獲取所有的震嫉,然后遍歷的時(shí)候森瘪,依次判斷,如果滿足條件就輸出(上面 FileDemo做的)
* 獲取的時(shí)候就已經(jīng)是滿足條件的了票堵,然后輸出即可
*
* 要想實(shí)現(xiàn)這個(gè)效果扼睬,就必須學(xué)習(xí)一個(gè)接口:文件名稱過濾器
* public String[] list(FilenameFilter filter)
* public File[] listFiles(FilenameFilter filter)
*/
public class FileDemo2 {
public static void main(String[] args) {
// 封裝e判斷目錄
File file = new File("e:\\");
// 獲取該目錄下所有文件或者文件夾的String數(shù)組
// public String[] list(FilenameFilter filter)
String[] strArray = file.list(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
// return false;不輸出
// return true;全部輸出
// 通過這個(gè)測試,我們就知道了,到底把這個(gè)文件或者文件夾的名稱加不加到數(shù)組中窗宇,取決于這里的返回值是true還是false
// 所以措伐,這個(gè)的true或者false應(yīng)該是我們通過某種判斷得到的
// System.out.println(dir + "---" + name);
// File file = new File(dir, name);
// // System.out.println(file);
// boolean flag = file.isFile();判斷你是否是文件,如果是就輸出
// boolean flag2 = name.endsWith(".jpg");//判斷是不是以jpg結(jié)尾
// return flag && flag2;
return new File(dir, name).isFile() && name.endsWith(".jpg");
}
});
// 遍歷
for (String s : strArray) {
System.out.println(s);
}
}
}
/*
* 需求:把E:\評(píng)書\三國演義下面的視頻名稱修改為
* 00?_介紹.avi
*
* 思路:
* A:封裝目錄
* B:獲取該目錄下所有的文件的File數(shù)組
* C:遍歷該File數(shù)組军俊,得到每一個(gè)File對象
* D:拼接一個(gè)新的名稱侥加,然后重命名即可。
*/
public class FileDemo {
public static void main(String[] args) {
// 封裝目錄
File srcFolder = new File("E:\\評(píng)書\\三國演義");
// 獲取該目錄下所有的文件的File數(shù)組
File[] fileArray = srcFolder.listFiles();
// 遍歷該File數(shù)組粪躬,得到每一個(gè)File對象
for (File file : fileArray) {
// System.out.println(file);
// E:\評(píng)書\三國演義\三國演義_001_[評(píng)書網(wǎng)-今天很高興,明天就IO了]_桃園三結(jié)義.avi
// 改后:E:\評(píng)書\三國演義\001_桃園三結(jié)義.avi
String name = file.getName(); // 三國演義_001_[評(píng)書網(wǎng)-今天很高興,明天就IO了]_桃園三結(jié)義.avi
int index = name.indexOf("_");
String numberString = name.substring(index + 1, index + 4);
// System.out.println(numberString);
// int startIndex = name.lastIndexOf('_');
// int endIndex = name.lastIndexOf('.');
// String nameString = name.substring(startIndex + 1, endIndex);
// System.out.println(nameString);
int endIndex = name.lastIndexOf('_');
String nameString = name.substring(endIndex);
String newName = numberString.concat(nameString); // 001_桃園三結(jié)義.avi
// System.out.println(newName);
File newFile = new File(srcFolder, newName); // E:\\評(píng)書\\三國演義\\001_桃園三結(jié)義.avi
// 重命名即可
file.renameTo(newFile);
}
}
}
Day20
遞歸
方法定義中調(diào)用方法本身的現(xiàn)象
注意事項(xiàng):
遞歸一定要有出口担败,否則就是死遞歸
遞歸的次數(shù)不能太多,否則就內(nèi)存溢出
構(gòu)造方法不能遞歸使用
使用遞歸的條件
-做遞歸要寫一個(gè)方法
返回值類型,參數(shù)列表
-出口條件
-規(guī)律
用遞歸實(shí)現(xiàn)5的階乘
/*
* 做遞歸要寫一個(gè)方法:
* 返回值類型:int
* 參數(shù)列表:int n
* 出口條件:
* if(n == 1) {return 1;}
* 規(guī)律:
* if(n != 1) {return n*方法名(n-1);}
*/
public static int jieCheng(int n){
if(n==1){
return 1;
}else {
return n*jieCheng(n-1);
}
}
}
有一對兔子镰官,從出生后第3個(gè)月起每個(gè)月都生一對兔子提前,小兔子長到第三個(gè)月后每個(gè)月又生一對兔子,假如兔子都不死泳唠,問第十二個(gè)月的兔子對數(shù)為多少
/* 分析:我們要想辦法找規(guī)律
* 兔子對數(shù)
* 第一個(gè)月: 1
* 第二個(gè)月: 1
* 第三個(gè)月: 2
* 第四個(gè)月: 3
* 第五個(gè)月: 5
* 第六個(gè)月: 8
* ...
*
* 由此可見兔子對象的數(shù)據(jù)是:
* 1,1,2,3,5,8...
* 規(guī)則:
* 從第三項(xiàng)開始狈网,每一項(xiàng)是前兩項(xiàng)之和
* 而且說明前兩項(xiàng)是已知的
* 可以用,數(shù)組實(shí)現(xiàn),遞歸實(shí)現(xiàn)
*/
public static void main(String[] args) {
// 定義一個(gè)數(shù)組
int[] arr = new int[20];
arr[0] = 1;
arr[1] = 1;
// arr[2] = arr[0] + arr[1];
// arr[3] = arr[1] + arr[2];
// ...
for (int x = 2; x < arr.length; x++) {
arr[x] = arr[x - 2] + arr[x - 1];
}
System.out.println(arr[19]);
/*
* 方法: 返回值類型:int 參數(shù)列表:int n 出口條件: 第一個(gè)月是1,第二個(gè)月是1 規(guī)律: 從第三個(gè)月開始笨腥,每一個(gè)月是前兩個(gè)月之和
*/
public static int fib(int n) {
if (n == 1 || n == 2) {
return 1;
} else {
return fib(n - 1) + fib(n - 2);
}
}
輸出固定位置下的所有java文件
/*需求:請大家把E:\JavaSE目錄下所有的java結(jié)尾的文件的絕對路徑給輸出在控制臺(tái)
*
* 分析:
* 封裝目錄
* 獲取該目錄下所有的文件或者文件夾的File數(shù)組
* 遍歷該File數(shù)組拓哺,得到每一個(gè)File對象
* 判斷該File對象是否是文件夾
* 是:回到第二步
* 否:繼續(xù)判斷是否以.java結(jié)尾
* 是:就輸出該文件的絕對路徑
* 否:不搭理它
*/
public class FilePathDemo {
public static void main(String[] args) {
// 封裝目錄
File srcFolder = new File("E:\\JavaSE");
// 遞歸功能實(shí)現(xiàn)
getAllJavaFilePaths(srcFolder);
}
private static void getAllJavaFilePaths(File srcFolder) {
// 獲取該目錄下所有的文件或者文件夾的File數(shù)組
File[] fileArray = srcFolder.listFiles();
// 遍歷該File數(shù)組,得到每一個(gè)File對象
for (File file : fileArray) {
// 判斷該File對象是否是文件夾
if (file.isDirectory()) {
getAllJavaFilePaths(file);
} else {
// 繼續(xù)判斷是否以.java結(jié)尾
if (file.getName().endsWith(".java")) {
// 就輸出該文件的絕對路徑
System.out.println(file.getAbsolutePath());
}
}
}
}
}
刪除指定目錄的所有文件
/*
* 需求:遞歸刪除帶內(nèi)容的目錄
*
* 目錄我已經(jīng)給定:demo
*
* 分析:
* 封裝目錄
* 獲取該目錄下的所有文件或者文件夾的File數(shù)組
* 遍歷該File數(shù)組扇雕,得到每一個(gè)File對象
* 判斷該File對象是否是文件夾
* 是:回到第二步
* 否:就刪除
*/
public class FileDeleteDemo {
public static void main(String[] args) {
// 封裝目錄
File srcFolder = new File("demo");
// 遞歸實(shí)現(xiàn)
deleteFolder(srcFolder);
}
private static void deleteFolder(File srcFolder) {
// 獲取該目錄下的所有文件或者文件夾的File數(shù)組
File[] fileArray = srcFolder.listFiles();
if (fileArray != null) {
// 遍歷該File數(shù)組拓售,得到每一個(gè)File對象
for (File file : fileArray) {
// 判斷該File對象是否是文件夾
if (file.isDirectory()) {
deleteFolder(file);
} else {
System.out.println(file.getName() + "---" + file.delete());
}
}
//刪除文件夾
System.out.println(srcFolder.getName() + "---" + srcFolder.delete());
}
}
}
IO流
用來上傳和下載文件
IO流的分類:
流向:
輸入流 讀取數(shù)據(jù)
輸出流 寫出數(shù)據(jù)
數(shù)據(jù)類型:
字節(jié)流
字節(jié)輸入流 讀取數(shù)據(jù) InputStream
字節(jié)輸出流 寫出數(shù)據(jù) OutputStream
字符流
字符輸入流 讀取數(shù)據(jù) Reader
字符輸出流 寫出數(shù)據(jù) Writer
注意:一般我們在探討IO流的時(shí)候,如果沒有明確說明按哪種分類來說镶奉,默認(rèn)情況下是按照數(shù)據(jù)類型來分的础淤。
OutputStream的子類
FileOutputStream
構(gòu)造方法
FileOutputStream(File file)
FileOutputStream(String name)
FileOutputStream(String name,boolean append)創(chuàng)建一個(gè)向具有指定 name 的文件中寫入數(shù)據(jù)的輸出文件流。如果第二個(gè)參數(shù)為 true哨苛,則將字節(jié)寫入文件末尾處鸽凶,而不是寫入文件開始處
成員方法
public void write(int b):寫一個(gè)字節(jié)
public void write(byte[] b):寫一個(gè)字節(jié)數(shù)組
public void write(byte[] b,int off,int len):寫一個(gè)字節(jié)數(shù)組的一部分,從off開始,寫len個(gè)
字節(jié)輸出流操作步驟:
創(chuàng)建字節(jié)輸出流對象
寫數(shù)據(jù)
釋放資源
創(chuàng)建字節(jié)輸出流對象
兩種方式(效果相同)
FileOutputStream(File file)構(gòu)造方法
File file = new File("fos.txt");
FileOutputStream fos = new FileOutputStream(file);
FileOutputStream(String name)構(gòu)造方法
FileOutputStream fos = new FileOutputStream("fos.txt");
創(chuàng)建字節(jié)輸出流對象做了那幾件事
-調(diào)用系統(tǒng)功能去創(chuàng)建文件
〗ㄇ汀-創(chuàng)建fos對象
〔=摹-把fos對象指向這個(gè)文件
釋放資源close()
關(guān)閉此文件輸出流并釋放與此流有關(guān)的所有系統(tǒng)資源
為什么一定要close()呢
讓流對象變成垃圾,這樣就可以被垃圾回收器回收了
通知系統(tǒng)去釋放跟該文件相關(guān)的資源
public class FileOutputStreamDemo {
public static void main(String[] args) throws IOException {
// 創(chuàng)建字節(jié)輸出流對象
// File file = new File("fos.txt");
// FileOutputStream fos = new FileOutputStream(file);
FileOutputStream fos = new FileOutputStream("fos.txt");
// 調(diào)用write()方法
//fos.write(97); //97 -- 底層二進(jìn)制數(shù)據(jù) -- 通過記事本打開 -- 找97對應(yīng)的字符值 -- a
//public void write(byte[] b):寫一個(gè)字節(jié)數(shù)組
byte[] bys={97,98,99,100,101};
fos.write(bys);
//public void write(byte[] b,int off,int len):寫一個(gè)字節(jié)數(shù)組的一部分
fos.write(bys,1,3);
//釋放資源
fos.close();
}
}
如何實(shí)現(xiàn)數(shù)據(jù)的換行
寫入換行符號(hào)即可
不同的系統(tǒng)對換行符號(hào)識(shí)別是不一樣
windows:\r\n
linux:\n
Mac:\r
而一些常見的個(gè)高級(jí)記事本亿蒸,是可以識(shí)別任意換行符號(hào)的
public class FileOutputStreamDemo3 {
public static void main(String[] args) throws IOException {
// 創(chuàng)建字節(jié)輸出流對象
// FileOutputStream fos = new FileOutputStream("fos.txt");
// 創(chuàng)建一個(gè)向具有指定 name 的文件中寫入數(shù)據(jù)的輸出文件流,如果第二個(gè)參數(shù)為 true凑兰,則將字節(jié)寫入文件末尾處,而不是寫入文件開始處
//文件追加
FileOutputStream fos = new FileOutputStream("fos.txt", true);
// 寫數(shù)據(jù)
for (int x = 0; x < 10; x++) {
fos.write(("hello" + x).getBytes());
//換行
fos.write("\r\n".getBytes());
}
// 釋放資源
fos.close();
}
}
/*
* 加入異常處理的字節(jié)輸出流操作
*/
public class FileOutputStreamDemo4 {
public static void main(String[] args) {
// 為了在finally里面能夠看到該對象就必須定義到外面边锁,為了訪問不出問題姑食,還必須給初始化值
FileOutputStream fos = null;
try {
// fos = new FileOutputStream("z:\\fos4.txt");
fos = new FileOutputStream("fos4.txt");
fos.write("java".getBytes());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
// 如果fos不是null,才需要close()
if (fos != null) {
// 為了保證close()一定會(huì)執(zhí)行茅坛,就放到這里了
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
InputStream的子類
FileInputStream
字節(jié)輸入流操作步驟:
創(chuàng)建字節(jié)輸入流對象
調(diào)用read()方法讀取數(shù)據(jù)音半,并把數(shù)據(jù)顯示在控制臺(tái)
釋放資源
讀取數(shù)據(jù)的方式:
int read():一次讀取一個(gè)字節(jié)
int read(byte[] b):一次讀取一個(gè)字節(jié)數(shù)組
public class FileInputStreamDemo {
public static void main(String[] args) throws IOException {
// FileInputStream(String name)
// FileInputStream fis = new FileInputStream("fis.txt");
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");
// // 調(diào)用read()方法讀取數(shù)據(jù),并把數(shù)據(jù)顯示在控制臺(tái)
// // 第一次讀取
// int by = fis.read();
// System.out.println(by);
// System.out.println((char) by);
//
// // 第二次讀取
// by = fis.read();
// System.out.println(by);
// System.out.println((char) by);
//
// // 第三次讀取
// by = fis.read();
// System.out.println(by);
// System.out.println((char) by);
// // 我們發(fā)現(xiàn)代碼的重復(fù)度很高,所以我們要用循環(huán)改進(jìn)
// // 而用循環(huán)曹鸠,最麻煩的事情是如何控制循環(huán)判斷條件呢?
// // 第四次讀取
// by = fis.read();
// System.out.println(by);
// // 第五次讀取
// by = fis.read();
// System.out.println(by);
// //通過測試煌茬,我們知道如果你讀取的數(shù)據(jù)是-1,就說明已經(jīng)讀取到文件的末尾了
// 用循環(huán)改進(jìn)
// int by = fis.read();
// while (by != -1) {
// System.out.print((char) by);
// by = fis.read();
// }
// 最終版代碼
int by = 0;
// 讀取彻桃,賦值坛善,判斷
while ((by = fis.read()) != -1) {
System.out.print((char) by);
}
// 釋放資源
fis.close();
}
}
復(fù)制文件的字符
/*
* 復(fù)制文本文件
*
* 數(shù)據(jù)源:從哪里來
* a.txt -- 讀取數(shù)據(jù) -- FileInputStream
*
* 目的地:到哪里去
* b.txt -- 寫數(shù)據(jù) -- FileOutputStream
*
* java.io.FileNotFoundException: a.txt (系統(tǒng)找不到指定的文件)
*
* 這一次復(fù)制中文沒有出現(xiàn)任何問題,為什么呢
* 上一次我們出現(xiàn)問題的原因在于我們每次獲取到一個(gè)字節(jié)數(shù)據(jù)邻眷,就把該字節(jié)數(shù)據(jù)轉(zhuǎn)換為了字符數(shù)據(jù)浑吟,然后輸出到控制臺(tái)
* 而這一次呢?確實(shí)通過IO流讀取數(shù)據(jù),寫到文本文件耗溜,你讀取一個(gè)字節(jié)组力,我就寫入一個(gè)字節(jié),你沒有做任何的轉(zhuǎn)換
* 它會(huì)自己做轉(zhuǎn)換
*/
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
// 封裝數(shù)據(jù)源
FileInputStream fis = new FileInputStream("a.txt");
// 封裝目的地
FileOutputStream fos = new FileOutputStream("b.txt");
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
// 釋放資源(先關(guān)誰都行)
fos.close();
fis.close();
}
}
計(jì)算機(jī)是如何識(shí)別什么時(shí)候該把兩個(gè)字節(jié)轉(zhuǎn)換為一個(gè)中文呢
在計(jì)算機(jī)中中文的存儲(chǔ)分兩個(gè)字節(jié):
第一個(gè)字節(jié)肯定是負(fù)數(shù)
第二個(gè)字節(jié)常見的是負(fù)數(shù)抖拴,可能有正數(shù)燎字。但是沒影響
把c盤下的a.txt的內(nèi)容復(fù)制到d盤下的b.txt中
圖片視頻都可
/*
* 需求:把c盤下的a.txt的內(nèi)容復(fù)制到d盤下的b.txt中
*
* 數(shù)據(jù)源:
* c:\\a.txt -- 讀取數(shù)據(jù)-- FileInputStream
* 目的地:
* d:\\b.txt -- 寫出數(shù)據(jù) -- FileOutputStream
*/
public class CopyFileDemo2 {
public static void main(String[] args) throws IOException {
// 封裝數(shù)據(jù)源
FileInputStream fis = new FileInputStream("c:\\a.txt");
// 封裝目的地
FileOutputStream fos = new FileOutputStream("d:\\b.txt");
// 復(fù)制數(shù)據(jù)
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
// 釋放資源
fos.close();
fis.close();
}
}
一次讀取一個(gè)字節(jié)數(shù)組
/*
* 一次讀取一個(gè)字節(jié)數(shù)組:int read(byte[] b)
* 返回值其實(shí)是實(shí)際讀取的字節(jié)個(gè)數(shù)
*/
public class FileInputStreamDemo2 {
public static void main(String[] args) throws IOException {
// 創(chuàng)建字節(jié)輸入流對象
// FileInputStream fis = new FileInputStream("fis2.txt");
FileInputStream fis = new FileInputStream("FileOutputStreamDemo.java");
// 讀取數(shù)據(jù)
// 定義一個(gè)字節(jié)數(shù)組
// 第一次讀取
// byte[] bys = new byte[5];
// int len = fis.read(bys);
// // System.out.println(len);
// // System.out.println(new String(bys));
// // System.out.println(new String(bys, 0, len));
// System.out.print(new String(bys, 0, len));
//
// // 第二次讀取
// len = fis.read(bys);
// // System.out.println(len);
// // System.out.println(new String(bys));
// // System.out.println(new String(bys, 0, len));
// System.out.print(new String(bys, 0, len));
//
// // 第三次讀取
// len = fis.read(bys);
// // System.out.println(len);
// // System.out.println(new String(bys));
// // System.out.println(new String(bys, 0, len));
// System.out.print(new String(bys, 0, len));
//
// // 第四次讀取
// len = fis.read(bys);
// // System.out.println(len);
// // System.out.println(new String(bys, 0, len));
// System.out.print(new String(bys, 0, len));
// // 代碼重復(fù)了,用循環(huán)改進(jìn)
// // 但是阿宅,我不知道結(jié)束條件
// // len = fis.read(bys);
// // System.out.println(len);
// // len = fis.read(bys);
// // System.out.println(len);
// // 如果讀取到的實(shí)際長度是-1候衍,就說明沒有數(shù)據(jù)了
// byte[] bys = new byte[115]; // 0
// int len = 0;
// while ((len = fis.read(bys)) != -1) {
// System.out.print(new String(bys, 0, len));
// // System.out.print(new String(bys)); //千萬要帶上len的使用
// }
// 最終版代碼
// 數(shù)組的長度一般是1024或者1024的整數(shù)倍
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}
// 釋放資源
fis.close();
}
}
需求:把c:\a.txt內(nèi)容復(fù)制到d:\b.txt中,改進(jìn)版
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
// 封裝數(shù)據(jù)源
FileInputStream fis = new FileInputStream("c:\\a.txt");
FileOutputStream fos = new FileOutputStream("d:\\b.txt");
// 復(fù)制數(shù)據(jù)
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
// 釋放資源
fos.close();
fis.close();
}
}
緩沖區(qū)類(高效類)
寫數(shù)據(jù):BufferedOutputStream
讀數(shù)據(jù):BufferedInputStream
BufferedOutputStream(OutputStream out)
BufferedInputStream(InputStream in)
為什么不傳遞一個(gè)具體的文件或者文件路徑,而是傳遞一個(gè)OutputStream對象呢?
原因很簡單洒放,字節(jié)緩沖區(qū)流僅僅提供緩沖區(qū)蛉鹿,為高效而設(shè)計(jì)的,但是呢,真正的讀寫操作還得靠基本的流對象實(shí)現(xiàn)
寫數(shù)據(jù)
public class BufferedOutputStreamDemo {
public static void main(String[] args) throws IOException {
// BufferedOutputStream(OutputStream out)
// FileOutputStream fos = new FileOutputStream("bos.txt");
// BufferedOutputStream bos = new BufferedOutputStream(fos);
// 簡單寫法
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("bos.txt"));
// 寫數(shù)據(jù)
bos.write("hello".getBytes());
// 釋放資源
bos.close();
}
}
讀取數(shù)據(jù)
public class BufferedInputStreamDemo {
public static void main(String[] args) throws IOException {
// BufferedInputStream(InputStream in)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
"bos.txt"));
// 讀取數(shù)據(jù)往湿,第一種方式
// int by = 0;
// while ((by = bis.read()) != -1) {
// System.out.print((char) by);
// }
// System.out.println("---------");
//第二種方式
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}
// 釋放資源
bis.close();
}
}
//注意:雖然我們有兩種方式可以讀取妖异,但是,請注意领追,這兩種方式針對同一個(gè)對象在一個(gè)代碼中只能使用一個(gè)
**四種方式比較**
基本字節(jié)流一次讀寫一個(gè)字節(jié)
基本字節(jié)流一次讀寫一個(gè)字節(jié)數(shù)組
高效字節(jié)流一次讀寫一個(gè)字節(jié)
高效字節(jié)流一次讀寫一個(gè)字節(jié)數(shù)組
/*
* 需求:把e:\\哥有老婆.mp4復(fù)制到當(dāng)前項(xiàng)目目錄下的copy.mp4中
*
* 字節(jié)流四種方式復(fù)制文件:
* 基本字節(jié)流一次讀寫一個(gè)字節(jié): 共耗時(shí):117235毫秒
* 基本字節(jié)流一次讀寫一個(gè)字節(jié)數(shù)組: 共耗時(shí):156毫秒
* 高效字節(jié)流一次讀寫一個(gè)字節(jié): 共耗時(shí):1141毫秒
* 高效字節(jié)流一次讀寫一個(gè)字節(jié)數(shù)組: 共耗時(shí):47毫秒
*/
public class CopyMp4Demo {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
// method1("e:\\哥有老婆.mp4", "copy1.mp4");
// method2("e:\\哥有老婆.mp4", "copy2.mp4");
// method3("e:\\哥有老婆.mp4", "copy3.mp4");
method4("e:\\哥有老婆.mp4", "copy4.mp4");
long end = System.currentTimeMillis();
System.out.println("共耗時(shí):" + (end - start) + "毫秒");
}
// 高效字節(jié)流一次讀寫一個(gè)字節(jié)數(shù)組:
public static void method4(String srcString, String destString)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
srcString));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destString));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
bis.close();
}
// 高效字節(jié)流一次讀寫一個(gè)字節(jié):
public static void method3(String srcString, String destString)
throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(
srcString));
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream(destString));
int by = 0;
while ((by = bis.read()) != -1) {
bos.write(by);
}
bos.close();
bis.close();
}
// 基本字節(jié)流一次讀寫一個(gè)字節(jié)數(shù)組
public static void method2(String srcString, String destString)
throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
fos.close();
fis.close();
}
// 基本字節(jié)流一次讀寫一個(gè)字節(jié)
public static void method1(String srcString, String destString)
throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
fos.close();
fis.close();
}
}