JAVA进阶

Collection(单列集合的顶层接口)

    public boolean add(E e)            添加
    List中添加一定返回true因为元素可重复,Set中元素不能重复
    所以可能是true可能是false
    public void clear()                  清空
    public boolean remove(E e)           删除
    1.只能通过元素删除因为Set中没有索引,而Collection的方法是具有共性的
    2.删除成功返回true删除失败返回false
    public boolean contains(Object obj)  判断是否包含
    底层逻辑用到equals所以自定义类型必须重写equals方法,不然就是Object的比较地址值
    public boolean isEmpty()             判断是否为空
    public int size()                    长度
     

List(有三个集合类)

特点:有序,有索引,可重复

List系独有方法
        void add(int index,E element)  根据索引插入元素
        细节:如果插入索引有元素那么原索引下的元素会自动往后移动
        E remove(int index)            删除索引下的元素,返回被删除的元素
        如果出现方法重载优先调用形参与实参一致的
        E set(int index,E element)     修改索引下的元素,返回被修改的元素
        E get(int index)               返回指定索引下的元素

ArrayList(用数组实现)

LinkedList(用双链表实现)

Vector(不常用)

Set(集合实现类)

特点:无序,不重复,无索引

哈希值:默认是通过地址值计算,所以一般得重新,利用内部的属性值计算

哈希值特点:没有重写的计算出来的哈希值不一样,如果重写了然后属性值一样那么哈希值一样

特例:有小概率不同属性和不同地址值算出来的哈希值有可能一样(哈希碰撞)

HashSet(哈希表存储)(数组,链表,红黑树)

LinkedHashSet(有序)(哈希表存储只是多了双向链表)

TreeSet(可排序)(红黑树存储)

迭代器

Collection<String> coll=new ArrayList<>();
    coll.add("aaa");
    coll.add("bbb");
    coll.add("ccc");
    //获取迭代器指针
    //方法hasNext()判断此位置是否有元素
    //方法next()获取该位置指针然后移动到下一位
    /*细节
        当前位置没有元素强行获取会报NoSuchElementException
        迭代器遍历完毕,指针不会复位
        循环中只能使用一次next
        迭代器遍历时,不能使用集合的增删
     */
    Iterator<String> it= coll.iterator();
    while(it.hasNext()){
        String str = it.next();
        System.out.println(str);
}

ArrayList<String> arrayList=new ArrayList<>();
        列表迭代器
        //与迭代器差不多只是多了添加元素,修改元素
        //hasPrevious(),Previous()相等于倒着遍历(有缺点)
        ListIterator<String> lit=arrayList.listIterator();
        while(lit.hasNext()){
            lit.next();
        }

for增强

Collection<String> coll=new ArrayList<>();
    coll.add("aaa");
    coll.add("bbb");
    coll.add("ccc");
   //for增强
   //for增强不会修改集合和数组原本的数据
   for (String s : coll) {
       System.out.println(s);

lambda表达式

 Collection<String> coll=new ArrayList<>();
   coll.add("aaa");
   coll.add("bbb");
   coll.add("ccc");
   //lambda表达式
   coll.forEach(s-> System.out.println(s));

泛型

JAVA中的泛型是伪泛型,只在编译中存在

Java文件存在在class文件没有,这就是泛型的擦除

泛型类

修饰符 class 类名 <类型>{}

泛型方法

修饰符 <类型> 返回值类型 方法名(类型 变量名){}

泛型接口

1.实现类给出具体的类型

2.实现类延续泛型,创建实现类对象再确定类型

泛型的通配符

泛型不具有继承性,但数据可以

?extends E:表示可以传递E和E的所有子类类型

?super E:表示可以传递E和E的所有父类

Map(双列集合)

特点:

1.一次需要存一对数据(键和值)

2.键不能重复,值可以

3.键和值是一一对应的,每个键只能找到对应的值

 V put(K key,V value)                  添加元素
 如果添加数据的键不存在,就直接添加,如果存在键,那么就覆盖数据,并将被覆盖的值进行返回
 V remove(K key,V value)               根据键删除对应元素
 返回被删除的值
 void clear()                          移除所有的键和值
 boolean containsKey(Object key)       判断集合包含指定的键
 boolean containsValue(Object value)   判断集合包含指定的值
 boolean isEmpty()                     判断集合是否为空
 int size()                            集合个数

三种遍历方式

        //第一种
        Map<String,String> m=new HashMap<>();
        m.put("郭靖","黄蓉");
        m.put("杨过","小龙女");
        m.put("亚瑟","安其拉");
        m.put("至尊宝","紫霞仙子");
        Set<String> keys=m.keySet();
        for (String key : keys) {
            String value=m.get(key);
            System.out.println(key+"="+value);
        }
        //第二种
        Set<Map.Entry<String, String>> entries = m.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String value = entry.getValue();
            System.out.println(key+"="+value);
        }
        //第三种
        m.forEach(( key, value) -> System.out.println(key+"="+value));

