API笔记整理

API笔记整理

1、java.io.File

  • File可以表示硬盘删的一个文件或目录(实际表示的是一个抽象路径)

  • File可以:

    • 访问其表示的文件或目录的的属性信息(名字,大小,修改时间等)
    • 可以创建或者删除一个文件或目录
    • 可以访问一个目录中的子项内容
    • 注:File不能访问文件数据
  • 绝对路径与相对路径:

    • 绝对路径:清晰明了但是不利于跨平台
      • (“C:/User/TEDU/IdeaProjects/CGB2202/demo.txt”)
    • 相对路径:
      • (“./demo.txt”)
      • "./"表示当前目录,可省略
  • mkdir是linux中的一条命令,就是make directory的简写,意思就是创建目录

//访问表示的文件的属性信息
import java.io.File;
public class FileDemo{
    public static void main(String[] args){
        File file = new File("./demo.txt");
        String name = file.getName();//获取文件名
        long length = file.length();//获取文件在内存中实际占用大小(单位是字节)
        boolean cw = file.canWrite();//判断是否可写
        boolean cr = file.canread();//判断是否可读
        boolean ih = file.isHidden();//判断是否隐藏
        boolean ie = file.exists();//判断是否存在
        boolean isFile = file.isFile();//判断当前file是否为文件
        boolean isDirectory = file.isDirectory();//判断当前file是否为目录
    }
}
//创建或删除文件
import java.io.File;
public class Demo{
    public static void main(String[] args) throws IOException{
        File file = new File("./test.txt");
        /*
        创建文件的前提是该文件所在的目录必须存在,如果目录不存在则创建时会抛出异常
        java.io.IOException:系统找不到指定的路径。
        */
        if(file.exists()){
            System.out.println("文件存在");
        }else{
            file.createNewFile();//创建新文件
        }
        
        if(file.exists()){
            file.delete();//将file表示的文件删除
        }else{
            System.out.println("该文件不存在");
        }
    }
}
//创建或删除目录
import java.io.File;
public class Demo{
    public static void main(String[] args){
        File dir = new File("demo");
        if(dir.exists()){
            System.out.println("目录已存在");
        }else{
            //dir.mkdir(); //创建目录时要求梭子啊的目录必须存在,否在创建失败
            dir.mkdirs();//会一同将不存在的父目录全部创建出来(推荐使用)
        }
        if(dir.exists()){
            dir.delete();//删除目录
            //删除目录只能删除空目录,否则删除不成功
        }else{
            System.out.println("该目录不存在");
        }
    }
}
//访问目录下的子项
public class Demo{
    public static void main(String[] args){
        File dir = new File("./src/file");
        if(dir.isDirectory()){
            File[] subs = file.listFiles();
            //返回当前目录中所有子项,每个子项都包含在返回的数组中作为一个元素。
            for(int i=0; i<subs.length; i++){
                File sub = subs[i];
                System.out.println(sub);
            }
        }
    }
}
//利用过滤器筛选需要的内容
public class Demo{
    public static void main(String[] args){
        File dir = new File("./");
        if(dir.isDirectory()){
            //创建过滤器的匿名内部类
            FileFilter fileFilter = new FileFilter(){
                public void accept(File file){
                    return file.getName.contains("o");
                }
            };
            File[] subs = dir.listFiles(fileFilter);
            for(int i=0; i<subs.length; i++){
                File sub = subs[i];
                System.out.println(sub);
            }
        }
    }
}

2、lambda表达式:java8之后java推出的新特性

  • lambda可以使得程序员面向函数式变成
  • 直观感受,可以用更精简的语法创建匿名内部类
  • 但是lambda创建匿名内部类时要求所实现的接口中只能有一个抽象方法
语法:
(参数列表)->{
    方法体;
}
//利用lambda表达式创建过滤器
public class Demo{
    public static void main(String[] args){
        FIle dir = new File(".");
        if(dir.isDirectory()){
            /*
            FileFilter fileFilter = (File file)->{
             return file.getName().contains("o");   
            }
            */
            //再简化
            FileFilter fileFilter = file->file.getName().contains("o");
            File[] subs = dir.listFile(fileFilter);
            for(int i=0; i<subs.length; i++){
                System.out.println(subs[i]);
            }
        }
    }
}

