关于java:JAVA编程

44次阅读

共计 19765 个字符,预计需要花费 50 分钟才能阅读完成。

@TOC

JAVA

简历:技术(10W)+ 我的项目(20W)+ 算法(30W) + 业务(50~100W) + 行业视线(上不封顶)

①JavaSE

JAVA 背景常识

JDK 装置和配置

程序的运行机制
  • Java 语言是编译型和解释型的联合

![[外链图片转存失败, 源站可能有防盗链机制, 倡议将图片保留失败, 源站可能有防盗 a 下来 img-E8Ie02)(C:\Ue10V-526\011027\AppData\Roaming\Typora\typora-user-images\image-2021480310176152570.pg6
9)(C:\Users\UC241027\AppData\Roaming\Typora\typora-user-images\image-20210310171652570.png)]](https://img-blog.csdnimg.cn/2…

  • JVM(Java Virtual Machine):它定义了指令集、寄存器集、构造栈、垃圾收集堆、内存区域,负责 java 字节码解释运行,边解释边运行,一次编译随处运行。

  • JRE(Java Runtime Environment):Java 虚拟机、库函数、运行 Java 应用程序必须的文件。
  • JDK(Java Development Kit):蕴含 JRE,以及减少编译器和调试器等用于程序开发的文件。

Java 装置与配置
  • 环境变量 Path 配置

    JAVA_HOME : JAVA 装置的目录

    Path:%JAVA_HOME%\bin

第一个 Java 程序

  • Java 编译的时候,呈现 unmappable character for encoding GBK

    解决办法:

    1、因为零碎默认编码不是 utf8,所以要将编译改写为 javac -encoding UTF-8 XXX.java 就能够失常输入

    2、将 XXX.java 文件另存为 –> 抉择编码 ANSI 保留

变量、数据类型、运算符

标识符

  • ASCⅡ字符集:12^8 = 256
  • Unicode 国内字符集:2^16 = 65536

变量

  • 变量实质是可操作的存储空间,空间地位是确定的,值不确定;变量名拜访“对应的存储空间”,操作这个“存储空间”存储的值
  • 局部变量、成员变量(也称实例变量)和动态变量

数据类型

  • boolean 类型是 4 个字节,数组中是 1 个字节(在内存中占 1 个字节或 4 个字节)
  • 数字格式化输入

System.out.format("%.3f %.3f\n",r,volume);

System.out.printf("%.3f %.3f\n",r,volume);

运算符

  • 整数运算:

    两数有一个为 long, 则后果为 long。

    没有 long 时,后果为 int。即便操作数全为 short、byte,后果也是 int。

  • 浮点运算:

    有一个为 long,后果为 long。

    两个为 float,后果才为 float。

  • 取模运算:

    个别应用整数,后果是”余数“,”余数“符号和右边雷同。

  • 自增、自减

    a++ // 先赋值,再自增

    ++a // 先自增,再赋值

  • 关系运算符

    \>、>=、<、<= 仅针对数值类型(byte/short/int/long,float/double 以及 char–>0~65535)

  • 逻辑运算符

  • 位运算符

  • 数据类型的转换

整型常量是 int 类型,然而能够主动转为:byte、short、char。只有不超过对应类型的范畴。

管制语句

  1. 管制语句分为:程序、抉择、循环;
  2. 任何软件和程序,实质上都是有 ” 变量、抉择语句、循环语句 ” 组成。

switch 语句

  • switch 语句中 case 标签在 JDK1.5 之前必须是整数(long 类型除外)或枚举,不能字符串,但在 JDK1.7 之后容许应用字符串

Scanner 类 键盘输入

  • java 中 Scanner 类 nextInt 之后用 nextLine 无奈读取输出

    问题呈现起因:

    这是因为在调用 nextLine()函数前调用了 Scanner 的另一个函数 nextInt()(或是 nextDouble())。呈现这种状况的起因是两个函数的解决机制不同,nextInt()函数在缓冲区中遇到“空格”、“回车符”等空白字符时会将空白字符前的数据读取走,但空白字符不会被解决掉,而 nextLine()函数是在缓冲区中读取一行数据,这行数据以“回车符”为完结标记,nextLine()会把包含回车符在内的数据提走。所以 nextInt()后的 nextLine()函数并非读取不到数据,因为 nextInt()将“回车符”留在了缓冲区,nextLine()读取时遇到的第一个字符便是“回车符”,所以间接完结了。

    解决办法:

    在要应用 nextLine()前先调用一次 nextLine(),这样留在缓冲区的“回车符”就会被解决掉,这时第二个 nextLine()函数能够失常读取到数据。

办法

办法重载(overload):理论是齐全不同的办法,只是名称雷同而已,释义:定义多个办法名雷同,但参数不同的办法。

  • 形成办法重载的条件:

    • 不同的含意:形参类型、形参个数、形参程序不同
    • 只有返回值不同不形成办法的重载(如:int a(String str){}与 void a(String str){}不形成办法重载)
    • 只有形参的名称不同,不形成办法的重载
  • 办法重写的三个要点:

面向对象编程

  1. 属性用于定义该类或该类对象蕴含的数据或者说动态特色。成员变量能够对其初始化,如果不对其初始化,Java 应用默认的值对其初始化。
  • 成员变量的默认值

  1. 结构器 4 个要点

  1. JAVA 虚拟机内存模型概念

  • 容易造成内存透露的操作

①. 创立大量无用对象
②. 动态汇合类的应用
③. 各种连贯对象(IO 流对象、数据库连贯对象、网络连接对象)未敞开
④. 监听器的应用

  1. 对象的申明周期
  • 创建对象四步

①. 调配对象空间,并将对象成员变量初始化为 0 或空
②. 执行属性值得显式初始化
③. 执行构造方法
④. 返回对象的地址给相干的变量

  • 应用

通过变量援用操作对象

  • 回收

对象咩有被变量应用,则被认为是”垃圾“, 会被垃圾回收器回收

this、static 关键字

this 关键字
  • 创立一个对象分为四步:


** this 的实质是“创立好的对象地址”,在构造方法调用前,对象曾经创立。因而,在构造方法中应用 this 示意 ” 以后对象 ”。

  • this 最常的用法

static 关键字

继承

继承的实现
  • 继承要点:
instanceof 运算符

instanceof 是二元运算符,右边是对象,左边是类;当对象是左边类或子类所创建对象时,返回 true; 反之为 false。

public class Person{
    String name;
    int age;
    
    public static void main(String[] args){Student s = new Student(“AAA”,66);
        System.out.println(s instanceof Person);
        System.out.println(s instanceof Student);
    }
}

class Student extends Person{}

办法的重写 override

子类通过重写父类的办法,能够用本身的行为替换父类的行为;办法的重写是实现多态的必要条件。

  • 办法重写须要合乎三个要点:

final 关键字

属性和办法前加 final,是不可扩大(继承)和更改的,办法不可重写,但可重载。

  • final 关键字的作用:

继承和组合

组合不同于继承,更加灵便。
组合的外围是将父类对象作为子类的属性,而后,子类通过调用这个属性来获取父类的属性和办法。

  • 组合:排汇或并购
public class Animal{public static void main(String[] args){Taidi t = new Taidi();
        t.dog.shout();}
}

class Dog{public void shout(){System.out.println("wangwang....");
    }
}

// 组合
class Taidi {Dog dog = new Dog(); //Taidi 蕴含(排汇)了 Dog, 所以具备了 Dog 的属性和办法
}

总结: 继承除了代码复用、也能不便咱们对事务建模。”is a“关系倡议应用继承,”has a“关系倡议应用组合。(如:Student is a Person 逻辑就没问题,但 Student has a Person 就有问题了;笔记本和芯片的关系属于蕴含,则能够应用”has a“)

super 关键字

  1. super 能够看做是间接父类对象的援用。通过 super 来拜访被子类笼罩的办法或属性。
  2. 应用 super 调用一般办法,语句没有地位限度,能够在子类中轻易调用。
  3. 若构造方法的第一行代码没有显式的调用 super()或者 this(); 那么 java 默认都会调用 super(), 含意是调用父类的无参数构造方法。super()可省略。

继承树追溯

封装(encapsulation)

  • 封装的具体的长处

  • 封装的实现 — 应用拜访控制符

+ protected 须要留神的两个细节

多态

多态指的是同一个办法调用,因为对象不同可能会有不同的行为。

  • 多态的要点

  • 多态的必要三个条件
  1. 继承
  2. 重写
  3. 父类援用指向子类对象
  • 类型的强制转化,分编译和运行,编译看右边,编译之后是什么类型就执行什么样的办法;运行看左边。

形象办法和抽象类

abstract 润饰的办法,没有办法体,只有申明。定义的是一种 ” 标准 ”,就是通知子类必须要给形象办法提供具体的实现。

  • 抽象类的应用要点:

接口 interface

  1. 面向对象的精华,是对对象的形象,最能体现这一点的就是接口。
  2. 接口就是比 ” 抽象类 ” 还 ” 形象 ” 的 ” 抽象类 ”。(abstract)
  3. 接口就是定规范的,就是要让他人实现的。(public)
  4. 接口申明办法的时候能够不写 public 和 abstract,默认是有的。
  5. 接口定义的是不变的,如变量只能定义为常量。能够不写 public abtract final 来润饰变量,默认是有的。

定义接口的具体阐明:

区别:

  • 一般类:具体实现
  • 抽象类:具体实现,标准(形象办法)
  • 接口:JDK1.8 之前只有标准,但 JDK1.8 之后新增了静态方法和默认办法

    • 默认办法:
      默认办法和形象办法的区别是形象办法必须要被实现,因为默认办法有办法体,所以不须要实现,在接口中 default 必须要写,通过实现类的对象调用。
    • 静态方法:
      能够在接口中间接定义静态方法的实现。这个静态方法间接从属于接口(接口也是类,一种非凡的类),能够通过接口名调用。
接口的多继承

接口齐全反对多继承,和类的继承相似,子接口扩大某个父接口,将会取得父接口中所定义的所有。

字符串 String 类详解

字符串 String 是在办法区的字符串常量池(String Pool)中存储

String 类和常量池
  • 常量池分三种:

  • String 根底

外部类

  • 外部类:
  1. 定义在一个类的外部的类,目标是方便使用外部类的相干属性和办法;
  2. 外部类只是一个编译时概念,一旦编译胜利,就会成为齐全不同的两个类。

  • 外部类作用

  • 外部类的分类

  1. 非动态外部类
// 外部类
public class Outer {
    private int age = 10;

    private void show(){System.out.println("good!!!");
    }

    // 非动态外部类
    public class Inner{
        private String name = "tom";
        private int age = 20;

        public void showInner(){System.out.println("Inner.showInner");
            System.out.println(age);
            System.out.println(Outer.this.age);
            show();}
    }

    public static void main(String[] args) {Outer.Inner inner = new Outer().new Inner();    // 通过 new 外部类名(). 外部类名() 来创立外部类对象
        inner.showInner();}
}
  1. 动态外部类

// 外部类
public class Outer {
    private int a = 10;
    private static int b = 20;

    // 动态外部类
    static class Inner{public void test(){System.out.println(b);
        }
    }

    public static void main(String[] args) {Outer.Inner inner = new Outer.Inner();    // 通过 new 外部类名. 外部类名() 来创立外部类对象
        inner.test();}
}
  1. 匿名外部类

适宜那种只须要应用一次的类。

public class AnonymousInnerClass {public void test(A a){a.run();
    }

    public static void main(String[] args) {AnonymousInnerClass anonymousInnerClass = new AnonymousInnerClass();
        // 匿名外部类
        anonymousInnerClass.test(new A() {
            @Override
            public void run() {System.out.println("匿名外部类是没有名字的类,只需应用一次;如果从新调用一次,就会定义新的匿名外部类!");
            }
        });
    }
}

interface A{void run();
}
  1. 部分外部类

定义在办法外部的,作用域只限于本办法。

public class LocalInnerClass{public void show(){
        // 作用域仅限于该办法
        class Inner{public void fun(){System.out.println("部分外部类的实现!");
            }
        }
        new Inner().fun();
    }

    public static void main(String[] args){new LocalInnerClass().show();}
}

数组

数组:雷同类型数据的有序汇合,数组也是对象。

  • 数组的四个根本特点

数组初始化

  • 1、数组动态初始化

例如:
int[] a = {1,2,3}; // 动态初始化根本类型数组
Man[] mans = {new Man(1,1),new Man(2,2)}; // 动态初始化援用类型数组

  • 2、数组动静初始化

例如:
int[] a = new int[2]; // 动静初始化数组,先调配空间
a[0] = 1; // 给数组元素赋值
a[1] = 2; // 给数组元素赋值

  • 3、数组的默认初始化

例如:
int[] a = new int[2]; // 默认值:0,0
boolean[] b = new boolean[2]; // 默认值:false,false
String[] s = new String[2]; // 默认值:null,null

总结:默认初始化 —-> 数组元素相当于对象的属性,恪守对象属性默认初始化的规定。

异样机制

当程序呈现谬误,程序平安的、继续执行的机制。

JAVA 罕用类

Wrapper 包装类

包装类:能够把根本类型、包装类对象、字符串三者进行互相转化

  • 主动装箱和拆箱

  • 包装类的缓存问题

当数字在 [-128,127] 之间的时候,返回缓存数组中的某个元素。

public class Test{public static void main(String[] args){// 当数字在 [-128,127] 之间的时候,返回的是缓存数组中的某个元素
        Integer i1 = 123; // 主动装箱;编译器:Integer i1 = Integer.valueOf(123);
        Integer i2 = 123; // 主动装箱;编译器:Integer i1 = Integer.valueOf(123);
        
        System.out.println(i1 == i2);  // true; 是因为 123 都是从缓存中取的同一个元素
        System.out.println(i1.equals(i2)); // true
    }
}

字符串相干类

String 类:不可变字符序列,会产生新对象的。
StringBuilder 类:可变字符序列;效率高,然而线程不平安;增加字符序列,返回本身对象。
StringBuffer 类:可变字符序列;效率低,然而线程平安;增加字符序列,返回本身对象。

  • String 类
public class Test{public static void main(String[] args){
        // 编译器做了优化,在编译的时候,左边是字符串常量, 不是变量,所以间接将字符串做了拼接
        String str1 = "hello" + "java";    // 相当于 str1 = "hello java";
        String str2 = "hello java";
        
        System.out.println(str1 == str2);    //true

        String str3 = "hello";
        String str4 = "java";

        // 编译的时候不晓得变量中存储的是什么,所以没方法在编辑的时候做优化
        String str5 = str3 + str4;

        System.out.println(str2 == str5);    //false
    }
}
  • 效率测试
public class Test {public static void main(String[] args) {
        String str = "";

        long num1 = Runtime.getRuntime().freeMemory();
        long time1 = System.currentTimeMillis();

        for(int i = 0;i < 5000;i++){str += i;}

        long num2 = Runtime.getRuntime().freeMemory();
        long time2 = System.currentTimeMillis();

        System.out.println("String 占用内存:" + (num1 - num2));
        System.out.println("String 占用工夫:" + (time2 - time1));

        System.out.println("===================================");

        StringBuilder sb = new StringBuilder("");

        long num3 = Runtime.getRuntime().freeMemory();
        long time3 = System.currentTimeMillis();

        for(int i = 0;i < 5000;i++){sb.append(i);
        }

        long num4 = Runtime.getRuntime().freeMemory();
        long time4 = System.currentTimeMillis();

        System.out.println("StringBuilder 占用内存:" + (num3 - num4));
        System.out.println("StringBuilder 占用工夫:" + (time4 - time3));

        System.out.println("===================================");

        StringBuffer sb2 = new StringBuffer("");

        long num5 = Runtime.getRuntime().freeMemory();
        long time5 = System.currentTimeMillis();

        for(int i = 0;i < 5000;i++){sb2.append(i);
        }

        long num6 = Runtime.getRuntime().freeMemory();
        long time6 = System.currentTimeMillis();

        System.out.println("StringBuffer 占用内存;" + (num5 - num6));
        System.out.println("StringBuffer 占用工夫:" + (time6 - time5));
    }
}

效率测试后果如下:

File 类

java.io.File 类:代表文件和目录。

枚举

枚举类型隐形地继承自 java.lang.Enum。枚举本质上还是类,而每个被枚举的成员本质就是一个枚举类型的实例。他们默认都是 public static final 润饰的。能够间接通过枚举类型名应用。

enum 枚举名 {枚举体(常量列表)}
  • 特地留神:

汇合(容器)

泛型

泛型简介

泛型是将类型基于一个占位符模式来定义,在泛型中,不能够应用根本类型,只能用对象类型来定义泛型。

  • 泛型的益处:

总结一下:

  • 类型擦除

编译时采纳泛型写的类型参数,编译器会在编译时去掉。

泛型的应用
  • 定义泛型

  • 泛型类

泛型类是把泛型定义在类上。

  • 泛型接口

泛型接口和泛型类的申明形式统一。泛型接口的具体类型须要在实现类中进行申明。

  • 泛型办法

泛型办法是指将办法的参数类型定义成泛型,以便在调用时承受不同类型的参数。类型参数能够有多个,用逗号隔开,如:<K,V>。类型参数个别放到返回值后面。

+ 非静态方法

+ 静态方法

静态方法无法访问类上定义的泛型;如果静态方法操作的援用数据类型不确定的时候,必须要将泛型定义在办法上。

  • 泛型办法与可变参数

在泛型办法中,泛型也能够定义可变参数类型。

  • 通配符和高低限定

    • 无界通配符


+ 通配符的下限限定

下限限定示意通配符的类型是 T 类以及 T 类的子类或者 T 接口以及 T 接口的子接口。

+ 通配符的上限限定

上限限定示意通配符的类型是 T 类以及 T 类的父类或者 T 接口以及 T 接口的父接口。该办法不实用泛型类。

  • 泛型总结

容器

数组也是一种容器,能够搁置对象或根本类型数据

  • 数组的劣势:是一种简略的线性序列,能够疾速地拜访数组元素,效率高。仅从效率和类型查看的角度讲,数组是最好的。
  • 数组的劣势:不灵便。容量须要当时定义好,不能随着需要的辩护而扩容。


总之,容器的底层都是基于数组来实现的。容器中数据都是存储在内存的。

List

List:有序(元素存入汇合的程序和取出的程序统一)、可反复

  • ArrayList 是 List 接口的实现类。是 List 存储特色的具体实现。
  • ArrayList 底层是用数组实现的存储。特点:查问效率高、增删效率低、线程不平安。
  • ArrayList:提早扩容,如要扩容以 1.5 倍扩容。
Vector

Vector:底层应用数组实现的。线程平安,效率低。Vector 的应用与 ArrayList 是雷同的。初始容量是 10,如要扩容以 2 倍扩容。

Stack

Stack:栈容器,是 Vector 的一个子类,它实现了一个规范的后进先出(LIFO:Last In First Out)的栈。

  • 栈的操作

// 栈容器应用案例
public class StackTest {public static void main(String[] args) {StackTest st = new StackTest();
        st.symmetry();}

    // 匹配符号的对称性
    public void symmetry(){String str = "...{.....[....(....)....]....}..(....)..[...]...";

        // 实例化 Stack
        Stack<String> stack = new Stack<>();

        // 假如修改法
        boolean flag = true; // 假如是匹配的

        // 拆分字符串获取字符
        for(int i = 0;i < str.length();i++){char c = str.charAt(i);
            if(c == '{'){stack.push("}");
            }
            if(c == '['){stack.push("]");
            }
            if(c == '('){stack.push(")");
            }

            // 判断符号是否匹配
            if(c == '}'||c == ']'||c == ')'){if(stack.empty()){
                    flag = false;
                    break;
                }
                
                String x = stack.pop();

                if(x.charAt(0) != c){
                    flag = false;
                    break;
                }
            }
        }
        if(!stack.empty()){flag = false;}
        System.out.println(flag);
    }
}
LinkedList
  1. 底层用双向链表实现的存储。特点:查问效率低,增删效率高,线程不平安。
  2. 实现了 List 接口,所以 LinkedList 是具备 List 的存储特色的(有序,元素有反复)
Set

Set 特点:无序,不可反复。无序指 Set 中的元素没有索引,只能遍历查找;不可反复指不容许退出反复的元素。

HashSet
  • HashSet:是一个没有反复元素的汇合,不保障元素的程序,线程不平安。容许有 null 元素;采纳哈希算法实现,底层是用 HashMap 实现的,HashMap 底层应用的是数组与链表实现元素的存储。查问效率和增删效率比拟高。Hash 算法也称之为散列算法。

无序:

不反复:

TreeSet

  • 通过元素本身实现比拟规定

  • 通过比拟器指定比拟规定

Map

Map 接口定义了双例汇合的存储特色,它不是 Collection 接口的子接口。双例汇合的存储特色是以 key 与 value 构造为单位进行存储的。

  • Map 与 Collection 的区别

HashMap

  • HashMap 的底层源码


TreeMap

Iterator 迭代器

  • Iterator 对象的工作原理

Collections 工具类

数据结构

数据结构是以某种特定的布局形式存储数据(存储构造上差别)的容器。

  • 数据结构逻辑分类
  1. 线性构造:元素存在一对一的互相关系

线性表、栈、队列、串(一堆数组)等

  1. 树形构造:元素存在一对多的互相关系

二叉树、红黑树、B 树、哈夫曼树等

  1. 图形构造:元素存在多对多的互相关系

有向图、无向图、简略图等

线性构造

栈构造

栈是一种只能从一端存取数据且遵循 ” 后进先出(LIFO)” 准则的线性存储构造

链表构造

链表构造是由许多节点形成的,每个节点都蕴含两局部:

  • 链表分类

单向链表
双向链表
双向循环链表

  • 链表的特点

  • 链表的优缺点

单向链表构造

双向链表构造

树形构造

  • 节点

应用树结构存储的每一个数据元素都被称为“结点”。

  • 节点的度

某个结点所领有的子树的个数

  • 树的深度

树中节点的做大档次数

  • 叶子结点

度为 0 的结点,也叫终端结点。

  • 分支结点

度不为 0 的结点,也叫非终端结点或外部结点。

  • 孩子

也可称之为子树或者子结点,示意以后节点上层的间接结点。

  • 双亲

也可称之为父结点,示意以后结点的间接下层结点。

  • 根节点

没有双亲结点的结点。在一个树形构造中只有一个根节点。

  • 先人

从以后结点下层的所有结点。

  • 子孙

以后结点上层的所有结点。

  • 兄弟

同一双亲的孩子。

二叉树

满二叉树


齐全二叉树


二叉树遍历






正则表达式

Java 中正则表达式为 String 类型,被验证的内容同样为 String 类型。通过 String 类中的 matches 办法实现内容的匹配校验。如:”被验证内容“.matches(“ 正则表达式 ”)

在定义限定内容规定是,如果没有指定长度限定,那么默认长度为 1。

内容限定

  • 单个字符限定

[a]:示意以后内容必须是字母 a

  • 范畴字符限定

[a-z0-9]:示意内容能够是 a - z 之间的任意字母或者 0 - 9 之间的任意数字,不分先后

  • 取反限定

[^abc]:示意内容不能是 a 或 b 或 c。

长度限定

长度限定符号

预约义字符

在正则表达式中能够通过一些预约义字符来示意内容限定。目标是为了简化内容限定的定义

组合定义

通过多个内容限定与长度限定来组合定义

常见的正则表达式

|:或者,如:a|b (a 或 b)
\\.:任意字符,如:-|\\. (- 或任意一个字符)

IO 流

  • 数据源:提供数据的原始媒介。常见的数据源有:数据库、文件、其余程序、内存、网络连接、IO 设施。

  • 流:形象、动静的概念,是一连串间断动静的数据汇合。

输出流:数据流从数据源到程序(InputStream、Reader 结尾的流)

输入流:数据流从程序到目的地(OutputStream、Writer 结尾的流)

  • JAVA 中四大 IO 抽象类

InputStream/OutputStream 和 Reader/Writer 类是所有 IO 类的形象父类

InputStream: 字节输出流
OutputStream: 字节输入流
Reader: 读取的字符流抽象类,数据单位为字符
Writer: 输入的字符流抽象类,数据单位为字符

  • Java 中流的细分

按流的方向分类:

输出流:InputStream、Reader 结尾的流
输入流:OutputStream、Writer 结尾的流

按解决的数据单元分类:

字节流:以字节为单位获取数据,FileInputStream、FileOutputStream
字符流:以字符为单位获取数据,Reader/Writer 结尾的流,如 FIleReader、FileWriter

按解决对象不同分类

节点流:间接从数据源或目的地读写数据,如:FileInputStream、FileReader、DataInputStream
解决流:也叫包装流,不间接连贯到数据源或目的地,是”解决流的流“。通过对其余流的解决进步程序的性能,如:BufferedInputStream、BufferedReader。

  • 通过字节缓冲流进步读写效率


总结:



  • File 类

File 类是 Java 提供的针对磁盘中的文件或目录转换对象的包装类。一个 File 对象能够代表一个文件或目录。

文件字节流

通过缓冲区进步读写效率

形式一:

public class FileDemo {public static void main(String[] args) throws Exception{try(FileInputStream fis = new FileInputStream("images/s1.jpg");
            FileOutputStream fos = new FileOutputStream("images/11.jpg");
        ){
            // 创立一个缓冲区
            byte[] buff = new byte[1024]; // 空间换效率, 效率低,但空间节俭。int len = 0;

            while((len = fis.read(buff)) != -1){fos.write(buff,0,len);
            }
            fos.flush();}catch (Exception e){e.printStackTrace();
        }
    }
}

形式二:

public class FileDemo {public static void main(String[] args) throws Exception{try(FileInputStream fis = new FileInputStream("images/s1.jpg");
            FileOutputStream fos = new FileOutputStream("images/11.jpg");
        ){
            // 创立一个缓冲区
            byte[] buff = new byte[fis.available()]; // 效率换空间,占内存,但效率快

            fis.read(buff);
            fos.write(buff);
            fos.flush();}catch (Exception e){e.printStackTrace();
        }
    }
}
通过字节缓冲流进步读写效率

public class FileCopyTools {public static void main(String[] args) {copyFile("images/s1.jpg","images/11.jpg");
    }

    /**
     * 文件拷贝办法
     */
    public static void copyFile(String src,String des){try(BufferedInputStream bis = new BufferedInputStream(new FileInputStream(src));
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(des));
        ){
            int temp = 0;
            while((temp = bis.read()) != -1){bos.write(temp);
            }
            bos.flush();} catch (Exception e){e.printStackTrace();
        }
    }
}

