共计 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。只有不超过对应类型的范畴。
管制语句
- 管制语句分为:程序、抉择、循环;
- 任何软件和程序,实质上都是有 ” 变量、抉择语句、循环语句 ” 组成。
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){}不形成办法重载)
- 只有形参的名称不同,不形成办法的重载
- 办法重写的三个要点:
面向对象编程
- 属性用于定义该类或该类对象蕴含的数据或者说动态特色。成员变量能够对其初始化,如果不对其初始化,Java 应用默认的值对其初始化。
- 成员变量的默认值
- 结构器 4 个要点
- JAVA 虚拟机内存模型概念
- 容易造成内存透露的操作
①. 创立大量无用对象
②. 动态汇合类的应用
③. 各种连贯对象(IO 流对象、数据库连贯对象、网络连接对象)未敞开
④. 监听器的应用
- 对象的申明周期
- 创建对象四步
①. 调配对象空间,并将对象成员变量初始化为 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 关键字
- super 能够看做是间接父类对象的援用。通过 super 来拜访被子类笼罩的办法或属性。
- 应用 super 调用一般办法,语句没有地位限度,能够在子类中轻易调用。
- 若构造方法的第一行代码没有显式的调用 super()或者 this(); 那么 java 默认都会调用 super(), 含意是调用父类的无参数构造方法。super()可省略。
继承树追溯
封装(encapsulation)
- 封装的具体的长处
- 封装的实现 — 应用拜访控制符
+ protected 须要留神的两个细节
多态
多态指的是同一个办法调用,因为对象不同可能会有不同的行为。
- 多态的要点
- 多态的必要三个条件
- 继承
- 重写
- 父类援用指向子类对象
- 类型的强制转化,分编译和运行,编译看右边,编译之后是什么类型就执行什么样的办法;运行看左边。
形象办法和抽象类
abstract 润饰的办法,没有办法体,只有申明。定义的是一种 ” 标准 ”,就是通知子类必须要给形象办法提供具体的实现。
- 抽象类的应用要点:
接口 interface
- 面向对象的精华,是对对象的形象,最能体现这一点的就是接口。
- 接口就是比 ” 抽象类 ” 还 ” 形象 ” 的 ” 抽象类 ”。(abstract)
- 接口就是定规范的,就是要让他人实现的。(public)
- 接口申明办法的时候能够不写 public 和 abstract,默认是有的。
- 接口定义的是不变的,如变量只能定义为常量。能够不写 public abtract final 来润饰变量,默认是有的。
定义接口的具体阐明:
区别:
- 一般类:具体实现
- 抽象类:具体实现,标准(形象办法)
-
接口:JDK1.8 之前只有标准,但 JDK1.8 之后新增了静态方法和默认办法
- 默认办法:
默认办法和形象办法的区别是形象办法必须要被实现,因为默认办法有办法体,所以不须要实现,在接口中 default 必须要写,通过实现类的对象调用。 - 静态方法:
能够在接口中间接定义静态方法的实现。这个静态方法间接从属于接口(接口也是类,一种非凡的类),能够通过接口名调用。
- 默认办法:
接口的多继承
接口齐全反对多继承,和类的继承相似,子接口扩大某个父接口,将会取得父接口中所定义的所有。
字符串 String 类详解
字符串 String 是在办法区的字符串常量池(String Pool)中存储
String 类和常量池
- 常量池分三种:
- String 根底
外部类
- 外部类:
- 定义在一个类的外部的类,目标是方便使用外部类的相干属性和办法;
- 外部类只是一个编译时概念,一旦编译胜利,就会成为齐全不同的两个类。
- 外部类作用
- 外部类的分类
- 非动态外部类
// 外部类
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();}
}
- 动态外部类
// 外部类
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();}
}
- 匿名外部类
适宜那种只须要应用一次的类。
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();
}
- 部分外部类
定义在办法外部的,作用域只限于本办法。
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
- 底层用双向链表实现的存储。特点:查问效率低,增删效率高,线程不平安。
- 实现了 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 工具类
数据结构
数据结构是以某种特定的布局形式存储数据(存储构造上差别)的容器。
- 数据结构逻辑分类
- 线性构造:元素存在一对一的互相关系
线性表、栈、队列、串(一堆数组)等
- 树形构造:元素存在一对多的互相关系
二叉树、红黑树、B 树、哈夫曼树等
- 图形构造:元素存在多对多的互相关系
有向图、无向图、简略图等
线性构造
栈构造
栈是一种只能从一端存取数据且遵循 ” 后进先出(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:数据容器(封包)的作用
示意数据报包。数据报包用来实现将发送的数据进行封包解决的。