HashMap,LinkedHashMap和TreeMap

其实和Set中对应的HashSet,LinkedHashSet和TreeSet底层原理一样,只是多了键找值的功能

可变参数

细节:

1.在方法的形参中最多只能写一个可变参数;

2.在方法中,如果存在可变参数以外的形参,那么可变参数要写到最后面

3.可变参数本质上是个数组

4.格式:数据类型...参数名称

Collections

collections不是集合,而是集合的工具类

不可变集合

特点:定义完成后不能被修改,增删

List,Set,Map接口中都存在of方法来创建不可变集合

细节:

List(直接用)

Set(元素不重复)

Map(最多添加十对键值对)

超过十个可以用ofEntries方法

JDk10可以直接用copyOf方法代替

 Map<String,String> map=new HashMap<>();
        map.put("1","a");
        map.put("2","b");
        map.put("3","c");
        map.put("4","d");
        map.put("5","e");
        map.put("6","f");
        map.put("7","g");
        map.put("8","h");
        map.put("9","i");
        map.put("10","j");
        Map<Object, Object> map1 = Map.ofEntries(map.entrySet().toArray(new Map.Entry[0]));
        //等价
        Map<String, String> map2 = Map.copyOf(map);

Stream流

获取方式

//单列集合获取方式
        ArrayList<Integer> list=new ArrayList<>();
        Collections.addAll(list,1,2,3,4,5,6);
        list.stream().forEach(integer-> System.out.println(integer));
       // 双列集合获取方式(通过转单列)
        Map<String,Integer> map=new HashMap<>();
        map.put("aa",1);
        map.put("bb",2);
        map.put("cc",3);
        map.put("dd",4);
        map.entrySet().stream().forEach((Map.Entry<String, Integer> s)-> System.out.println(s));
        // 数组获取方式
        String[] arr={"aaa","bbb","ccc","ddd"};
       Arrays.stream(arr).forEach(s-> System.out.println(s));
        // 一堆零散数据
        Stream.of(arr).forEach(s-> System.out.println(s));//可以是引用数据类型,但基本数据类型就会数组当成整个元素
        Stream.of(1,2,3,4,5,6,7).forEach(s-> System.out.println(s));

中间方法

注意:

中间方法Stream只能用一次建议链式编程

修改Stream中的数据不会影响集合或者数组中的数据

 /*
      filter         过滤
      limit          获得前几个元素
      skip           跳过前几个元素
      distinct       元素去重(依赖equals和hashcode)
      concat         合并流
      map            转换流中的数据类型
       */
        //过滤
        ArrayList<Integer> list1=new ArrayList<>();
        Collections.addAll(list1,1,2,3,4,5,6);
        list1.stream().filter(i-> i>=5).forEach(integer -> System.out.println(integer));
        //转换数据类型
        //apply中的形参s表示流中的每个数据
        ArrayList<String> list2=new ArrayList<>();
        Collections.addAll(list2,"a-1","b-2","c-3","d-4");
        list2.stream().map(s-> Integer.parseInt(s.split("-")[1]));

终结方法

/*
        forEach             遍历
        count               统计
        toArray             收集数据放到数组
        collect             收集流中的数据放到集合中(list,set,map)
         */
        //放数组
        ArrayList<String> list=new ArrayList<>();
        Collections.addAll(list,"aaa","bbb","ccc","ddd");
        //IntFunction的泛型:具体类型的数组
        //apply的形参:流中的数据的个数,要跟数组的长度保持一致
        //apply的返回值:具体类型的数组
        list.stream().toArray(new IntFunction<String[]>() {
            @Override
            public String[] apply(int value) {
                return new String[value];
            }
        });
        //放集合(map)
        ArrayList<String> arrayList=new ArrayList<>();
        Collections.addAll(arrayList,"a-1","b-2","c-3","d-4");
        Map<String, Integer> collect = arrayList.stream().collect(Collectors.toMap(
                new Function<String, String>() {
                    @Override
                    public String apply(String s) {
                        return s.split("-")[0];
                    }
                    },
                new Function<String, Integer>() {
                    @Override
                    public Integer apply(String s) {
                        return Integer.parseInt(s.split("-")[1]);
                    }
                }));
        System.out.println(collect);

方法引用

其实就是把已经存在的方法拿来用,当中函数式接口中的抽象方法体

::方法引用符

注意:需要有函数式接口,被引用的方法必须存在

引用静态方法