文件字符流

  • 如果一个一个字符读取,后果是 Unicode 字符,需将后果强转 char 才能看懂数据内容。
  • 如果是字符输入流,创立了两个字符输入流并同时向同一个文件输入内容,默认是会笼罩。除非加参数 true, 能力追加。

字符缓冲流

字符输出缓冲流

字符输入缓冲流

转换流

InputStreamReader/OutputStreamWriter 用来实现将字节流转化成字符流。

字符输入流

  • PrintWriter: 是节点流,能够间接作用于文件的。

字节数组流

字节数组输出流(ByteArrayInputStream)
  • ByteArrayInputStream : 则是把内存的 ” 字节数组对象 ” 当做数据源。
  • FileInputStream:是把文件当做数据源。
字节数组输入流(ByteArrayOutputStream)
  • ByteArrayOutputStream:将流中的数据写入到字节数组中。
public class ByteArrayOutputStreamDemo {public static void main(String[] args) {
        ByteArrayOutputStream bos = null;
        StringBuilder sb = new StringBuilder();
        try{bos = new ByteArrayOutputStream();

           bos.write('a');
           bos.write('b');
           bos.write('c');

           byte[] arr = bos.toByteArray();

           for(int i = 0;i < arr.length;i++){sb.append((char)arr[i]);
           }

            System.out.println(sb.toString());
        }finally{
            try{if(bos != null){bos.close();
                }
            }catch (Exception e){e.printStackTrace();
            }
        }
    }
}