3、JAVA IO java的输入与输出

  • java使用输入与输出的两个方向来规定读和写操作;其中输入是从外界到我们写的程序的方向是获取的过程,是【读取】操作,输出则是发送到外界的方法,是【写出】操作

  • java将IO比喻成"流",我们可以理解为是连接我们写的程序与外界设备之间的"管道",类似现实生活中的"水管",只不过这个管子里流的不是水,而是"字节"

  • java.io.InputStream和Outputasatream是所有字节输入流与输出流的超类,它们是抽象类,InputStream定义了读取字节的相关方法,OutputStream定义了写出字节的相关方法,实际开发中我们可以创建不同种类的输入与输出流来连接对应的设备进行读写操作

  • java将流分为两类:节点类与处理流

    • 节点流:又称为低级流,是实际连接我们的程序与另一端的"管道",负责实际读写数据的流
      • 注:读写一定是建立在低级流的基础之上的;
    • 处理流:又称为高级流,过滤流,不能独立存在,必须连接在其他流上,目的是当数据流经它时对数据进行某种加工处理,简化我们的相应操作。
    • 实际开发中,我们总是串联一组高级流到低级流上,完成一个复杂的数据读写操作,这个过程也称为流连接,这是IO的精髓
  • 所有流操作结束必须关闭流:调用close方法

  • java按照读写的数据单位划分为字节流与字符流

    • java.io.InputStream和OutputStream是所有字节输入和输出流的超类

    • java.io.Reader和Writer则是所有字符输入和输出流的超类

    • 注:这两对超类之间时平级的,互相没有继承关系

    • 字符流:Reader里定义了读取字符的相关方法,Writer里定义了写出字符的相关方法

  • 低级流

    • 文件流
      • java.io.FileInputStream和FileOutputStream,它们继承自InputStream和OutputStream是实际用于读写文件的流。
  • 高级流

    • 缓冲流:

      • java.io.BufferedInputStream和Bu纷纷热点Output Stream
      • 缓冲流在流连接中的作用是加快读写效率
      • 缓冲流的flush方法用于强制将缓冲区中已经缓存的数据一次性写出。
        • 注:该方法实际上是在字节输出流的超类OutputStream上定义的,并非只有缓冲输出流有这个方法,但是实际上只有缓冲输出流的该方法有实际意义,其他的流实现该方法的目的仅仅是为了在流连接的过程中传递flush动作给缓冲输出流
    • 对象流:

      • java.io.ObjectOutputStream和ObjectInputStream

      • 它们是一对高级流,在流连接中的作用是进行对象的序列化与反序列化

        • 对象序列化:将对象按照其结构转化为一组字节的过程
      • 对象输出流提供了序列化方法: void writeObject(Object obj);

        • 将给定的对象转化为一组字节并写出,但是需要注意的是:写出的对象所属的类必须实现接口:java.io.Serializable,否则该方法会抛出异常:java.io.NotSerializableExcption;

        • 实力序列化接口后最好主动定义序列化版本号这个常量,这样一来对象序列化就不会根据类的结构生成一个版本号,而是使用该股定制,那么反序列化时,只要还原的对象和当前类的版本号一直就可以进行还原。

        • public static final long serialVersionUID = 1L//long型版本号自定义
          
      • 当属性被关键字transient修饰后,那么但进行对象序列化时,该属性值会被忽略,忽略不必要的属性可以达到对象瘦身的目的,减少资源开销

      • 流连接

        • 对象----->对象流(序列化)–>文件流(持久化)–>文件
      • 反序列化:Object readObject();

    • 转换流:

      • java.io.InputStreamReader和OutputStreamWriter

      • 他们是常见的字符流实现类,同时是一对高级流。实际开发中我们不会直接使用他们,但是流连接中他们时重要的一环

      • 创建转换流时,可以指定字符集,保证在读写时不会发生乱码

        • StandardCharsets.UTF_8

        • 常用字符集:GBK 和UTF_8

    • 缓冲字符流:

      • java.io.BufferedReader和BufferedWriter
      • 缓冲字符流是一对高级的字符流;BufferedReader流可以块读文本数据加速,并且可以按行读取字符串;BufferedWriter流快写文本数据加速
    • java.io.PrintWriter具有自动行刷新的缓冲字符输出流

      • 内部总是连接BufferedWriter
      • println方法,按行写出
      • 参数这里可以指定是否进行行刷新