类名::静态方法(其实和方法调用差不多->类名.静态方法

引用成员方法

格式:对象::成员方法

1.其他类:其他类对象::方法名(new A()::方法)

2.本类:this::方法名(不能是静态方法)

3.父类:super::方法名(不能是静态方法)

引用构造方法

格式:类名::new

规则:

1.需要有函数式接口

2.被引用的方法必须已经存在

3.被引用方法的形参和返回值(构造方法可以不用管返回值,构造方法运行完了对象就有了),需要跟抽象方法的形参和返回值保持一致

4.被引用方法的功能需要满足当前的需求

使用类名引用成员方法

格式:类名::成员方法

与其他类对象引用方法名的区别是类名引用的成员方法具有局限性

特例规则:抽象方法形参的第一个参数表示被调用者决定了哪些类可以被调用(局限性)

,第二参数到最后一个参数需要跟被引用者的参数保持一致,如果没有第二个参数那么就是无参的成员方法

引用数组的构造方法

格式:数据类型[]::new

java底层已经写好了数组的构造方法

细节:数据类型要保持一致

异常

Exception是异常的顶级父类包含RuntimeException(运行时异常)和 编译异常

作用:

1.查询bug的关键参考信息

2.可以作为方法内部的一种特殊返回值

异常的三种处理方式

1.JVM的默认处理方式

把异常原因及异常出现的位置打印到控制台,并停止程序运行(下面的程序不会执行)

2.捕获异常(自己处理)

格式:try{

可能出现异常的代码

}catch(异常类名 变量名){

异常的处理代码

}

1.如果try中没有遇到问题就不执行catch中的代码

2.如果try可能有多个问题,那么就写多个catch去捕获(注意父类写下面)

3.如果catch没有捕获到那就白写了

4.如果try遇到问题,那么try下面的代码就不执行了

3.抛出异常

throws写在方法处告诉编译者可能出现的bug(编译必须写,运行可以不写)

throw写在方法内,结束方法

异常中的常见方法

getMessage(返回详细说明字符串)(返回值String)

toString(简短说明)(返回值String)

printStackTrace(常用)

自定义异常

1.定义异常类

2.写继承关系

3.空参构造

4.带参构造

编译异常就继承Exception(由参数错误导致的)

运行异常就继承RunTimeException(提醒程序员检查本地信息)

File

file对象表示一个路径,可以是文件的路径,也可以是文件夹的路径

路径可以是已存在的,也可以是不存在的

三种方法创建文件对象

   //1.直接用
      String path="C:\\Users\\Jessny\\Desktop\\实验.txt";
        File f1=new File(path);
        //2.父路径+子路径
        String  parent="C:\\Users\\Jessny\\Desktop";
        String  child="实验.txt";
        File f2=new File(parent,child);
        //3.文件父路径和字符串子路径拼接
        File parent1=new File("C:\\Users\\Jessny\\Desktop");
        String  child1="实验.txt";
        File f3=new File(parent1,child1);

成员方法

 File file=new File("test\\myio\\src\\a.txt");
        boolean b1 = file.isDirectory();判断是否为文件夹
        boolean b2 = file.isFile();判断是否为文件
        boolean b3 = file.exists();判断是否为FILE类型(文件夹或者文件)
        long length = file.length();获取文件大小(字节)
        File absoluteFile = file.getAbsoluteFile();返回绝对路径
        String path = file.getPath();返回定义文件时的路径(相对路径)
        String name = file.getName();返回文件名带后缀
        long l = file.lastModified();修改文件最后的毫秒值
        /********************************************************************************/
        File file1=new File("D:\\JAVA测试文件夹\\aaa\\a.txt");
        boolean newFile = file1.createNewFile();
        创建文件,如果不存在就创建并返回true,反之false,父级路径如果不存在就好出现异常
        File file2=new File("D:\\JAVA测试文件夹\\aaa\\kkk");
        boolean mkdir = file1.mkdir();创建单级文件夹
        File file3=new File("D:\\JAVA测试文件夹\\aaa\\kkk\\nnn");
       boolean mkdirs = file1.mkdirs();创建多级文件夹
        boolean delete = file1.delete();删除文件(不走回收站),有内容的删除失败
        /*****************************************************************************/
        File[] arr=File.listRoots();获取系统盘符
        File file4=new File("D:\\JAVA测试文件夹");
        File[] files = file4.listFiles();获得该路径下的所有内容,带参是写过滤的实现
        
        当路径不存在或者是文件的时候返回null
        当路径下是空文件夹的时候返回长度为0的数组
        路径可以是隐藏文件
        当文件夹需要权限才能访问的话,返回null
         
        for (File f : files) {
            System.out.println(f);
        }

IO流

字节流:能处理所有文件

字符流:只能处理文本文件

字节输出流

        创建对象
        可以是路径,也可以是file对象
        只要父级路径存在,不存在的文件也会创建一个新的,如果存在会覆盖之前写的数据
        FileOutputStream f=new FileOutputStream("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt");
        写数据
        f.write(97);//写一个
        byte[] bytes={97,98,99,100,101};
        f.write(bytes);//写多个
        f.write(bytes,0,3);//写多个限范围
        释放资源
        f.close();



续写:Windows:\r\n但写其中一个也可以JAVA会帮忙补全
      Linux:   \n
      Mac:   \r

字节输入流

        创建对象
        如果文件不存在就会报错
        FileInputStream fis=new 
        FileInputStream("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt");
        读数据
        读的是ASCII对应的数字,读到末尾返回-1
        int i;
        while((i=fis.read())!=-1){
            System.out.println((char) i);
        }和write一样有三种
        释放资源
        fis.close();

文件拷贝

FileInputStream fis=new FileInputStream("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt");
        FileOutputStream fos=new FileOutputStream("D:\\IdeaProjects\\day123\\test\\myio\\b.txt");
        int len;
        byte[] b=new byte[2];
        while((len=fis.read(b))!=-1){
            fos.write(b,0,len);
        }
        先开后关
        fos.close();
        fis.close();

IO流捕获异常

 都会自动释放资源
        //JDK7
        try(创建流对象1;创建流对象2){
                 可能出现异常的代码;
        }catch (异常类名 变量名){
            异常处理的代码
        }
        //JDK9
        创建流对象1;
        创建流对象2;
        try(变量名1;变量名2){
            可能出现异常的代码;
        }catch (异常类名 变量名){
            异常处理的代码
        }

字符集

ASCII字符集中一个英文占一个字节

简体中文版Windows,默认使用GBK字符集

GBK兼容ASCII字符集

一个英文,占一个字节,二进制第一位是0

一个中文占两个字节,二进制高位字节的第一位是1

Unicode字符集的UTF-8编码方式

一个英文占一个字节,二进制第一位是0,转成十进制是正数

一个中文占三个字节,二进制第一位是1,转成十进制是负数

乱码的原因

1.读取数据不完整

2.编码和解码不统

拷贝的时候没有乱码是因为数据没有丢失

不要使用字节流读取文本文件

编码解码时使用同一个码表,使用同一种编码方式

JAVA中的编码解码

        编码
        String str1="ai你好";
        byte[] bytes=str1.getBytes("GBK");可以空参,空参默认JAVA中的UTF-8
        System.out.println(Arrays.toString(bytes));
        解码
        String str2=new String(bytes);空参默认JAVA中的UTF-8
        System.out.println(str2);
        String str3=new String(bytes,"GBK");
        System.out.println(str3);

字符流

FileReader fr=new FileReader("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt");
        FileWriter fw=new FileWriter("D:\\IdeaProjects\\day123\\test\\myio\\b.txt");
        int ch;
        while ((ch=fr.read())!=-1){
            fw.write("你好");
            fw.write(ch);
        }
        char[] chars=new char[2];
        int len;
        while ((len=fr.read(chars))!=-1){
            fw.write(chars,0,len);
        }
        read(chars)是把读取数据,解码,强转结合在一起

        fw.close();
        fr.close();

字符流原理解析

1.创建字符输入流对象

底层:关联文件,并创建8192的数组缓冲区

2.读取数据

底层:判断缓冲区是否有数据可以读取;

缓冲区没有数据:就从文件获取数据,尽可能装满缓冲区,如果文件也没有数据就返回-1

缓冲区有数据:就从缓冲区读取

输出流中flush方法可以将缓冲区的数据刷新到文件中

字节缓冲流(区别就是自带长度为8192的缓冲区)

字符缓冲流(基本上没区别,但有两个新方法readLine一次读一行,newLine跨平台换行)

转换流:字节流想用字符流中的方法

//JDK11之前
        InputStreamReader isr=new InputStreamReader(new FileInputStream
                ("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt"),"GBK");
        OutputStreamWriter osw=new OutputStreamWriter(new FileOutputStream
                ("D:\\IdeaProjects\\day123\\test\\myio\\b.txt"),"GBK");
        int i;
        while ((i = isr.read())!=1){
            osw.write(i);
        }
        osw.close();
        isr.close();
        //JDK11
        FileReader fr=new FileReader("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt"
                , Charset.forName("GBK"));
        FileWriter fw=new FileWriter("D:\\IdeaProjects\\day123\\test\\myio\\b.txt"
                ,Charset.forName("GBK"));
        int l;
        while ((l=fr.read())!=-1){
            fw.write(l);
        }
        fw.close();
        fr.close();

利用字节流读取文本数据,不会出现乱码,读一整行

FileInputStream fis=new FileInputStream("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt");
        InputStreamReader isr=new InputStreamReader(fis);
        BufferedReader br=new BufferedReader(isr);
        String str;
        while ((str= br.readLine())!=null){
            System.out.println(str);
        }
        br.close();

序列化流和反序列化流(将类写入文件/读取文件中的类)

1.使用序列化流将对象写入文件时,需要让Javabeen实现Serializable接口,否则会出现NoSerializableException异常

2.序列化流的数据是不能修改的,一旦修改就再也读不回来

3.序列化对象后修改Javabeen会出现InvalidClassException异常,需要通过添加SerialVersionUID(序列号,版本号)

4.一个对象的成员变量不想被序列化,可以通过给成员变量加transient关键字修饰,该关键字的标记的成员变量不参与序列化的过程

Student s1=new Student("zhangsan",23);
        创建序列化对象
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream
                ("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt"));
        写出数据
        oos.writeObject(s1);
        释放资源
        oos.close();
        
        
        创建反序列化对象
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream
                ("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt"));
        读取数据
        Student o =(Student) ois.readObject();
        System.out.println(o);
        释放资源
        ois.close();    