数据流

  • DataInputStream 和 DataOutputStream 提供了能够存取与机器无关的所有 Java 根底类型数据(如:int、double、String 等)。
数据输入流
// 数据输入流
public class DataIOStreamDemo {public static void main(String[] args) {try(DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream("data.txt")));){dos.writeChar('a');
            dos.writeInt(4);
            dos.writeDouble(Math.random());
            dos.writeUTF("您好");
            dos.flush();}catch (Exception e){e.printStackTrace();
        }

    }
}
数据输出流

读取的程序要与数据输入流写入的程序统一,否则不能读取数据

// 数据输出流
public class DataIOStreamDemo {public static void main(String[] args) {try(DataInputStream dis = new DataInputStream(new BufferedInputStream(new FileInputStream("data.txt")));){
            // 间接读取数据,留神:读取的程序要与写入的程序统一,否则不能读取数据
            System.out.println("char:" + dis.readChar());
            System.out.println("int:" + dis.readInt());
            System.out.println("double:" + dis.readDouble());
            System.out.println("utf:" + dis.readUTF());
        }catch (Exception e){e.printStackTrace();
        }
    }
}

对象流

数据流只能实现对根本数据类型和字符串类型的读写,并不能 Java 对象进行读写操作(字符串除外),而对象流除了能实现对根本数据类型进行读写操作,还能对 Java 对象进行读写操作。

  • 对象的序列化和反序列化