//文件输出流和文件输入流
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo{
    public static void main(String[] args) throws IOExcption{
        FileOutputStream fos = new FileOutputStream("./demo.txt");
        //文件输出流,如果当前目录下该文件不存在,则自动创建该文件
        //一个参数可以是抽象路径,也可以是一个File实例, 为覆盖模式
        //两个参数:第一个同上,第二个为append 追加模式,true表示开启追加模式
        fos.write(1);
        //写出一个字节,写出的内容是给定的int值对应的2进制的"低八位";
        fos.close();
        FileInputStream fis = new FileInputStream("./demo.txt");
        int d = fis.read();
        //读取文件中的一个字节,并将其放入int值对应的2进制的低八位,读取到末尾返回-1;
        fis.close();
    }
}
//块读写
import java.io.FileInpuStream;
import java.io.FileOutputStream;
import java.io.IOException;
public class Demo{
    public static void main(String[] args){
        FileInputStream fis = new FIleInputStream("demo.txt");
        FileOutputStream fos = new FileOutputStream("demo_cp.txt");
        byte[] data = new byte[1024*10];//指定块读的大小
        int len;
        while((len = fis.read(data)) != 1-){
            fos.write(data,len);
            //加入len参数,可以让写出是按照给定长度写出,防止出现多写的情况。
        }
        fis.close();
        fos.close();
    }
}

4、java的异常处理机制

  • Java中的所有异常的超类为Throwable,其下派生了两个子类:Error和Exception

    • Error表示系统错误,通常是不能再程序运行期间被解决的错误。
    • Exception表示程序级别的不哦呜,通常是由于逻辑等导致的问题,可以在程序运行期间被解决。
  • 异常处理机制中的try-catch

  • 语法:
    try{
        可能出现异常的代码片段
    }catch(xxxxException e){
        try语句块中出现xxxxException后的解决办法
    }
    
  • 异常处理机制 中的finally块

    • finally块是异常处理机制的最后一块,它可以跟在try之后或者最后一个catch之后

    • finally可以保证只要程序执行到try语句块中,无论try中是否出现异常,finally最终都会必定执行

    • 通常我们将释放资源这类操作放在finally中确保运行,例如IO操作后最终的close方法调用。

    • import java.io.*;
      public class Demo{
          public static void main(String[] args){
              FileOutpuptStream fos = null;
              try{
                  fos = new FileOutputStream("fos.dat");
                  fos.write(1);
              }catch(IOException e){
                  e.printStackTrace();//输出错误信息有助于我们debug
                  String message = e.getMessage();//获取错误消息,一般用于体是给用户或者记录日志的时候使用
              }finally{
                  try{
                      if(fos != null){//避免空指针异常
                          fos.close();
                      }
                  }catch(IOException e){
                      e.printStackTrace();
                  }
              }
          }
      }
      
  • 自定义异常:

  • 通常用于那些满足语法但是不满足业务场景时的错误。

  • 自定义异常要做如下操作:

    • 类名要做到见名知意

    • 要继承自Throwable(直接或间接继承都可以)

    • 提供超累异常支持的所有构造器

    • //年龄不合法
      public class IllegalAgeException extends Exception{
          public IllegalAgeException(){}
              public IllegalAgeException(String message) {
              super(message);
          }
      
          public IllegalAgeException(String message, Throwable cause) {
              super(message, cause);
          }
      
          public IllegalAgeException(Throwable cause) {
              super(cause);
          }
      
          public IllegalAgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
              super(message, cause, enableSuppression, writableStackTrace);
          }
      }
      
  • 异常的抛出

    • throw关键字可以主动对外抛出一个异常

      • 通常:
        • 程序出现了异常,但是该异常不应当在当前代码块中被解决时,可以主动将其抛出去
        • 程序可以运行,但是已不满足业务场景要求时可以当作异常跑出去
    • throws关键字:当我们使用throw主动对外抛出一个异常时,除了RuntimoeException之外其他异常抛出时必须在方法上使用throws声明该异常的抛出

    • public class Demo{
          private int age;
          public int getAge(){
              return age;
          }
          public void setAge(int age) throws IllegalAgeException{
              if(age<0 || age>100){
                  throw new IlleaglAgeException("年龄不合法");
              }
              this.age = age;
          }
      }
      
    • 当我们调用一个含有throws声明异常抛出的方法时,编译器要求我们必须处理这个异常,否则编译不通过

      • 处理方法由两种:
        • 使用try-catch主动捕获并处理这个异常
        • 使用throws继续将该异常抛出
  • 子类重写超类含有throws生命异常抛出的方法时,对throws的重写规则

    • 允许抛出部分异常

    • 允许不再抛出任何异常

    • 允许抛出超类方法抛出异常的子类异常

    • 不允许抛出额外异常:超类哦没有的,且没有继承关系的

    • 不允许抛出超类方法抛出异常的超类型异常

      总结:子类重写抛出异常要小于等于超类

