你都是会点啥技术(四)— Java
写在前面的话:到2019年6月份为止,真正使用java有两年了,在大学期间老师教过一遍java(学的不好),看过两三个老师讲解的java视频,每次学习都会有新的体验和收获,也读过《java编程思想》和《深入理解Java虚拟机》,从我对我自己的审视来看,万万不敢说掌握了java这门语言,这次是把java从基础到高级梳理一遍,一方面是对java知识回顾,一方面补充工作中遇到的问题,理论和实践相结合吧, 我想这肯定对我的java功底有一个很大的提升。这次总结也算给自己的java基础画一个小小的句号。。。让我踏着java去开拓更广阔的领域去吧。重点:集合 IO 线程
链接:https://pan.baidu.com/s/1u58CBOZwX7qZzL1byKlMXQ
提取码:4zk3
做饭之前需要准备好厨房(生产环境)和厨具,对于java来说,JDK就是做饭的厨房(生产环境),厨具的话流行的有Eclipse,Idea,拿蒸米饭来说,使用高压锅比使用普通铁锅,不仅节省时间而且还不容易糊,还可以让你做米饭事半功倍。
Java初学者必须面对的一步,就是Java JDK的安装及环境变量配置了,这步还没有熟练和掌握的可以参考
JDK下载安装和环境变量作用的详解。
一个简单的java程序的基本要素有:标识符、关键字、注释、修饰符、语句、块、类以及 main() 方法。
我们的java程序就是是靠着这些基本要素按照规范组合使用!
拓展点:
1.java程序的运行过程。
2.jdk,jre,jvm区别。
3.判断标识符是否合法。
4.修饰符的作用。
实战:
1.main方法传值。
厨房(生产环境)和厨具准备好了,做一顿美味的菜。佐料是必不可少的,每种佐料都能发挥出它不同的特色味道。java中的佐料有:算术运算符、赋值运算符、逻辑运算符、关系运算符、自增和自减运算符、位运算符、条件运算符,而java中的数据类型相当于不同食物的原料,例如,小麦,水稻…。
这些佐料都用于变量上,变量是一个具有适当的数据类型的数值。
拓展点:
1、变量的作用域,final常量特点
2、数据类型
(1.)基本数据类型:
类型名称 | 关键字 | 占用内存(内存空间) | 取值范围 | 默认值 |
---|---|---|---|---|
字节型 | byte | 1字节(8位) | -128~127 | 0 |
短整型 | short | 2字节(16位) | -32768~32767 | 0 |
整型 | int | 4字节(32位) | -2147483648~2147483647 | 0 |
长整型 | long | 8字节(64位) | -9223372036854775808L~9223372036854775807L | 0L |
单精度浮点型 | float | 4字节(32位) | +/-3.4E+38F(6~7 个有效位) | 0.0f |
双精度浮点型 | double | 8字节(64位) | +/-1.8E+308 (15 个有效位) | 0.0d |
字符型 | char | 2字节(16位) | ISO 单一字符集 | ‘u0000’ |
布尔型 | boolean | 1字节(8位) | true 或 false | false |
(2.)数值的隐式类型转化和强制类型或转换
(3.)数据类型结构
整数类型等号右边默认是int类型,如果想要表示long类型,需要在值后面加L
浮点型等号右边默认是double类型,如果想要表示float类型,需要在值后面加F
3、char字符型对应的ASCII十进制值
0-9:48-57
A-Z:65-90
a-z:97-122
4、逻辑运算符中的短路与和短路或的特点。
5、 成员变量和局部变量的定义以及生命周期?(面)
局部变量:
当厨房(生产环境),厨具,佐料都准备好后,我们就开始生火做饭了。这个火候怎么把握呢,java中有顺序结构、选择结构和循环结构三种结构来控制火候。
顺序结构:系统则默认自上而下一行一行地执行
选择结构:if和else的组合使用,switch case的使用
循环结构:while,do while,for,foreach(遍历)
终止函数的执行或退出类的方法:return
强行退出循环:break
中止当前迭代的循环,进入下一次的迭代:continue
拓展点:
1.switch 语句中的变量类型可以是: byte、short、int 或者 char。从 Java SE 7 开始,switch 支持字符串 String 类型了,同时 case 标签必须为字符串常量或字面量。
当大厨把饭做好之后,接下来就开始美美的拼盘了,java中对字符串进行操作,就像对食物进行加工雕刻拼盘,最后一份色香味俱全的美味就出现了。
定义字符串:String类的特点。
连接字符串:+,concat,append
获取字符串长度:str.length()
转换大小写:str.toLowerCase()/str.toUpperCase()转小写/大写非字母不受影响
去空格:str.trim()
截取字符串:substring() 按字符截取
分割字符串:str.split()返回字符串数组
替换字符串:replace(),replaceFirst()和replaceAll()匹配正则表达式进行替换
比较字符串:equals(),equalsIgnoreCase() 比较时不区分大小写,compareTo() 方法用于按字典顺序比较两个字符串的大小,该比较是基于字符串各个字符的 Unicode 值。
查找字符串:indexOf() 方法和 lastlndexOf() 方法用于在字符串中获取匹配字符(串)的索引值,charAt() 方法可以在字符串内根据指定的索引查找字符
利用正则表达式验证字符串
扩展:
1、String,StringBuffer,StringBuilder的区别
2、String类的特点
数字和日期这两种食物的拼盘开始啦!
数值运算:Math 类封装了常用的数学运算,提供了基本的数学操作,如指数、对数、平方根和三角函数等,当我们需要进行数值运算的时候就可以直接利用了。
生成随机数:Math中的random() 方法只能产生 double 类型的 0~1 的随机数,Random 类提供了丰富的随机数生成方法,可以产生 boolean、int、long、float, byte 数组以及 double 类型的随机数。
数字格式化:DecimalFormat类对结果进行格式化处理
大数字运算: BigInteger 类是针对整型大数字的处理类,而 BigDecimal 类是针对大小数的处理类,他俩用于高精度计算。
时间日期的处理:Date 类主要封装了系统的日期和时间的信息,并提供了一些日期操作的常用方法。
Calendar类是一个抽象类,它通过getInstance() 方法返回一个 Calendar 对象,
例子:
Calendar calendar = Calendar.getInstance();
calendar.get(Calendar.DAY_OF_YEAR);
Calendar.YEAR:年份。
Calendar.MONTH:月份。(月份从 0 开始,需要加 1)
Calendar.DATE:日期。
Calendar.DAY_OF_MONTH:日期,和上面的字段意义完全相同。
Calendar.HOUR:12小时制的小时。
Calendar.HOUR_OF_DAY:24 小时制的小时。
Calendar.MINUTE:分钟。
Calendar.SECOND:秒。
Calendar.DAY_OF_WEEK:星期几。获取今天星期几(以星期日为第一天)
日期格式化:使用 DateFormat 类和 SimpleDateFormat 类来格式化日期
创建DateFormat对象需要用
DateFormat df=DateFormat.getDatelnstance();日期
DateFormat df=DateFormat.getTimeInstance();时间
SHORT:完全为数字,如 12.5.10 或 5:30pm。
MEDIUM:较长,如 May 10,2016。
LONG:更长,如 May 12,2016 或 11:15:32am。
FULL:是完全指定,如 Tuesday、May 10、2012 AD 或 11:l5:42am CST。
我们把原料小麦加工成面粉,原料水稻加工成大米,相当于对原料进行了一次加工包装。java中也提供原料的包装类,比如int对应Integer,short对应Short等。
Object类:
方法 | 说明 |
---|---|
Object clone() | 创建与该对象的类相同的新对象 |
boolean equals(Object) | 比较两对象是否相等 |
void finalize() | 当垃圾回收器确定不存在对该对象的更多引用时,对象的圾回收器调用该方法 |
Class getClass() | 返回一个对象运行时的实例类 |
int hashCode() | 返回该对象的散列码值 |
void notify() | 激活等待在该对象的监视器上的一个线程 |
void notifyAll() | 激活等待在该对象的监视器上的全部线程 |
String toString() | 返回该对象的字符串表示 |
void wait() | 在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待 |
方法 | 返回值 | 说明 |
---|---|---|
byteValue() | byte | 以 byte 类型返回该 Integer 的值 |
shortValue() | short | 以 short 类型返回该 Integer 的值 |
intValue() | int | 以 int 类型返回该 Integer 的值 |
toString | String | 返回一个表示该 Integer值的 String 对象 |
equals(Object obj) | boolean | 比较此对象与指定对象是否相等 |
compareTo(IntegeranotherInteger) | int | 在数字上比较两个 Integer 对象,如相等,则返回 0; 如调用对象的数值小于 anotherlnteger 的数值,则返回负值; 如调用对象的数值大于 anotherlnteger 的数值,则返回正值 |
valueOf(String s) | Integer | 返回保存指定的 String 值的 Integer 对象 |
parseInt(String s) | toString() | 将数字字符串转换为 int 数值 |
Float类:
方法 | 返回值 | 说明 |
---|---|---|
byteValue() | byte | 以 byte 类型返回该 Float 的值 |
doubleValue() | double | 以 double 类型返回该 Float 的值 |
floatValue() | float | 以float类型返回该Float的值 |
intValue() | int | 以 int 类型返回该 Float 的值(强制转换为 int 类型) |
longValue() | long | 以long类型返回该Float的值(强制转换为long类型) |
shortValue() | short | 以 short 类型返回该 Float 的值(强制转换为short类型) |
isNaN() | noolean | 如果此 Float 值是一个非数字值,则返回 true,否则返回 false |
isNaN(float v) | boolean | 如果指定的参数是一个非数字值,则返回 true,否则返回 false |
toString | String | 返回一个表示该 Float值的 String 对象 |
valueOf(String s) | Float | 返回保存指定的 String 值的 Float 对象 |
parseFloatString s) | toString() | 将数字字符串转换为 float 数值 |
Double类:
方法 | 返回值 | 说明 |
---|---|---|
byteValue() | byte | 以 byte 类型返回该 Double 的值 |
doubleValue() | double | 以 double 类型返回该 Double 的值 |
floatValue() | float | 以float类型返回该Double的值 |
intValue() | int | 以 int 类型返回该 Double 的值(强制转换为 int 类型) |
longValue() | long | 以long类型返回该Double的值(强制转换为long类型) |
shortValue() | short | 以 short 类型返回该 Double 的值(强制转换为short类型) |
isNaN() | noolean | 如果此 Double 值是一个非数字值,则返回 true,否则返回 false |
isNaN(float v) | boolean | 如果指定的参数是一个非数字值,则返回 true,否则返回 false |
toString | String | 返回一个表示该 Double值的 String 对象 |
valueOf(String s) | Float | 返回保存指定的 String 值的 Double 对象 |
parseFloatString s) | toString() | 将数字字符串转换为 double 数值 |
Number类: 是一个抽象类,也是一个超类(即父类)。Number 类属于 java.lang 包,所有的包装类(如 Double、Float、Byte、Short、Integer 以及 Long)都是抽象类 Number 的子类。
Character类:
方法 | 描述 |
---|---|
void Character(char value) | 构造一个新分配的 Character 对象,用以表示指定的 char 值 |
char charValue() | 返回此 Character 对象的值,此对象表示基本 char 值 |
int compareTo(Character anotherCharacter) | 根据数字比较两个 Character 对象 |
boolean equals(Character anotherCharacter) | 将此对象与指定对象比较,当且仅当参数不是 null,而 是一个与此对象 包含相同 char 值的 Character 对象时, 结果才是 true |
boolean isDigit(char ch) | 确定指定字符是否为数字,如果通过 Character. getType(ch) 提供的字 符的常规类别类型为 DECIMAL_DIGIT_NUMBER,则字符为数字 |
boolean isLetter(int codePoint) | 确定指定字符(Unicode 代码点)是否为字母 |
boolean isLetterOrDigit(int codePoint) | 确定指定字符(Unicode 代码点)是否为字母或数字 |
boolean isLowerCase(char ch) | 确定指定字符是否为小写字母 |
boolean isUpperCase(char ch) | 确定指定字符是否为大写字母 |
char toLowerCase(char ch) | 使用来自 UnicodeData 文件的大小写映射信息将字符参数转换为小写 |
char toUpperCase(char ch) | 使用来自 UnicodeData 文件的大小写映射信息将字符参数转换为大写 |
Boolan类:
方法 | 返回值 | 说明 |
---|---|---|
booleanValue() | boolean | 将 Boolean 对象的值以对应的 boolean 值返回 |
equals(Object obj) | boolean | 判断调用该方法的对象与 obj 是否相等。当且仅当参数不是 null,且与调用该方法的对象一样都表示同一个 boolean 值的 Boolean 对象时,才返回 true |
parseBoolean(String s) | boolean | 将字符串参数解析为 boolean 值 |
toString | String | 返回表示该 boolean 值的 String 对象 |
valueOf(String s) | Float | 返回一个用指定的字符串表示的 boolean 值 |
Byte类:
方法 | 返回值 | 说明 |
---|---|---|
byteValue() | byte | 以一个 byte 值返回 Byte 对象 |
compareTo(Byte byte) | int | 在数字上比较两个 Byte 对象 |
doubleValue() | double | 以一个 double 值返回此 Byte 的值 |
intValue() | int | 以一个 int 值返回此 Byte 的值 |
parseByte(String s) | byte | 将 String 型参数解析成等价的 byte 形式 |
toString() | String | 返回表示此 byte 值的 String 对象 |
valueOf(String s) | Byte | 返回一个保持指定 String 所给出的值的 Byte 对象 |
equals(Object obj) | boolean | 将此对象与指定对象比较,如果调用该方法的对象与 obj 相等 则返回 true,否则返回 false |
System 类:
系统级的很多属性和控制方法都在该类内部,该类构造方法时private的,所以无法创建该类的对象,也就是无法实例化该类,System 类内部的成员变量和成员方法都是 static 的,所以可以方便地进行调用。
System类的3 个静态成员变量,分别是 PrintStream out、InputStream in 和 PrintStream err。
(1、)PrintStream out:标准输出流。
(2、)InputStream in:标准输入流。
(3、)PrintStream err:标准的错误输出流。
System类的成员方法
常用的方法有 arraycopy()、currentTimeMillis()、exit()、gc() 和 getProperty()。
(1、)arraycopy() :该方法的作用是数组复制,即从指定源数组中复制一个数组,复制从指定的位置开始,到目标数组的指定位置结束。
(2、)currentTimeMillis() :该方法的作用是返回当前的计算机时间。
(3、)exit() :该方法的作用是终止当前正在运行的 Java 虚拟机,status 的值为 0 时表示正常退出,非零时表示异常退出。使用该方法可以在图形界面编程中实现程序的退出功能等。
(4、)gc():该方法的作用是请求系统进行垃圾回收。至于系统是否立刻回收,取决于系统中垃圾回收算法的实现以及系统执行时的情况。
(5、)getProperty():
属性名 | 描述 |
---|---|
java.version | Java运行时环境版本 |
java.home | Java安装目录 |
os.name | 操作系统的名称 |
os.version | 操作系统的版本 |
user.name | 用户的账户名称 |
user.home | 用户的主目录 |
user.dir | 用户的当前工作目录 |
数组这一章,不容易理解的就是数组的排序和查找,所以放到数据结构学习博客里面去了。
本章主要内容就是像做饭的过程,只能在实践中慢慢体会啦!
[public][abstract|final]class<class_name>[extends<class_name>]
[implements<interface_name>]
{
//定义属性部分
<property_type><property1>;
<property_type><property2>;
<property_type><property3>;
…
//定义方法部分
function1();
function2();
function3();
…
}
public:表示“共有”的意思。如果使用 public 修饰,则可以被其他类和程序访问。每个 Java 程序的主类都必须是 public 类,作为公共工具供其他类和程序使用的类应定义为 public 类。
abstract:如果类被 abstract 修饰,则该类为抽象类,抽象类不能被实例化,但抽象类中可以有抽象方法(使用 abstract 修饰的方法)和具体方法(没有使用 abstract 修饰的方法)。继承该抽象类的所有子类都必须实现该抽象 类中的所有抽象方法(除非子类也是 抽象类)。
final:如果类被 final 修饰,则不允许被继承。
class:声明类的关键字。
class_name:类的名称。
extends:表示继承其他类。
implements:表示实现某些接口。
property_type:表示成员变量的类型。
property:表示成员变量名称。
function():表示成员方法名称。
java三大特性:继承,封装,多态。
良好的封装能够减少耦合。
类内部的结构可以自由修改。
可以对成员变量进行更精确的控制。
隐藏信息,实现细节。
子类拥有父类非 private 的属性、方法。
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法。
Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
内部类的学习!
了解数据结构学习集合会更好一点。
在程序运行时由用户输入一个类名,然后动态获取该类拥有的构造、属性和方法,甚至调用任意类的任意方法。
类型 | 访问方法 | 返回值类型 | 说明 |
---|---|---|---|
包路径 | getPackage() | Package 对象 | 获取该类的存放路径 |
类名称 | getName() | String 对象 | 获取该类的名称 |
继承类 | getSuperclass() | Class 对象 | 获取该类继承的类 |
实现接口 | getlnterfaces() | Class 型数组 | 获取该类实现的所有接口 |
构造方法 | getConstructors() | Constructor 型数组 | 获取所有权限为 public 的构造方法 |
构造方法 | getDeclaredContxuectors() | Constructor 对象 | 获取当前对象的所有构造方法 |
方法 | getMethods() | Methods 型数组 | 获取所有权限为 public 的方法 |
方法 | getDeclaredMethods() | Methods 对象 | 获取当前对象的所有方法 |
成员变量 | getFields() | Field 型数组 | 获取所有权限为 public 的成员变量 |
成员变量 | getDeclareFileds() | Field 对象 | 获取当前对象的所有成员变量 |
内部类 | getClasses() | Class 型数组 | 获取所有权限为 public 的内部类 |
内部类 | getDeclaredClasses() | Class 型数组 | 获取所有内部类 |
内部类的声明类 | getDeclaringClass() | Class 对象 | 如果该类为内部类,则返回它的成员类,否则返回 null |
在调用 getFields() 和 getMethods() 方法时将会依次获取权限为 public 的字段和变量,然后将包含从超类中继承到的成员实量和方法。而通过 getDeclareFields() 和 getDeclareMethod()只是获取在本类中定义的成员变量和方法。
(1.)访问构造方法
方法名称 | 说明 |
---|---|
isVarArgs() | 查看该构造方法是否允许带可变数量的参数,如果允许,返回 true,否则返回false |
getParameterTypes() | 按照声明顺序以 Class 数组的形式获取该构造方法各个参数的类型 |
getExceptionTypes() | 以 Class 数组的形式获取该构造方法可能抛出的异常类型 |
newInstance(Object … initargs) | 通过该构造方法利用指定参数创建一个该类型的对象,如果未设置参数则表示采用默认无参的构造方法 |
setAccessiable(boolean flag) | 如果该构造方法的权限为 private,默认为不允许通过反射利用 netlnstance()方法创建对象。如果先执行该方法,并将入口参数设置为 true,则允许创建对象 |
getModifiers() | 获得可以解析出该构造方法所采用修饰符的整数 |
(2.)访问方法
方法名称 | 说明 |
---|---|
getName() | .获取该方法的名称 |
getParameterType() | 按照声明顺序以 Class 数组的形式返回该方法各个参数的类型 |
getRetumType() | 以 Class 对象的形式获得该方法的返回值类型 |
getExceptionTypes() | 以 Class 数组的形式获得该方法可能抛出的异常类型 |
invoke(Object obj,Object…args) | 利用 args 参数执行指定对象 obj 中的该方法,返回值为 Object 类型 |
isVarArgs() | 查看该方法是否允许带有可变数量的参数,如果允许返回 true,否 则返回 false |
getModifiers() | 获得可以解析出该方法所采用修饰符的整数 |
(3.)访问成员变量
方法名称 | 说明 |
---|---|
getName() | 获得该成员变量的名称 |
getType() | 获取表示该成员变量的 Class 对象 |
get(Object obj) | 获得指定对象 obj 中成员变量的值,返回值为 Object 类型 |
set(Object obj,Object value) | 将指定对象 obj 中成员变量的值设置为 value |
getlnt(0bject obj) | 获得指定对象 obj 中成员类型为 int 的成员变量的值 |
setlnt(0bject obj,int i) | 将指定对象 obj 中成员变量的值设置为 i |
setFloat(Object obj,float f) | 将指定对象 obj 中成员变量的值设置为 f |
getBoolean(Object obj) | 获得指定对象 obj 中成员类型为 boolean 的成员变量的值 |
setBoolean(Object obj,boolean b) | 将指定对象 obj 中成员变量的值设置为 b |
getFloat(Object obj) | 获得指定对象 obj 中成员类型为 float 的成员变量的值 |
setAccessible(boolean flag) | 此方法可以设置是否忽略权限直接访问 private 等私有权限的成员变量 |
getModifiers() | 获得可以解析出该方法所采用修饰符的整数 |
学习输入/输出流感触最深的就是使用java的多态性。。。
1. File(文件特征与管理):用于文件或者目录的描述信息,例如生成新目录,修改文件名,删除文件,判断文件所在路径等。
2. InputStream(二进制格式操作):抽象类,基于字节的输入操作,是所有输入流的父类。定义了所有输入流都具有的共同特征。
3. OutputStream(二进制格式操作):抽象类。基于字节的输出操作。是所有输出流的父类。定义了所有输出流都具有的共同特征。
4.Reader(文件格式操作):抽象类,基于字符的输入操作。
5. Writer(文件格式操作):抽象类,基于字符的输出操作。
6. RandomAccessFile(随机文件操作):一个独立的类,直接继承至Object.它的功能丰富,可以从文件的任意位置进行存取(输入输出)操作。
根据处理数据类型的不同分为:字符流和字节流
根据数据流向不同分为:输入流和输出流
按数据来源(去向)分类:
1、File(文件): FileInputStream, FileOutputStream, FileReader, FileWriter
2、byte[]:ByteArrayInputStream, ByteArrayOutputStream
3、Char[]: CharArrayReader,CharArrayWriter
4、String:StringBufferInputStream, StringReader, StringWriter
5、网络数据流:InputStream,OutputStream, Reader, Writer
Java 中的字符是 Unicode 编码,即双字节的,而 InputerStream 是用来处理单字节的,在处理字符文本时不是很方便。这时可以使用 Java 的文本输入流 Reader 类!
所有输入流类都是 InputStream 抽象类(字节输入流)和 Reader 抽象类(字符输入流)的子类。
InputStream 类的常用子类如下。
ByteArrayInputStream 类:将字节数组转换为字节输入流,从中读取字节。
FileInputStream 类:从文件中读取数据。
PipedInputStream 类:连接到一个 PipedOutputStream(管道输出流)。
SequenceInputStream 类:将多个字节输入流串联成一个字节输入流。
ObjectInputStream 类:将对象反序列化,操作的对象必须实现序列化接口。
(1.)int read() :读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。
(2.)int read(byte[] b) :将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。
(3.)int read(byte[] b, int off, int len):将数据读入一个字节数组,同时返回实际读取的字节数。如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置;len指定读取的最大字节数。
long skip(long n)):在输入流中跳过n个字节,并返回实际跳过的字节数。
int available() :返回在不发生阻塞的情况下,可读取的字节数。
void close() :关闭输入流,释放和这个流相关的系统资源。
void mark(int readLimit):在输入流的当前位置放置一个标记,如果读取的字节数多于readlimit设置的值,则流忽略这个标记。
void reset() :返回到上一个标记。
boolean markSupported() :测试当前流是否支持mark和reset方法。如果支持,返回true,否则返回false。
ByteArrayOutputStream 类:向内存缓冲区的字节数组中写数据。
FileOutputStream 类:向文件中写数据。
PipedOutputStream 类:连接到一个 PipedlntputStream(管道输入流)。
ObjectOutputStream 类:将对象序列化。
方法名及返回值类型 | 说明 |
---|---|
void write(int b) | 向输出流写入一个字节。这里的参数是 int 类型,但是它允许使用表达式,而不用强制转换成 byte 类型。为了提高 I/O 操作的效率,建议尽量使用write() 方法的另外两种形式 |
void write(byte[] b) | 把参数 b 指定的字节数组中的所有字节写到输出流中 |
void write(byte[] b,int off,int len) | 把参数 b 指定的字节数组中的若干字节写到输出流中。其中,off 指定字节数组中的起始下标,len 表示元素个数 |
void close() | 关闭输出流。写操作完成后,应该关闭输出流。系统将会释放与这个输出流相关的资源。注意,OutputStream 类本身的 close() 方法不执行任何操作,但是它的许多子类重写了 close() 方法 |
void flush() | 为了提高效率,在向输出流中写入数据时,数据一般会先保存到内存缓冲区中,只有当缓冲区中的数据达到一定程度时,缓冲区中的数据才会被写入输出流中。使用 flush() 方法则可以强制将缓冲区中的数据写入输 出流,并清空缓冲区 |
Reader 类的常用子类如下:
CharArrayReader 类:将字符数组转换为字符输入流,从中读取字符。
StringReader 类:将字符串转换为字符输入流,从中读取字符。
BufferedReader 类:为其他字符输入流提供读缓冲区。
PipedReader 类:连接到一个 PipedWriter。
InputStreamReader 类:将字节输入流转换为字符输入流,可以指定字符编码。
方法名及返回值类型 | 说明 |
---|---|
int read() | 从输入流中读取一个字符,并把它转换为 0~65535 的整数。如果返回 -1, 则表示已经到了输入流的末尾。为了提高 I/O 操作的效率,建议尽量使 用下面两种 read()方法 |
int read(char[] cbuf) | 从输入流中读取若干个字符,并把它们保存到参数 cbuf 指定的字符数组中。 该方法返回读取的字符数,如果返回 -1,则表示已经到了输入流的末尾 |
int read(char[] cbuf,int off,int len) | 从输入流中读取若干个字符,并把它们保存到参数 cbuf 指定的字符数组中。其中,off 指定在字符数组中开始保存数据的起始下标,len 指定读 取的字符数。该方法返回实际读取的字符数,如果返回 -1,则表示已经 到了输入流的末尾 |
Writer 类的常用子类如下。
CharArrayWriter 类:向内存缓冲区的字符数组写数据。
StringWriter 类:向内存缓冲区的字符串(StringBuffer)写数据。
BufferedWriter 类:为其他字符输出流提供写缓冲区。
PipedWriter 类:连接到一个 PipedReader。
OutputStreamReader 类:将字节输出流转换为字符输出流,可以指定字符编码。
方法名及返回值类型 | 说明 |
---|---|
void write(int c) | 向输出流中写入一个字符 |
void write(char[] cbuf) | 把参数 cbuf 指定的字符数组中的所有字符写到输出流中 |
void write(char[] cbuf,int off,int len) | 把参数 cbuf 指定的字符数组中的若干字符写到输出流中。其中,off 指定字符数组中的起始下标,len 表示元素个数 |
void write(String str) | 向输出流中写入一个字符串 |
void write(String str, int off,int len) | 向输出流中写入一个字符串中的部分字符。其中,off 指定字符串中的起始偏移量,len 表示字符个数 |
append(char c) | 将参数 c 指定的字符添加到输出流中 |
append(charSequence esq) | 将参数 esq 指定的字符序列添加到输出流中 |
append(charSequence esq,int start,int end) | 将参数 esq 指定的字符序列的子序列添加到输出流中。其中,start 指定子序列的第一个字符的索引,end 指定子序列中最后一个字符后面的字符的索引,也就是说子序列的内容包含 start 索引处的字符,但不包括 end索引处的字符 |
程序员的懒惰让他们很少有时间去编写没有人需要的代码
1.并发优缺点
发挥多处理的强大的功能
建模的简单性
异步事件的简化处理
响应更加灵敏的用户界面
安全性问题
活跃性问题
性能问题
java监视和管理控制台:cmd命名输入 jconsole
2.理解多线程与并发之间的联系与区别
区别:多线程其实并不是多个线程一起执行,而是线程之间因为切换的速度非常的快,所以,我们看起来像不间断的执行。
并行表示的是多个任务同时执行
联系:多线程并不一定是并发,如果是并发执行,那么肯定是多个线程在一块执行。
3.多线程与多进程的联系
进程是资源分配的基本单位
进程中包含多个线程,线程共享进程的资源
线程是处理器调度的基本单位
4.线程垃圾收集器(多线程执行的垃圾收集器,并行执行的垃圾收集器,serial单线程执行的垃圾收集器。)
(单线程一味的收集干活,一直等它干完活就结束,多线程一边想着干活,一边进行线程之间的切换。对于占用内存比较少,回收时间本来就比较短,可以使用单线程的垃圾收集器来进行收集,而它的性能是远比多线程要快的,因此在某些情境下单线程是远比多线程要快的)。
多线程下载并不是多线程提高了速度,也不是多线程的性能提高了,而是,由于外部服务器对资源的限制,为每一个链接分配一定的带宽,而不是将全部带宽分给一个链接,也就是说多线程下载并不是多线程提高了速度,不是多线程的性能提高了,而是多个链接突破了这个远程服务器的限制,也就导致了性能的提高。
5.线程的状态以及各状态之间的转换详解
创建状态:new一个线程后,该进程就处于新建状态,此时由JVM为其分配内存,并初始化成员变量的值。
就绪状态:调用start()方法之后,该线程处于就绪状态。java虚拟机会为其创建方法调用栈和程序计数器等待调度运行。
运行状态:处于就绪状态的线程抢占到CPU,开始执行run()方法的线程执行体,则该线程处于运行状态。
阻塞状态:当处于运行状态的线程失去所占用资源之后,便进入阻塞状态。
死亡状态:线程结束或者出现异常或错误,该线程结束生命周期。
6.线程的初始化,中断和源码分析
Java中线程两种类型:用户线程和守护线程 Thread.setDaemon(false)为用户线程,默认也为用户线程,Thread.setDaemon(true)设置为守护线程。
区别:1.主线程结束后用户线程还会继续运行,JVM存活。
2.如果没有用户线程,都是守护线程,那么JVM结束(随之而来的是所有一切烟消云散,包括所有的守护线程)。
stop()只是让这个线程无限期的等待下去,这个线程所获取得锁、获取得其他资源都没有被释放掉,因此这种方法已经不建议使用了。
interrupt():中断线程,interrupted():查看当前线程是否中断,isInterrupted():判断当前这个线程是否中断。
interrupted()是静态方法:测试当前线程是否已经是中断状态,执行后具有清除状态功能。
isInterrupted()是实例方法:测试线程Thread对象,是否已经是中断状态,但不会清除中断状态。
7-10.线程创建方式(8种)
继承Thread类
实现Runnable接口
带有返回值的线程继承Callable接口,使用FutureTask创建线程对象
内部类3种方式
Timer定时器 timer.schedule(new TimerTask(){},0,1000)
spring注解@Async
Lambda表达式parallelStream并发流
11.了解多线程带来的安全风险
线程安全性问题
活跃性问题 死锁(哲学家吃饭) 饥饿问题(食堂打饭) 活锁(两人过独木桥)
性能问题 线程切换
12.从线程的优先级看饥饿问题
1.优先级高的线程吞噬掉了优先级低的线程的CPU时间片
2.线程被永久堵塞在一个等待进入同步块的状态
3.处于等待状态的线程永远不被唤醒
1.设置合理的优先级
2.使用锁来代替synchronized
13.从java字节码看线程安全问题
java自带分析字节码文件工具javap -verbose name.class文件
线程安全性问题出现的条件:
多线程环境下
多个线程共享一个资源
对资源进行非原子性操作
14.synchronized保证线程安全的原理(理论层面)
内置锁/互斥锁
修饰普通方法:内置锁就是当前实例
修饰静态方法:内置锁就是当前Class字节码文件
修饰代码块:内置锁是放入的对象
15.synchronized保证线程安全的原理(JVM层面)
锁存在的位置:存在对象头中
对象头中的信息:Mark Word,Class Metadata Address,Array Length
线程Id
Epoch
对象的分代年龄信息
是否是偏向锁
锁标志位
每次获取锁和释放锁会浪费资源
很多情况下,竞争锁不是有多个线程,而是只有一个线程在使用
只有一个线程在访问同步代码块的场景
自旋
多线程使用
只能有一个锁进入代码块
16.单例问题与线程安全性深入解析
饿汉式单例模式不会出现线程安全问题
懒汉式单例模式使用双重检查加锁和volatile关键字提高CPU性能和避免线程安全性问题
17.理解自旋锁,死锁,重入锁
自旋锁就是代码被多个线程访问时,如果上一个锁不被释放,则下一个线程进入自旋状态。
死锁就是被访问的资源被互相锁住,就进入死锁状态
重人锁就是一个对象被线程访问时,可以进入另一个同步方法,线程不会出现死锁。因为这两个方法锁的是同一个对象。
18.深入理解volatile原理与使用
被volatile修饰的变量,在汇编中多了一个lock指令,lock指令将当前处理器缓存行的数据写回到系统内存中,其他cpu缓存该内存地址的数据失效了,
这就保证了当我们一个线程修改volatile修饰的变量的时候,另一个线程是可见的。
大量使用volatile会使处理器的缓存失效了,也就是说大量使用volatile会降低性能。
对比:volatile只能保证变量的可见性,但是,并不能保证对这个变量所操作的原子性。因此,synchronized可以完全替代volatile,但是volatile并不能取代
synchronized。
volatile保证变量在多个线程之间可见,保证变量的一致性
volatile称为轻量级锁,被volatile修饰的变量,在线程之间是可见的。(可见:一个线程修改了这个变量的值,在另外一个线程中能够读到这个修改后的值)
volatile除了线程之间互斥以外,另一个非常大的作用,就是保证可见性。
19.JDK5提供的原子类操作以及实现原理
AtomicInteger 对整形数据类型原子性操作
AtomicIntegerArray 对整形数组的原子性操作
AtomicReference<> 对实体对象的原子性操作
AtomicIntegerFieldUpdater<> a = AtomicIntegerFieldUpdater.newUpdater(A.class,“old”);对实体对象的字段进行原子性操作,字段需要用volatile操作。
20.Lock接口认识与使用
Lock可以非阻塞的获取锁,能被中断的获取锁,超时获取锁。
提供的方法:lock()加锁 unlock()解锁 lockInterruptibly()中断锁boolean tryLock()获取锁。
Lock需要显示地获取和释放锁,繁琐,但可以使代码更灵活。
Synchronized不需要显示地获取和释放锁,使用简单。
Lock lock = new ReentrantLock();可以方便的实现公平性。
21.手动实现一个可重入锁
思路:继承Lock接口,实现lock()和unlock()方法,声名布尔型isLockd,线程LockBy,整形lockcount三个变量。
操作这三个变量,通过wait()和notify()函数控制线程运行。
22,23.AbstractQueuedSynchronizer(AQS)详解
实现加锁和重入锁
24.公平锁
公平是针对锁的获取而言的,如果一个锁是公平的,那么锁的获取顺序就应该符合请求的绝对时间顺序。
25.读写锁
写 :排他锁
读:共享锁
读-读能共存,
读-写不能共存,
写-写不能共存
26.分析ReentrantReadWriteLock
tryAcquire(int acquires) 互斥锁加锁
tryRelease(int releases) 互斥锁释放
tryAcquireShared(int unused)共享锁加锁
tryReleaseShard(int unused) 共享锁释放
27.锁降级和锁升级
锁降级是指写锁降级为读锁,在写锁没有释放的时候,获取到读锁。
把读锁升级为写锁,在读锁没有释放的时候,获取到写锁。
28.线程安全性问题总结
多线程环境下
具有共享资源
对共享资源进行非原子性操作
使用synchronized
volatile
JDK原子类
使用Lock
29.线程间的通信
wait()和notify()必须放在同步代码块中。
调用wait()方法时会释放锁,调用notify()时会加锁。释放锁和加锁都是这当前锁释放时拿到的。
30.生产者和消费者问题
生产类实现Runnable,传入对象
消费类实现Runnbale,传入对象
对象类里面做生产和消费,控制产品个数,设置产品数量,然后利用通信控制生产和消费。
31-33.Condition的使用及原理解析有界队列,和源码阅读
Condition的作用是对锁进行更精确的控制,它的await()相当于wait(),它的signal()相当于notify(),它的signalAll()相当于notifyAll()
不同的是它不需要与synchronized捆绑使用,但需要与互斥锁和共享锁捆绑使用。
34.实现数据库连接池
连接池有助于数据库性能的提升
初始化时建立一定个数的连接放到linklist里,获取连接时去池中拿连接,如果池中没有连接则等待,释放一个连接时,可以叫醒获取连接的线程。
35.线程加塞join
语法:j.start();j.join()
36.ThreadLocal用于保存某个线程共享变量
get: 获取ThreadLocal中当前线程共享变量的值。
set: 设置ThreadLocal中当前线程共享变量的值。
remove: 移除ThreadLocal中当前线程共享变量的值。
initialValue: ThreadLocal没有被当前线程赋值时或当前线程刚调用remove方法后调用get方法,返回此方法值。
37-41.并发工具类:CountDownLatch,CyclicBarrier,Semaphore,Exchanger
Semaphore:一个计数信号量
CountDownLatch:一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。
CyclicBarrier:一个同步辅助类,它允许一组线程互相等待,直到到达某个公共屏障点
Exchanger:方便了两个共同操作线程之间的双向交换
42-44.FuterTask
哎,没理解透,找个好心情再出发: https://blog.csdn.net/codershamo/article/details/51901057
45.Fork/Join框架
拆分处理最后合并,能够发挥多核服务器的优势
ForkJoinTask 实现类 RecursiveTask
class A extends RecursiveTask
@Override
protected Integer compute(){
A a1 = new A();
A a2 = new A();
a1.fork();
a2.fork();
return a1.join() + a2.join();
}
ForkJoinPool pool = new ForkJoinPool();
Future f = pool.submit(new A());
结果:f.get();
46-48.同步容器和并发容器
Vector(线程安全) -----同步容器----> ArrayList(线程不安全)-----并发容器----->CopyOnWriteArrayList
Hashtable(线程安全)-------同步容器----> HashMap(线程不安全)----并发容器----->CopyOnWriteHashMap
并发容器:ConcurrentLinkedQueue
49.java中的阻塞队列BlockingQueue
private BlockingQueue queue = new ArrayBlockingQueue<>(10);
queue.push(1)发送 queue.take()抓取
50.Executors框架
public static void main(String[] args) {
// ExecutorService threadPool = Executors.newFixedThreadPool(10);//分配固定的线程数
ExecutorService threadPool = Executors.newCachedThreadPool();// 根据需要自动建立相应的线程数
for (int i = 0; i < 50; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
}
});
}
threadPool.shutdown(); // 关闭线程池
}
ServerSocket 类表示 Socket 服务器端,Socket 类表示 Socket 客户端,两者之间的交互过程如下:
服务器端创建一个 ServerSocket(服务器端套接字),调用 accept() 方法等待客户端来连接。
客户端程序创建一个 Socket,请求与服务器建立连接。
服务器接收客户的连接请求,同时创建一个新的 Socket 与客户建立连接,服务器继续等待新的请求。
URLConnection 类来表示与 URL 建立的通信连接,URLConnection 类的对象使用 URL 类的 openConnection() 方法获得.