序列化

对象的序列化:把 java 对象转换为字节序列的过程。

  • 对象序列化的作用

  • 序列化波及的类和接口

import java.io.BufferedOutputStream;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;

// 对象输入流实现根本数据类型的输入
public class ObjectIOStreamDemo {public static void main(String[] args) {try(ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream("data")));){oos.writeInt(10);
            oos.writeDouble(Math.random());
            oos.writeChar('a');
            oos.writeBoolean(true);
        }catch (Exception e){e.printStackTrace();
        }
    }
}
  • 将对象序列化到文件

反序列化

对象的反序列化:字节序列复原为 Java 对象的过程。

随机拜访流

  • 外围办法

多线程

程序:

过程:

  • 过程特点



线程:


  • 线程和过程的区别


  • 并发

  • 办法的执行特点()
  • 线程的执行办法的特点

  • 主线程

+ 主线程的特点

它是产生其余子线程的线程。
它不肯定是最初实现执行的线程,子线程可能在它完结之后还在运行。

  • 主线程

在主线程中创立并启动的线程,个别称之为子线程。

线程的创立

通过继承 Thread 类实现多线程

通过实现 Runnable 接口实现多线程
线程的执行流程

线程的生命周期

  • 新生状态

  • 就绪状态


  • 运行状态

  • 阻塞状态

  • 死亡状态