打印流

打印流包括字节打印流和字符打印流

打印流不操作数据源,只能操作目的地

字节打印流默认自动刷新

字符打印流需要手动开启

PrintStream ps=new PrintStream("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt");
        ps.print("你好");
        ps.close();
        PrintWriter pw=new PrintWriter("D:\\IdeaProjects\\day123\\test\\myio\\src\\a.txt");
        pw.println("张三");
        pw.close();

解压缩流和压缩流

解压

File src=new File("D:\\JAVA测试文件夹\\aaa.zip");
        File dest=new File("D:\\JAVA测试文件夹\\");
        unZip(src,dest);
 private static void unZip(File src,File dest) throws IOException {
        //解压本质就是拷贝压缩包里面的内容
        //创建解压缩流来读取压缩包中的数据
        ZipInputStream zis=new ZipInputStream(new FileInputStream(src));
        //获取压缩包的文件或文件夹对象
        ZipEntry entry;
        while ((entry = zis.getNextEntry())!=null){
            if(entry.isDirectory()){
                //文件夹
                File file=new File(dest, entry.toString());
                file.mkdirs();
            } else {
                //文件
                FileOutputStream fos=new FileOutputStream(new File(dest,entry.toString()));
                int b;
                while ((b=zis.read())!=-1){
                    fos.write(b);
                }
               fos.close();
                //一个压缩包文件处理完毕
                zis.closeEntry();
            }
        }
        zis.close();
    }