5、多线程

  • 线程是一个程序的单一顺序执行流程,多个单一流程一起运行就是多线程。多线程时并发执行的。

  • 创建线程有两种方式

    • 继承Thread并重写run方法

      • public class Demo{
            public static void main(String[] args){
                //实例化线程
                MyThread t1 = new MyThread();
                MyThread1 t2 = new MyThread1();
                //启动线程
                t1.start();
                t2.start();
            }
        }
        class MyThread extends Thread{
            public void run(){
                System.out.println("程序开始");
            }
        }
        class MyThread1 extends Thread{
            public void run(){
                System.out.println("程序结束");
            }
        }
        
      • 优点:结构简单,利于匿名内部类创建

      • 缺点:

        • 由于java时单继承的,这导致如果继承了Thread就无法再继承其他类了
        • 在定义线程时定义了线程任务,这导致任务与线程存在了必然的耦合关系,不利于线程的重用
    • 实现Runnable接口单独定义线程任务

      • public class Demo{
            public static void main(String[] args){
                MyRunable r1 = new MyRunable();
                MyRunnable1 r2 = new MyRunnable1();
                Thread t1 = new Thread(r1);
                Thread t2 = new Thread(r2);
                t1.start();
                t2.start();
            }
        }
        class MyRunnable implements Runnable{
            public void run(){
                for(int i=0; i<1000; i++){
                    System.out.println("开始了,");
                }
            }
        }
        class MyRunnable1 implements Runnable{
            public void run(){
                for(int i=0; i<1000; i++){
                    System.out.println("结束了");
                }
            }
        }
        
    • 启动线程调用的是线程的start方法,不能直接调用run方法,start方法调用后线程会被纳入到线程调度器中被统一管理,当他第一次获取调度器分配给它的CPU时间片后就会开始执行run方法

  • 线程提供的获取相关信息的方法

    • public class Demo{
          public static void main(String[] args){
              Thread main = Thread.currentThread();//获取主线程进行查看
              Stirng name = main.getName();//获取线程的名字
              long id = main.getId();//获取线程的唯一标识
              int prioity = main.getPriority();//获取线程的优先级
              boolean isInterrupted = main.isTnterrupted();//当前线程是否被中断
              boolean isDaemon = main.isDaemon();//是否为守护线程
              boolean isAlive = main.isAlive();//是否活着
          }
      }
      
    • java中所有的代码都是靠线程运行的,main方法也不例外,java程序跑起来后,JVM会创建一条线程来执行main方法,这个线程的名字也叫"main",我们通常称呼他为"主线程"

    • 线程的优先级

      • 线程有 10个优先级分别对应整数1-10,其中1是最低的,10是最高的,5是默认值

      • 当一个线程调用start方法后,线程便纳入到了线程调度其中统一管理,线程只能被动的被分配时间片并发执行而不能主动获取时间片,调度器会尽可能均匀的分配时间片给每个线程

      • 调整线程的优先级可以最大程度的改善一个线程获取时间片的几率,线程优先级越高的线程获取时间片的次数越多。

      • public class Demo{
            public static void main(String[] args){
                Thread min = run->{
                    for(int i=0; i<1000; i++){
                        System.out.println("min");
                    }
                };
                Thread nor = run->{
                    for(int i=0; i<1000; i++){
                        System.out.println("nor");
                    }
                };
                Thread max = run->{
                    for(int i=0; i<1000; i++){
                        System.out.println("max");
                    }
                };
                min.setPriorty(1);
                max.setPriorty(10);
                max.start();
                min.start();
                nor.start();
            }
        }
        
    • 守护线程:

      • 守护线程是通过普通线程调用方法setDaemon(true)设置而来的

      • 守护线程和普通线程的区别体现在一个结束时机上额不同:

        • 当进程结束时,进程会强制杀死所有正在运行的守护线程并最终停止
        • 进程的结束:当java进程中所有的普通线程都结束时,进程就会结束。
      • 设置守护线程的工作必须在线程start之前进行

      • public class DaemonThreadDemo {
            public static void main(String[] args) {
        
                Thread rose = new Thread(){
                    public void run(){
                        for(int i=0;i<5;i++){
                            System.out.println("rose:let me go!");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                            }
                        }
                        System.out.println("rose:啊啊啊啊啊啊AAAAAAaaaa.....");
                        System.out.println("噗通!");
                    }
                };
        
                Thread jack = new Thread(){
                    public void run(){
                        while(true){
                            System.out.println("jack:you jump!i jump!");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                            }
                        }
                    }
                };
                rose.start();
                //设置守护线程的工作必须在线程start之前进行!!!!
                jack.setDaemon(true);//将jack设置为守护线程
                jack.start();
        
                while(true);
        
            }
        }
        
  • sleep阻塞

    • 线程提供了一个静态方法sleep,可以时运行该方法的线程阻塞指定毫秒,超时后线程会自动回到RUNNABLE状态继续并发运行

      • public class Demo{
            public static void main(String[] args){
                for(int i=0; i<10; i++){
                    System.out.prinltn(i);
                    Thread.sleep(1000);//1s = 1000ms
                }
            }
        }
        
    • 当一个线程调用sleep方法处于睡眠阻塞的过程中其interrupt()方法被调用,那么这回中断该睡眠阻塞,并且sleep方法会抛出异常

      • public class SleepDemo2 {
            public static void main(String[] args) {
                Thread lin = new Thread(){
                    public void run(){
                        System.out.println("林:刚美完容,睡一会吧~");
                        try {
                            Thread.sleep(50000000);
                        } catch (InterruptedException e) {
                            System.out.println("林:干嘛呢!干嘛呢!干嘛呢!都破了相了!");
                        }
                        System.out.println("林:醒了");
                    }
                };
        
                Thread huang = new Thread(){
                    public void run(){
                        System.out.println("黄:大锤80!小锤40!开始砸墙!");
                        for(int i=0;i<5;i++){
                            System.out.println("黄:80!");
                            try {
                                Thread.sleep(1000);
                            } catch (InterruptedException e) {
                            }
                        }
                        System.out.println("咣当");
                        System.out.println("黄:大哥!搞定!");
                        lin.interrupt();//中断lin线程(如果线程处于睡眠阻塞,则是中断该阻塞状态)
                    }
                };
        
                lin.start();
                huang.start();
            }
        }
        
  • Synchronized关键字

    • 当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致操作顺序 出现了混乱,产生不正常后果,

      • 临界资源:操作该资源的完整过程同一时刻只能由单个线程进行的。
    • 同步监视器对象:一般是锁谁看谁

    • 同步锁

      • 同步方法

        • 普通方法
          • 默认的同步监视器对象是this,指代当前对象
        • 静态方法
          • 静态方法上如果使用synchronized,那么该方法一定是同步的
          • 静态方法上指定的锁对象为当前类的类对象,即Class类的实例,在JVM中每个被加载的类都有且只有一个Class的实例与之对应,它称为一个类的类对象
      • 同步块

        • 同步块可以更准确的锁定需要同步执行的代码片段,有效的缩小排队范围可以在保证安全的前提下尽可能的提高并发效率

        • //语法
          synchronized(同步监视器对象){
              需要多个线程同步执行的代码片段
          }
          
        • 同步执行:多个线程执行时有先后顺序

    • 互斥锁

      • 当使用多个synchronized锁定多个代码片段,并且指定的锁对象都相同时,这些代码片段就是互斥的,即:多线程不能同时执行它们

      • public class SyncDemo4 {
            public static void main(String[] args) {
                Foo foo = new Foo();
                Thread t1 = new Thread(){
                    public void run(){
                        foo.methodA();
                    }
                };
                Thread t2 = new Thread(){
                    public void run(){
                        foo.methodB();
                    }
                };
                t1.start();
                t2.start();
            }
        }
        class Foo{
            public synchronized void methodA(){
                try {
                    Thread t = Thread.currentThread();
                    System.out.println(t.getName() + ":正在执行A方法");
                    Thread.sleep(5000);
                    System.out.println(t.getName() + ":执行A方法完毕");
                }catch(InterruptedException e){
                }
            }
            public void methodB(){
                synchronized(this) {
                    try {
                        Thread t = Thread.currentThread();
                        System.out.println(t.getName() + ":正在执行B方法");
                        Thread.sleep(5000);
                        System.out.println(t.getName() + ":执行B方法完毕");
                    } catch (InterruptedException e) {
                    }
                }
            }
        }
        
    • 死锁

      • 以两个线程为例:但两个线程各自持有一个锁的过程中等待对方先释放锁时就会形成一种僵持状态导致程序卡住且无法再继续后面的操作,这种现象称为死锁

      • 解决死锁:

        • 尽量避免再持有一个锁的同时去等待持有另一个锁(避免synchronized嵌套)
        • 当无法避免synchronized嵌套时,就必须保证多个线程锁对象的持有顺序必须一致,即:A线程再持有锁1的过程总去持有锁2时,B线程也是要这样的持有顺序进行
      • //死锁
        public class Demo{
            private static Object chopsticks =new Object();
            private static Object spoon = new Object();
            public static void main(String[] args){
                Thread np = new Thread(){
                    public void run(){
                        try{
                            System.out.println("北方人:开始吃饭");
                            system.out.println("北方人去拿筷子");
                            synchronized(chopsticks){
                                System.out.println("北方人拿起了筷子,开始吃饭……");
                                Thread.sleep(5000);
                                System.out.println("北方人吃完饭去拿勺子");
                                synchronized(spoon){
                                    System.out.prinltn("北方人拿起了勺子,开始喝汤");
                                    Thread.sleep(5000);
                                }
                                System.out.println("北方人喝完汤,放下勺子");
                            }
                            System.out.println("北方人放下筷子,吃饭完毕");
                        }catch(IOException e){}
                    }
                };
                Thread sp = new Thread(){
                    public void run(){
                        try{
                            System.out.println("南方人:开始吃饭");
                            System.out.println("南方人去拿勺子");
                            synchronized(spoon){
                                System.out.println("南方人拿起勺子,开始喝汤");
                                Thread.sleep(5000);
                                System.out.println("南方人喝完了唐,去拿筷子");
                                synchronized(chopsticks){
                                    System.out.println("南方人拿起筷子,开始吃饭");
                                    Thread.sleep();
                                }
                                System.out.println("南方人吃完了饭,南方人放下了筷子");
                            }
                            System.out.println("南方人放下勺子,吃饭完毕");
                        }catch(IOException e){}
                    }
                };
                np.start();
                sp.start();
            }
        }
        
      • //解决死锁
        public class Demo {
            //筷子
            private static Object chopsticks = new Object();
            //勺
            private static Object spoon = new Object();
        
            public static void main(String[] args) {
                //北方人
                Thread np = new Thread(){
                    public void run(){
                        try {
                            System.out.println("北方人:开始吃饭");
                            System.out.println("北方人去拿筷子...");
                            synchronized (chopsticks) {
                                System.out.println("北方人拿起了筷子,开始吃饭...");
                                Thread.sleep(5000);
                            }
                            System.out.println("北方人吃完了饭,放下了筷子");
                            System.out.println("北方人去拿勺子...");
                            synchronized (spoon){
                                    System.out.println("北方人拿起了勺子,开始喝汤...");
                                    Thread.sleep(5000);
                            }
                            System.out.println("北方人喝完了汤,北方人放下了勺子");
                            System.out.println("吃饭完毕。");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
                //南方人
                Thread sp = new Thread(){
                    public void run(){
                        try {
                            System.out.println("南方人:开始吃饭");
                            System.out.println("南方人去拿勺...");
                            synchronized (spoon) {
                                System.out.println("南方人拿起了勺,开始喝汤...");
                                Thread.sleep(5000);
                            }
                            System.out.println("南方人喝完了汤,放下勺子...");
                            System.out.println("南方人去拿筷子...");
                            synchronized (chopsticks){
                                System.out.println("南方人拿起了筷子,开始吃饭...");
                                Thread.sleep(5000);
                            }
                            System.out.println("南方人吃完了饭,南方人放下了筷子");
                            System.out.println("吃饭完毕。");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                };
        
                np.start();
                sp.start();
            }
        }
        

6、集合:java.util.Collection接口

  • 集合与数组一样,可以保存一组元素,并且对于元素的操作全部提供了对应的方法,使用便捷,集合只能保存引用类型变量,并且保存的是元素的引用(地址)

  • Collection是所有集合的顶级接口,里面规定了所有集合都应当具备的相关操作

  • 其他的两个常见的子接口:

    • java.util.List; 可重复集且有序
    • java.util.Set; 不可重复集
    • 重复指的是元素是否允许存放重复的元素,重复的判定 是根据元素自身的equals方法来决定的
  • //Collection 常用方法
    import java.util.Colletion;
    import java.util.ArrayList;
    public class Demo{
        public static void main(String[] args){
            Collection c = new ArrayList();
            c.add("one");//添加元素
            int size = c.size();//元素个数
            boolean isEmpty = c.isEmpty();//判断是否为空集
            c.clear();//清空集合
            c.add("two");
            c.add("three");
            boolean contains = c.contains("one");
            //判断当前集合是否包含给定元素,判断依据是该元素是否与集合现有元素存在equals方法比较为true的情况,存在则认为包含。
            c.remove("two");
            //删除元素也是删除与给定元素equals比较为ture的元素,对list而言,重复元素只会删除一次
        }
    }
    //集合间的操作:
    class CDemo{
        public static void main(String[] args){
            Collection list = new ArrayList();
            list.add("one");
            list.add("two");
            list.add("three");
            list.add("four");
            Collection set = new HashSet();
            set.add("four");
            set.add("five");
            boolean addAll = list.addAll(set);
            //将给定集合中所有元素添加到当前集合中,添加后当前集合发生了改变则返回true
            boolean contains = list.containsAll(set);
            //判断当前集合是否包含给定集合中的所有元素,全部包含则返回true
            list.retainAll(set);
            //取交集,仅保留当前集合中与给定集合的共有元素
            list.removeAll(set);
            //删交集,将当前集合中与给定集合的共有元素删除
        }
    }
    
  • 集合的遍历

    • 集合提供了统一的遍历方式:迭代器模式

    • 对应的方法:Iterator iterator();该方法可以获取一个用于遍历当前集合的迭代器实现类

    • java.util.Iterator 迭代器接口

      • 不同的集合提供了ige迭代器的实现类用于遍历当前集合元素,迭代器接口上规定了遍历集合的相关方法,使用迭代器遍历集合的步骤:问->取->删的步骤进行,起哄删除不是必要操作。
    • JDK5之后,推出了一个新的特性:增强for循环,也称为新循环,是可以使用相同的语法遍历集合或数组

      • //语法
        for(元素类型  变量名:集合或数组){
            ...
        }
        
    • import java.util.Collection;
      import java.uitl.ArrayList;
      import java.util.Iterator;
      public class Demo{
          public static void main(String[] args){
              Collection<String> list = new ArrayList<>();
              list.add("one");
              list.add("two");
              list.add("three");
              list.add("four");
              list.add("five");
              //使用迭代器进行遍历
              Iterator<String> iterator = list.iterator();
              while(iterator.hasNext()){
                  String str = iterator.next();
                  System.out.println(str);
              }
              //使用新循环进行遍历
              for(String str:list){
                  System.out.println();
              }
          }
      }
      
  • JDK5时还推出了一个新特性:泛型

    • 泛型也称为参数化类型,它允许我们使用一个类时取指定该类中某个属性的类型或方法返回值的类型或方法参数的类型,使得我们使用合格类时更方便更灵活
    • 泛型在集合中广泛使用,用于指定该集合中的元素类型。
  • List集合

    • List接口继承自Collection,是可以存放重复元素且有序的集合

    • 常用实现类:

      • java.util.ArrayList;内部使用数组实现,查询性能更好
      • java.util.LinkedList;内部使用链表实现,增删性能更好,首位增删性能最佳,在对性能没有特别苛刻的情况下通常使用ArrayList即可
    • //List的独有方法
      import java.util.ArrayList;
      import java.util.List;
      public class Demo{
          public static void main(String[] args){
              List<String> list = new ArrayList();
              list.add("one");
              list.add("two");
              list.add("three");
              list.add("four");
              list.add("five");
              String srt = list.get(1);//获取指定下标对应的元素
              String old = list.set(2,"six");
              //将给定元素设置在指定位置上,返回值为该位置被替换下来的元素
              list.add(1,"seven");
              //list中重载的add方法,可以将给定元素插入到指定位置上
              String e = list.remove(3);
              //list中重载的remove方法,删除并返回指定位置上的元素
              List<String> subList = list.subList(1,3);
              //获取指定范围内的子集,含头不含尾,对子集的操作也就是对原集合的操作
          }
      }
      
  • Collections 集合的工具类:

    • sort方法:自然排序,有重载

      • sort(Collection c); 对c进行自然排序

      • sort(Collection c,Comparator com)

        • import java.util.Collection;
          import java.util.ArrayList;
          import java.util.Comparator;
          import java.util.Collections;
          public class Demo{
              public static void main(String[] args){
                  Collection<String> list = new ArrayList<>();
                  list.add("何志恒");
                  list.add("张老师");
                  list.add("小张老师");
                  list.add("何");
                  Collections.sort(list,new Comparator<String>(){
                      public int compare(String line1,String line2){
                          return line1.length()-line2.length();
                      }
                      //用来定义两个元素之间o1和o2的大小关系并返回
                      //如果返回值>0,则表示o1>o2
                      //如果返回值<0,则表示o1<o2
                      //如果返回值=0,则表示o1=o2
                  });
              }
          }
          
    • reverse方法:翻转list集合

    • toArray方法:将当前集合转为数组

      • toArray方法传入的数组长度实际没有长度要求,就功能而言如果给定的数组长度>=集合的size时,就是用该数组(将集合元素存入到数组中)然后将其返回;如果指定的数组长度不足时会根据该数组类型自行创建一个与集合size一直的数组并返回

      • import java.util.List;
        import java.util.ArrayList;
        import java.util.Collections;
        public class Demo{
            public static void main(String[] args){
                List<String> list = new ArrayList<>();
                list.add("one");
                list.add("two");
                list.add("three");
                list.add("four");
                list.add("five");
                String[] array = Collections.toArray(new String[list.size()]);
            }
        }
        
  • 数组转换集合

    • 数组的工具类Arrays提供了一个静态方法asList,可以将一个数组转换为List集合

    • import java.util.List;
      import java.util.Arrays;
      public class Demo{
          public static void main(String[] args){
              String[] line = {"one","two","three","four","five"};
              List<String> list = Arrays.asList(line);
              //对集合的操作就是对数组的操作,不能进行增删,可能导致越界异常,如果需要操作可以通过ArrayList(List l)这个构造器创建新的集合包含数组转换过来的集合。
          }
      }
      

7、Map:查找表 ;java.uitl.Map接口

  • 体现的结构是一个多行两列的表格,其中左列称为key,右列称为value,Map总是根据key获取对应的value值

  • 常用的实现类:

    • java.util.HashMap:称为散列表,哈希表,是使用散列算法实现的Map,当今查询速度最快的数据结构
    • java.util.TreeMap:使用二叉树算法是实现的Map;
  • //Map常用方法
    import java.util.Map;
    import java.util.HashMap;
    public class Demo{
        public static void main(String[] args){
            Map<String,Integer> map = new HashMap<>();
            map.put("数学",100);//将一组键值对存入Map中
            map.put("语文",100);
            //key不能重复
            map.put("物理",98);
            map.put("化学",90);
            map.put("英语",10);
            //如果put方法存入的键值对中,key不存在时,则直接将key-value存入,返回值为null,如果key存在,则是替换value操作,此时返回值为被替换下来的value,所以为了防止空指针异常,如果接收返回值,这里必须用Integer 包装类进行接收。
            Integer value = map.get("化学");
            //根据给定额key获取对应的value,如果给定的key不存在,则返回值为null
            int size = map.size();
            //返回map的键值对的个数
            boolean ck = map.containsKey("语文");
            //判断是否存在给定的key
            boolean cv = map.containsValue(100):
            //叛党是否存在给定的value
            value = map.remove("英语");
            //从map中删除给定的key对应的这一组键值对,返回值为该key所对应的value
            
        }
    }
    
  • //Map的遍历
    import java.util.Map;
    import java.util.HashMap;
    public class Demo{
        public static void main(String[] args){
            Map<String,Integer> map = new HashMap<>();
            map.put("数学",100);//将一组键值对存入Map中
            map.put("语文",100);
            //key不能重复
            map.put("物理",98);
            map.put("化学",90);
            map.put("英语",10);
            Set<String> keySet = map.keySet();
            //将当前Map中所有的key以一个set集合形式返回,遍历该集合等同于遍历所有的key
            
            Set<Map.Entry<String,Integer>> entrySet = map.entrySet();
            //将当前Map中每一组键值对以一个Entry实例形式表示,并存入Set集合后返回
            //java.util.Map.Entry的每一个实例用于表示Map中的一组键值对,其中方法
            //K  getKey();获取对应的key
            //V  getValue();获取对应的value
            for(Map.Entry<String,Integer> e:entrySet){
                String key = e.getKey();
                Integer value = e.getValue();
            }
            
            map.forEach((k,v)->System.out.println(k+" "+v););
            //JDK8之后支持的forEach用于集合和Map使用lambda表达式遍历的操作。
        }
    }
    
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值