线程的应用

终止线程

import java.io.IOException;

public class StopThread implements Runnable{
    private boolean flag = true;

    @Override
    public void run() {System.out.println(Thread.currentThread().getName() + "线程开始");

        int i = 0;
        while(flag){System.out.println(Thread.currentThread().getName() + " " + i++);
            try {Thread.sleep(1000);
            } catch (InterruptedException e) {e.printStackTrace();
            }
        }

        System.out.println(Thread.currentThread().getName() + "线程完结");
    }

    // 劝本人他杀形式终止线程, 线程能失常完结。public void stop(){this.flag = false;}

    public static void main(String[] args) throws IOException {System.out.println("主线程开始");

        StopThread st = new StopThread();

        Thread t1 = new Thread(st);

        // 启动线程
        t1.start();

        System.in.read();

        st.stop();

        System.out.println("主线程完结");
    }
}
  • 暂停以后线程执行 sleep/yield

+ yield 办法的应用

线程联结

  • join 办法的应用

class A implements Runnable{
    @Override
    public void run() {for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + " " + i);
            try {Thread.sleep(1000);
            } catch (InterruptedException e) {e.printStackTrace();
            }
        }
    }
}

public class JoinThread {public static void main(String[] args) throws InterruptedException {Thread t = new Thread(new A());
        