压缩单个文件

 File src=new File("D:\\JAVA测试文件夹\\a.txt");
        File dest=new File("D:\\JAVA测试文件夹\\");
         toZip(src,dest);
 public static void toZip(File src,File dest) throws IOException {
        //创建压缩流
        ZipOutputStream zos=new ZipOutputStream(new FileOutputStream(new File(dest,"a.zip")));
        //创建ZipEntry对象,表示压缩包中的文件或文件夹
        ZipEntry entry=new ZipEntry("a.txt");
        //把ZipEntry对象放到压缩包当中
        zos.putNextEntry(entry);
        //把src写到压缩包当中
        FileInputStream fis=new FileInputStream(src);
        int b;
        while ((b=fis.read())!=-1){
            zos.write(b);
        }
        zos.closeEntry();
        zos.close();
    }

压缩一个文件夹

//压缩的文件夹
        File src=new File("D:\\JAVA测试文件夹\\aaa");
        String parent = src.getParent();
        File dest=new File(parent,src.getName()+".zip");
        ZipOutputStream zos=new ZipOutputStream(new FileOutputStream(dest));
        //获取src里面的每个文件,变成ZipEntry对象,放入压缩包中
        tozip(src,zos,src.getName());
        zos.close();
private static void tozip(File src,ZipOutputStream zos,String name) throws IOException {
        File[] files = src.listFiles();
        for (File file : files) {
            if(file.isFile()){
                //文件
                ZipEntry entry=new ZipEntry(name+"\\"+file.getName());
                zos.putNextEntry(entry);
                FileInputStream fis=new FileInputStream(file);
                int b;
                while ((b=fis.read())!=-1){
                    zos.write(b);
                }
                fis.close();
                zos.closeEntry();
            }else {
                //文件夹
                tozip(file,zos,name+"\\"+file.getName());
            }
        }
        zos.close();
    }

多线程

多线程可以让程序同时做多件事情,提高效率(同时做多件事情就可以考虑多线程)

并发:在同一时刻,有多条指令在单个CPU上交替执行

并行:在同一时刻,有多条指令在多个CPU上同时执行

多线程的三种实现方式

法一:继承Thread
public class MyThread extends Thread{
    定义一个方法继承Thread
    重写run方法
    创建子类对象,并启动线程

    @Override
    public void run() {
        System.out.println(getName()+":你好");
    }
}
      MyThread mt1=new MyThread();
        MyThread mt2=new MyThread();
        mt1.setName("线程一");
        mt2.setName("线程二");
        mt1.start();
        mt2.start();
