2022-03-17

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();
    }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末他膳,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子绒窑,更是在濱河造成了極大的恐慌棕孙,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,084評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件些膨,死亡現(xiàn)場離奇詭異蟀俊,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)订雾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,623評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門肢预,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人葬燎,你說我怎么就攤上這事误甚。” “怎么了谱净?”我有些...
    開封第一講書人閱讀 163,450評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵窑邦,是天一觀的道長。 經(jīng)常有香客問我壕探,道長冈钦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,322評(píng)論 1 293
  • 正文 為了忘掉前任李请,我火速辦了婚禮瞧筛,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘导盅。我一直安慰自己较幌,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,370評(píng)論 6 390
  • 文/花漫 我一把揭開白布白翻。 她就那樣靜靜地躺著乍炉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪滤馍。 梳的紋絲不亂的頭發(fā)上岛琼,一...
    開封第一講書人閱讀 51,274評(píng)論 1 300
  • 那天,我揣著相機(jī)與錄音巢株,去河邊找鬼槐瑞。 笑死,一個(gè)胖子當(dāng)著我的面吹牛阁苞,可吹牛的內(nèi)容都是我干的困檩。 我是一名探鬼主播,決...
    沈念sama閱讀 40,126評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼那槽,長吁一口氣:“原來是場噩夢啊……” “哼窗看!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起倦炒,我...
    開封第一講書人閱讀 38,980評(píng)論 0 275
  • 序言:老撾萬榮一對情侶失蹤显沈,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后逢唤,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拉讯,經(jīng)...
    沈念sama閱讀 45,414評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,599評(píng)論 3 334
  • 正文 我和宋清朗相戀三年鳖藕,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了魔慷。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,773評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡著恩,死狀恐怖院尔,靈堂內(nèi)的尸體忽然破棺而出蜻展,到底是詐尸還是另有隱情,我是刑警寧澤邀摆,帶...
    沈念sama閱讀 35,470評(píng)論 5 344
  • 正文 年R本政府宣布纵顾,位于F島的核電站,受9級(jí)特大地震影響栋盹,放射性物質(zhì)發(fā)生泄漏施逾。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,080評(píng)論 3 327
  • 文/蒙蒙 一例获、第九天 我趴在偏房一處隱蔽的房頂上張望汉额。 院中可真熱鬧,春花似錦榨汤、人聲如沸蠕搜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,713評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽讥脐。三九已至,卻和暖如春啼器,著一層夾襖步出監(jiān)牢的瞬間旬渠,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,852評(píng)論 1 269
  • 我被黑心中介騙來泰國打工端壳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留告丢,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,865評(píng)論 2 370
  • 正文 我出身青樓损谦,卻偏偏與公主長得像岖免,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子照捡,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,689評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • 鄭州網(wǎng)站建設(shè)小程序開發(fā) 企業(yè)網(wǎng)站建設(shè)颅湘,是相對來說簡單的一種建站類型,網(wǎng)站建設(shè)的周期也相對較短;雖然是比較簡單的建站...
    L是木子李呢閱讀 102評(píng)論 0 0
  • Nature | 免疫細(xì)胞改變癌細(xì)胞基因解碼方式 原創(chuàng)榴蓮不酥圖靈基因 收錄于話題#前沿分子生物學(xué)機(jī)制 撰文:榴蓮...
    圖靈基因閱讀 433評(píng)論 0 0
  • 論技工學(xué)校的專業(yè)設(shè)置與專業(yè)教育的實(shí)施 【摘要】: 專業(yè)設(shè)置對于技工學(xué)校的建設(shè)與發(fā)展具有重要作用栗精,專業(yè)教育的實(shí)施在技...
    3cde25271093閱讀 413評(píng)論 0 1
  • TRUTHONLY飾品——耳飾臉型搭配技巧 一闯参、如何判斷飾品的風(fēng)格? 1、飾品的直曲度 曲就是圓圈悲立,有弧度鹿寨、圓潤,...
    TRUTHONLY閱讀 360評(píng)論 0 1
  • 老師薪夕,抱抱我 【作者】2021809 +王亞男 【所屬學(xué)科】小學(xué)語文項(xiàng)目學(xué)科 【故事所屬類型】 教育情感類 ...
    94河北王亞男笑雅笑春風(fēng)閱讀 275評(píng)論 0 0