        // 启动 A 线程
        t.start();
        
        // 主线程
        for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + " " + i);
            
            // 当 i = 2 时,主线程期待 A 线程完结之后再运行
            if(i == 2){t.join();
            }
            Thread.sleep(1000);
        }
    }
}
Thread 类罕用办法
  • 获取以后线程名称

  • 判断以后线程是否存活

线程优先级

守护线程


  • 守护线程的特点:守护线程会随着用户线程死亡而死亡。
  • 守护线程与用户线程的区别

线程同步(就是把并行改成串行)

synchronized 可阻止并发更新同一个共享资源,实现了同步,然而 synchronized 不能用来实现不同线程之间的消息传递(通信)。

实现线程同步

  • synchronized 关键字应用时须要思考的问题:

> ![在这里插入图片形容](https://img-blog.csdnimg.cn/2021032109123238.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpdV90b19saXU=,size_16,color_FFFFFF,t_70)

> ![在这里插入图片形容](https://img-blog.csdnimg.cn/20210321091356173.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2xpdV90b19saXU=,size_16,color_FFFFFF,t_70)
线程同步的应用
应用 this 作为线程对象锁

在不同线程中雷同对象中 synchronized 会互斥。

语法结构:

synchronized(this){// 同步代码}

public synchronized void accessVal(int newVal){}
应用字符串作为线程对象锁

所有线程在执行 synchronized 时都会同步。因字符串是不变序列,所以会持有雷同锁。

synchronized("字符串"){// 同步代码}
应用 Class 作为线程对象锁

在不同线程中,领有雷同 Class 对象中的 synchronized 会互斥。

synchronized(XX.class){// 同步代码}

synchronized public static void accessVal(){// 同步代码}
应用自定义对象作为线程对象锁

在不同线程中,领有雷同自定义对象中的 synchronized 会互斥。放在线程中造成互斥锁。

synchronized(自定义对象){// 同步代码}
死锁及解决方案

死锁是因为同一代码块呈现嵌套 synchronized 造成的,解决办法是避免出现嵌套 synchronized 语句块。

线程并发合作(生产者 / 消费者模式)

  • 角色:

    生产者:负责生产数据的模块
    消费者:负责解决数据的模块
    缓冲区:消费者不能间接应用生产者数据,它们之间有个“缓冲区”。生产者将生产好的数据放入“缓冲区”,消费者从“缓冲区”拿要解决的数据。

    缓冲区的益处:

  • wait() 办法:要在 synchronized 块中调用,该办法执行后,线程会将持有的对象锁开释,并进入阻塞状态,其余须要该对象锁的线程就能够持续运行了。
  • notify() 办法:要在在 synchronized 块中调用,该办法执行后,会唤醒处于期待状态队列中的一个线程
/**
 * 定义馒头类
 */
class ManTou{
    private int id;

    public ManTou(int id){this.id = id;}

    public int getId(){return this.id;}
}

/**
 * 定义缓冲类
 */
class SyncStack{
    // 定义放馒头的盒子
    private ManTou[] mt = new ManTou[10];

    // 定义盒子的 suoyin
    private int index;

    /**
     * 放馒头
     */
    public synchronized void push(ManTou manTou){while(this.index == this.mt.length){
            try {
                // 该办法执行后,线程会将持有的对象锁开释,并进入阻塞状态,其余须要该对象锁的线程就能够持续运行了。this.wait();} catch (InterruptedException e) {e.printStackTrace();
            }
        }

        this.notify(); // 该办法执行后,会唤醒处于期待状态队列中的一个线程
        this.mt[this.index] = manTou;
        this.index++;
    }

    /**
     * 取馒头
     */
    public synchronized ManTou pop(){while(this.index == 0){
            try {
                // 该办法执行后,线程会将持有的对象锁开释,并进入阻塞状态,其余须要该对象锁的线程就能够持续运行了。this.wait();} catch (InterruptedException e) {e.printStackTrace();
            }
        }

        this.notify(); // 该办法执行后,会唤醒处于期待状态队列中的一个线程
        this.index--;
        return this.mt[this.index];
    }
}

/**
 * 定义生产者线程
 */
class Producer extends Thread{
    private SyncStack ss;

    public Producer(SyncStack ss){this.ss = ss;}

    @Override
    public void run() {for (int i = 0; i < 10; i++) {System.out.println("生产馒头:" + i);

            ManTou manTou = new ManTou(i);
            this.ss.push(manTou);
        }
    }
}

/**
 * 定义消费者线程
 */
class Customer extends Thread{
    private SyncStack ss;

    public Customer(SyncStack ss){this.ss = ss;}

    @Override
    public void run() {for (int i = 0;i < 10;i++) {ManTou manTou = this.ss.pop();

            System.out.println("生产馒头:" + i);
        }
    }
}

public class ProduceThread {public static void main(String[] args) {SyncStack ss = new SyncStack();

        new Thread(new Producer(ss)).start();
        new Thread(new Customer(ss)).start();}
}

线程并发合作总结

  • 线程通过哪些办法来进行消息传递,总结如下:

下列的办法均是 java.lang.Object 类的办法,都只能在同步办法或者同步代码块中应用,否则会抛出异样。

网络编程

网络通信协定

OSI 七层协定模型:别离是:应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。

TCP/IP 协定

应用层、传输层、互联网络层、网络接口层(物理 + 数据链路层)

  • 传输过程中,会波及到封装和解封




总结:发送数据必须同时指定 IP 地址和端口。
#### URL(Uniform Resource Locator)
在 www 上,每一信息资源都有对立且惟一的地址。URL 由四局部组成:协定、寄存资源的主机域名、被迫文件和端口号。
#### Socket

#### TCP 和 UDP 协定

TCP 协定

UDP 协定

网络编程中罕用类

  • InetAddress 类:封装计算机的 IP 地址和域名。没有构造方法,如果要失去对象,只能通过 getLocalHost()、getByName()等静态方法创建对象。
  • InetSocketAddress 类:蕴含 IP 和端口信息,罕用于 Socket 通信。此类实现 IP 套接字地址(IP 地址 + 端口号), 不依赖任何协定。相比于 InetAddress 多了端口号。
  • URL 类:标识了计算机的资源,它是指向互联网“资源”的指针。(IP 地址标识了 Internet 上惟一的计算机)

TCP 通信实现

  • 申请 - 响应 模式

Socket 类:发送 TCP 音讯
ServerSocket 类:创立服务器

  • Socket 的编程程序

UDP 通信实现

  • DatagramPacket:数据容器(封包)的作用

示意数据报包。数据报包用来实现将发送的数据进行封包解决的。

正文完
 0