法二:实现Runnable接口
public class MyRun implements Runnable{
    实现接口
    重写run方法
    创建自己类的对象
    创建Thread对象,并开启线程
    @Override
    public void run() {
        获取当前线程对象
        Thread t1 = Thread.currentThread();
        System.out.println(t1.getName()+":哈喽");
    }
}
 MyRun mr=new MyRun();
        Thread t=new Thread(mr);
        t.setName("线程");
        t.start();

法三:利用Callable接口和Future接口实现

public class MyCallable implements Callable {
    @Override
    public Integer call() throws Exception {
        int sum=0;
        for (int i = 1; i <=10; i++) {
            sum=sum+i;
        }
        return sum;
    }    
    特点:可以获取多线程的运行结果
    1.创建自己类实现Callable接口
    2.重写call方法
    3.创建自己类对象(多线程要执行的任务)
    4.创建FutureTask对象(管理多线程运行结果)
    5.创建Thread对象,并启动线程   
}
 MyCallable mc=new MyCallable();
        FutureTask<Integer> ft=new FutureTask<>(mc);
        Thread t=new Thread(ft);
        t.start();
        获取多线程运行结果
        Integer result = ft.get();

成员方法

       getName()获取对象名字
       setName()设置对象名字(有默认名字)
       currentThread()获取当前线程对象
       sleep()让线程休眠(毫秒)
       setPriority(1);设置线程优先级(1,5,10)
       getPriority()获取线程优先级
       setDaemon(Boolean on);守护线程(当被守护的线程结束,守护线程也会慢慢停止)
       Thread.yield();出让或礼让线程,会出让一次CPU线权(静态方法)
       join()插入线程,执行完该线程才进行下个任务

同步代码块

把操作共享数据的代码锁起来

特点:一个线程进去就锁上,出来后再打开

格式:synchronized(锁){

操作共享数据的代码

}

锁一般是类名.class保证只认准一个锁

同步方法

格式:修饰符 synchronized 返回值类型 方法名(方法参数){}

锁对象不能自己指定

非静态:this

静态:当前类的字节码文件对象

lock锁

效果和同步代码块或同步方法差不多

public class MyThread extends Thread{
  static int ticket=0;
  static Lock lock=new ReentrantLock();

    @Override
    public void run() {
        while (true){
            lock.lock();
            try {
                if (ticket==100){
                    break;
                }
                for (int i = 0; i < 100; i++) {
                    Thread.sleep(10);
                    ticket++;
                    System.out.println(getName()+"在出售第"+"张票");
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }

    }
}
 MyThread mt1=new MyThread();
        MyThread mt2=new MyThread();
        System.out.println(mt1.getPriority());
        System.out.println(mt2.getPriority());
        mt1.setName("窗口1:");
        mt2.setName("窗口2:");
        mt1.start();
        mt2.start();

等待唤醒机制

生产者和消费者

public class Foodie extends Thread{
    @Override
    public void run() {
        /*
        1.写循坏
        2.写同步代码块
        3.写结束条件
        4.写未结束情况
         */
        while (true){
            synchronized (Desk.lock){
                if (Desk.count==0){
                    break;
                }else{
                    if (Desk.noodles==0){
                        try {
                            Desk.lock.wait();//让当前线程跟锁进行绑定
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else{
                        //总数减少
                        Desk.count--;
                        System.out.println("食客正在吃面条"+"还能吃"+Desk.count+"碗");
                        //唤醒厨师
                        Desk.lock.notifyAll();
                        //修改面条状态
                        Desk.noodles=0;
                    }

                }
            }
        }

    }
}
public class Cook extends Thread{
    @Override
    public void run() {
        while (true){
            synchronized (Desk.lock){
                if (Desk.count==0){
                    break;
                }else {
                    if (Desk.noodles==1){
                        try {
                            Desk.lock.wait();
                        } catch (InterruptedException e) {
                            throw new RuntimeException(e);
                        }
                    }else {
                        System.out.println("厨师做了一碗面条");
                        //唤醒食客吃
                        Desk.lock.notifyAll();
                        //修改面条状态
                        Desk.noodles=1;
                    }
                }
            }
        }
    }
}
public class Desk {
    //吃面条的总数
    public static int count=10;
    //0表示桌子上没有面条,1表示有面条
    public static int noodles=0;
    //锁对象
    public static Object lock=new Object();
}
 public static void main(String[] args) {
        Cook c=new Cook();
        Foodie f=new Foodie();
        c.setName("厨师");
        f.setName("食客");
        c.start();
        f.start();
    }

阻塞队列

ublic class Foodie extends Thread{
    ArrayBlockingQueue queue;

    public Foodie(ArrayBlockingQueue queue) {
        this.queue = queue;
    }
    @Override
    public void run() {
        /*
        1.写循坏
        2.写同步代码块
        3.写结束条件
        4.写未结束情况
         */
        while (true){
            try {
                queue.take();
                System.out.println("食客吃了一碗面条");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

    }
}
public class Cook extends Thread{
    ArrayBlockingQueue queue;

    public Cook(ArrayBlockingQueue queue){
        this.queue=queue;
    }
    @Override
    public void run() {
        while (true) {
            try {
                queue.put("面条");
                System.out.println("厨师做了一碗面条");
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}
public static void main(String[] args) {
        //生产者和消费者必须是同一个阻塞队列
        ArrayBlockingQueue<String> queue=new ArrayBlockingQueue<>(1);
        Foodie f=new Foodie(queue);
        Cook c=new Cook(queue);
        f.start();
        c.start();
    }

 线程的六种状态

线程池 

1.创建一个空池子

2.提交任务时,池子会创建一个新线程对象,任务执行完毕,线程归还给池子,下回继续用,不需要创建新的线程,直接复用已创建的线程即可

3.如果提交任务时,没有空闲的线程,就需要等待

 //获取线程池对象
        ExecutorService pool= Executors.newCachedThreadPool();//几乎无限的线程
        ExecutorService pool1 = Executors.newFixedThreadPool(3);//指定线程
        //提交任务
        pool.submit(new Myrun());
        //销毁线程池
        pool.shutdown();

自定义线程池

ThreadPoolExecutor threadPoolExecutor=new ThreadPoolExecutor(
                3,//核心线程数量,必须大于0
                6,//最大线程数量,必须大于核心线程数量
                60,//空闲线程最大存活时间
                TimeUnit.SECONDS,//空闲线程最大存活时间单位
                new ArrayBlockingQueue<>(30),//任务队列
                Executors.defaultThreadFactory(),//创建线程工厂
                new ThreadPoolExecutor.AbortPolicy()//任务拒绝政策
        );

最大并行数

其实就是线程的多少

比如电脑是4核8线程,那么最大并行数就是8 

线程池大小

CPU密集型运算:最大并行数+1;

IO密集型运算:最大并行数*期望CPU利用率*总时间(CPU计算时间+等待时间)/CPU计算时间(可以用thread dump)来算

网络编程

计算机与计算机通过网络进行数据传输

常见软件架构:BS(客户端)(不需要开发客户端随时都能玩)与CS(浏览器)(适合定制专业软件)

三要素

IP地址,端口号,协议

IP

IPv4最多只有2^32次方个ip

利用局域网ip解决ip不够用的情况

特殊ip:127.0.0.1(永远表示本机)

ipconfig:查看本机IP地址

ping:检查网络是否连通

IPv6最多可以有2^128次方个ip

InetAddress

//获取InetAddress对象
        //ip的对象 一台电脑的对象
        InetAddress address=InetAddress.getByName("DESKTOP-DJL922R");//可以是电脑名也可以是ip
        String ip = address.getHostAddress();
        String name = address.getHostName();//有可能返回是ip,因为局域网中不存在这个电脑名或者其他情况

 端口号

应用程序在设备中的唯一标识

端口号:由两个字节表示的整数,取值范围:0~65535

其中0~1023用于一些知名的网络服务或应用

自己用1024以上就可以了

注意:一个端口号只能被一个应用程序使用

协议

在计算机网络中,连接和通信的规则被称为网络通信协议

UDP协议

UDP是面向无连接通信协议

速度快,由大小限制一次最多发64k,数据不安全,易丢失

**************发送数据*****************************
//创建对象(快递公司)
        /*
        绑定端口:以后就通过这个端口往外发送
        空参:会随机一个可用的端口
         */
        DatagramSocket ds=new DatagramSocket();
        //打包数据
        String str="你好,我是小米!!!";
        byte[] bytes = str.getBytes();
        int port=10086;
        InetAddress address=InetAddress.getByName("127.0.0.1");
        DatagramPacket dp=new DatagramPacket(bytes, bytes.length,address,port);
        //发送数据
        ds.send(dp);
        //释放资源
        ds.close();
**************接收数据**********************************
  //创建对象
        DatagramSocket ds=new DatagramSocket(10086);
        //接收数据
        byte[] bytes= new byte[1024];
        DatagramPacket dp=new DatagramPacket(bytes, bytes.length);
        ds.receive(dp);
        //解析数据
        byte[] data = dp.getData();
        int len = dp.getLength();
        int port = dp.getPort();
        InetAddress address = dp.getAddress();
        System.out.println("接收到数据:"+new String(data,0,len));
        System.out.println("该数据是从:"+address+"这台电脑中的"+port+"端口发出");

组播

组播地址:224.0.0.0~239.255.255.255

其中:224.0.0.0~2240.0.255为预留组播地址

 public static void main(String[] args) throws IOException {
        //创建组播对象
        MulticastSocket ms=new MulticastSocket();
        //打包文件
        String str="你好,你好";
        byte[] bytes = str.getBytes();
        int port=10086;
        InetAddress address = InetAddress.getByName("224.0.0.2");
        DatagramPacket dp=new DatagramPacket(bytes, bytes.length,address,port);
        ms.send(dp);
        ms.close();
    }
public class demon2 {
    public static void main(String[] args) throws Exception {
        MulticastSocket ms=new MulticastSocket(10086);
        //将本机添加到224.0.0.1这组
        InetAddress address = InetAddress.getByName("224.0.0.2");
        ms.joinGroup(address);
        byte[] bytes=new byte[1024];
        DatagramPacket dp=new DatagramPacket(bytes, bytes.length);
        ms.receive(dp);
        byte[] data = dp.getData();
        String name = dp.getAddress().getHostName();
        String ip = dp.getAddress().getHostAddress();
        int port = dp.getPort();
        int len = dp.getLength();
        System.out.println("ip为"+ip+",主机名为"+name+"的用户发送了:"+new String(data,0, len));
        ms.close();
    }
}

广播

广播地址:255.255.255.255

TCP协议

TCP是面向连接的通信协议

速度慢,没有大小限制,数据安全

 public static void main(String[] args) throws IOException {
        //创建Socket对象
        //细节:在创建的同时会连接服务端,如果连接不上就会报错
        Socket socket=new Socket("127.0.0.1",10086);
        //写数据
        OutputStream os = socket.getOutputStream();
        OutputStreamWriter osw=new OutputStreamWriter(os);
        osw.write("你好");
        //释放资源
        osw.close();
        socket.close();
    }
 public static void main(String[] args) throws Exception {
        //创建服务端ServerSocket对象
        ServerSocket ss=new ServerSocket(10086);
        //监听客户端链接
        Socket accept = ss.accept();
        //读数据
        InputStream is = accept.getInputStream();
        InputStreamReader isr=new InputStreamReader(is);
        int  b;
        while ((b=isr.read())!=-1){
            System.out.print((char) b);
        }
        //释放资源
        accept.close();
        ss.close();
    }

三次握手

确保连接建立

 四次挥手

确保连接断开

反射

反射允许对成员变量,成员方法和构造方法的信息进行编程访问

获取class对象的三种方式

第一种最常用
Class clazz1 = Class.forName("com.practice.Student");
        Class clazz2 = Student.class;
        Student s=new Student();
        Class clazz3 = s.getClass();

利用反射获取构造方法

 Class clazz = Class.forName("com.practice.Student");
        有Declared能获取全部,没有的只能获取public的
        获取全部
        Constructor[]  cons= clazz.getDeclaredConstructors();
        for (Constructor con : cons) {
            System.out.println(con);
        }

        获取指定
        Constructor con = clazz.getDeclaredConstructor(String.class,int.class);

        System.out.println(con);

        获取权限修饰符的值
        int modifiers = con.getModifiers();
        System.out.println(modifiers);
        获取构造方法所有的参数
        Parameter[] parameters = con.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        Constructor constructor = clazz.getDeclaredConstructor(String.class,int.class,String.class);
        取消临时校验
        constructor.setAccessible(true);
        创建一个对象
        Student stu = (Student)constructor.newInstance("zhangsan", 23,"1");
        System.out.println(stu);

利用反射获取成员变量

Class clazz = Class.forName("com.practice.Student");
        获取所有公共的成员变量
        Field[] fields = clazz.getFields();
        for (Field field : fields) {
            System.out.println(field);
        }
        获取指定的成员变量
        Field field = clazz.getDeclaredField("name");
        System.out.println(field);
        获取权限修饰符
        int modifiers = field.getModifiers();
        System.out.println(modifiers);
        获取成员变量名字
        String name = field.getName();
        System.out.println(name);
        获取成员变量的数据类型
        Class type = field.getType();
        System.out.println(type);
        获取成员变量记录的值
        Student s=new Student("zhangsan",23);
        field.setAccessible(true);
        String str =(String) field.get(s);
        System.out.println(str);
        修改成员变量的值
        field.set(s,"lisi");
        System.out.println(s);

利用反射获取成员方法

Class clazz=Class.forName("com.practice.Student");
        //获取公共的方法会包括父类Object里面的方法,而获得全部就只有本类的
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            System.out.println(method);
        }
        //获取指定的
        //clazz.getMethod("方法名",参数字节码有多少都要写);
        Method m = clazz.getMethod("toString");
        //获取方法修饰符
        int modifiers = m.getModifiers();
        System.out.println(modifiers);
        //获取方法形参
        Parameter[] parameters = m.getParameters();
        for (Parameter parameter : parameters) {
            System.out.println(parameter);
        }
        //获取异常类型
        Class[] exceptionTypes = m.getExceptionTypes();
        for (Class exceptionType : exceptionTypes) {
            System.out.println(exceptionType);
        }
        //方法运行
        Student s=new Student();
       // m.invoke("调用者s",如果有参数有多少要写多少个);如果有返回值可以接收

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值