outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

 2021-06-29 23:48    77  

第一,我个人觉得IO这块很复杂是因为刚开始接触的时候没有一些实际的应用场景,在加上流这块种类挺多,以及每个流都有自己的用途,所以导致我们在学习的时候就会出现这种想法!刚开始学习的时候,先按照流的方向去划分,分为输入流和输出流,此处就应该心里明确应用场景.我通过以下图形的方式:

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

按照上面的图可以知道,其实流主要就是在设备和设备之间的数据进行传输!而网络中的数据进行传输都是以一种比特流的方式进行.这些外部设备outputstreamwriter,包括,键盘(标准输入设备),显示器(标准输出设备),音响,网络上另一台主机,甚至你玩游戏用的游戏手柄,以及各种各样的信号传感器,都可以叫做外部设备,和这些设备之间进行数据交互.当然这个只是我们在说明流的作用!那么流分为字节流和字符流。

第二,知道了这个学习的方向后,要使用Java操作文件系统,那么首先要学习的就是文件的表示,即File类。然后,我们要操作做文件,虽然我们大部分操作都是操作文件系统,但是要明白IO流的概念不仅仅局限在操作文件上,前面我已经提到了,我们的编程语言是要能操作所有的输入输出,因此,API提供了两个顶层抽象类,用来表示操作所有的输出输出:InputStream,OutputStream。并且,这两个类表示字节的输入输出,因为输入输出的本质是字节流。这里注意体会一句话“字节流是最最基本的流”,这句话的由来就是因为计算机底层传递的就是字节。那么,当我们要操作文件的时候,就需要具体的对文件系统操作的IO实现类,于是我们需要学习FileInputStream和FileOutputStream,它们是文件输入输出字节流。这里之所以FileInputStream/OutputStream作为子类出现,按照面向对象思想理解就是,将来还有别的字节流来操作别的设备;学了文件IO字节流之后,我们会发现原始的字节流对象用起来没那么高效,因为每个读或写请求都由底层操作系统处理,这些请求往往会触发磁盘访问outputstreamwriter、网络活动或其他一些相对昂贵的操作。不带缓冲区的流对象,只能一个字节一个字节的读,每次都调用底层的操作系统API,非常低效,而带缓冲区的流对象,可以一次读一个缓冲区,缓冲区空了才去调用一次底层API,这就能大大提高效率。所以又有了BufferedInputStream和BufferedOutputSteam,他们的用法是把字节流对象传入后再使用,也相当于把它俩套在了字节流的外面,让基本字节流操作更高效!

第三,由于字节流在读写的时候出现编码格式问题,而且针对中文操作比较特殊,中文底层存储的时候第一个字节一定是负数,我们最常见的是和文件系统打交道,那么针对如此常见的用途,读取文本文件能不能用一种方便的方式呢outputstreamwriter?当然,FileReader和FileWriter这两个流对象可以直接把文件转成读取、写入流。让你省去了创建字节流,再套上转换流的步骤。看看这类名起的,实际上很形象,xxxReader和xxxWriter,明摆着告诉你“阅读和书写”都是“人可以做的”也就是他们表示的是字符流。同理上面的InputStreamReader和OutputStreamWriter,表示的是把字节流转成人可读的,把字节流转成人可写的。因此他们的顶层抽象类:Reader和Writer.

这里主要是针对概念上以及场景上去说明,最终实际场景,比如我们的文件上传和下载操作都需要使用流的方式操作。

Java基础知识之笔记总结分享(超详细)入门必备

给大家分享一篇我之前在学习java过程中的关于java基础部分的笔记,比较详细,内容也比较多。 如有问题请指出以便修改,谢谢。 篇幅较长建议收藏浏览。

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

里面的部分重点内容以后会做详细讲解:集合,线程,JVM,JMM内存管理,多线程。请大家多多关注。

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

java数据类型Java数据类型

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

基本数据类型

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

1.1 char :Unicode编码的字符,或字符的整数编码,必须用单引号float默认值是0.0f;double默认值是0.0d;

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

1.2基本类型字面值规则

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

1.整数字面值是int类型,如果右侧赋值超出int范围,需要做转型处理

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

2.byte,short,char 三种比int小的整数,在自身范围内可以直接赋值。

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

byte d=1+3 正确,1+3编译器会自动转成4

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

3.浮点数字面值是double;浮点数转成整数会直接舍弃小数点后位数。

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

4.字面值后缀,L D F

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

5.字面值前缀,0b 二进制;0x 16进制;0 8进制; \u char 类型16进制。

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

1.3基本类型的运算规则

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

1.计算结果的数据类型与运算中的最大类型一致。

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

2.byte,short,char三种比int小的整数,计算时会自动转成int

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

做加法运算时,数据类型会自动转成int,除了自增加自减不进行转化外,其它情况都是无long型时,所有非int类型转成int类型;有long类型时,都转成long类型。

outputstreamwriter:为什么我觉得 Java 的 IO 很复杂?

char类型相加,提升为int类型。

计算

3.整数运算溢出。Integer.MAX_VALUE+1 的负数最小值 4.浮点数运算不精确 5.浮点数特殊值 infinity 整数除0 ;Nan 负数开方

1.4 基本类型的类型转换数字类型之间可以互相转换,从小到大自动转换,从大到小需要强制转型。double d = 245; float d=100;自动转型。

基本数据类型转换

1.5运算符&& :逻辑与(短路与),两边同为真结果才为真,短路与:左边是假,右边忽略不执行& :不管左边结果是什么都要执行右边(&的左右两边都要参与运算)|| :逻辑或(短路或),两边只要有一个真结果就是真,短路或:左边是真,右边忽略不执行

2.流程控制2.1 switch:只能判断byte short char int enum jdk1.7之后的string。从成立的case 无条件穿透所有的case包括default直到结束或者遇到break中断跳出循环;如果所有条件都不成立,则执行default

2.2 for循环

2.3 break 和 continueBreak 中断、跳出循环和switchContinue 跳过后面的代码 继续进入循环的下一轮执行2.4 for-each循环数组遍历、集合迭代遍历的语法简化

3.面向对象 —— 封装、继承、多态 ★ ★ ★ ★ ★封装 1 类:模板、图纸 。类中定义对象的属性数据(成员变量),方法(成员方法)类在第一次使用时会加载到方法区 2 对象:从模板中创建的具体实例,实例是数据的打包新建实例时,在堆内存中,新分配内存空间给这个实例。

3 引用变量:理解成“遥控器”,保存一个实例的内存地址(引用变量保存在栈),引用变量的特殊值:null 不保存任何实例的内存地址。

4 构造方法:新建实例对象时,立即执行的一个特殊方法;构造方法必须和类同名,并且没有返回值类型。一个类中必须有构造方法,自己没定义,系统会添加默认构造方法,构造方法一般用来给属性赋值 5 构造方法重载一个类中可以定义多个不同参数的构造方法,是方法重载的一种体现。

6 方法重载Overload:同名不同参,与返回值类型无关,所有方法都可以重载。

7 this关键字:this.xxx 特殊引用,引用当前对象的地址。

this(…):构造方法之间的调用,必须是首行代码,如果有多个构造方法,会通过

this(…)调取下面的所有构造方法,完成赋值。

注意this不能在静态方法中使用

继承

Java的继承是单继承多实现,只能继承一个父类(如果不继承其他类,默认继承object类),但可以实现多个接口

1.不能继承的有:构造方法,私有成员

过程:先新建父类对象,再新建子类对象,两者作为一个整体对象,调用成员时,先找子类,再找父类

2.方法重写:override

继承的方法,在子类中重新定义父类中的方法(只能在子类中重写),方法名相同,参数的个数和类型也必须相同,返回值类型也必须相同。

方法重写返回值类型如果是基本类型应与父类的一致;重写要求方法名完全相同,返回值类型如果是基本类型或无返回值时必须一致。

3.父类的构造方法

新建子类对象时会先新建父类对象,也会先执行父类的构造方法

默认执行父类的无参构造,默认隐含调用super();

new Student() 默认执行父类无参构造

new Student(……)默认执行父类无参构造

手动调用父类的有参构造,super(参数):父类没有无参构造时必须手动调用

4.superSuper.xxxx() 方法重写时,调用父类中同一个方法的代码Super(参数) 调用父类的构造方法,默认调用父类无参构造super(),手动调用有参构造super(),必须是首行代码注意super不能在静态方法中使用

多态一个对象具有多种形态的表现,多态的前提是必须有继承。void test(父类型 o1) { };把一个子类型的实例当做父类型来处理,所有的子类型都可以传递到该方法,被当做父类型处理;作用:一致的类型

1. 类型的转换A. 向上转型子类的实例转成父类型,用父类型的引用变量,来引用子类实例,向上转型后,只能调用父类定义的通用成员,子类特有成员被隐藏B. 向下转型已经转成父类型的子类实例,转回子类型为了对子类型进行特殊处理2. Instanceof 运行期的类型识别当多种子类型都被当做父类型来处理,要对某种子类型进行特殊处理,可以先判断其真实类型再向下转型——对真实类型,及其父类型判断,都返回true。eg:

if(obj instanceof CustomException){ throw new CustomException(obj.getMessage());}4.数组属于object类,用来存放一组数据的数据结构,数组是最基本的一种数据结构但不是基本数据类型,数组是相同数据类型组成的集合,数组中的元素按线性顺序排序

4.1 数组的创建数组创建后若未指定初始值,则会依据数组类型的不同来设置默认值。。eg: 3种创业数组的方式:

新建int[]数组,长度6,默认值都是0,数组的起始地址值保存在变量a。

int[] a = new int[4];int [] b = {1,2,3,4};int [] c = new int [] {1,2,3,4,5}; 4.2 数组的长度属性 a.length数组一旦创立,长度不可变最大下标 a.length-1允许0长度的数组

4.3 二维数组存放数组的数组

int[][] a = new int[3][2];外围长度为3,内部3个数组长度为2,一共有4个数组,内部数组默认值0,外围数组保存的是内部数组的地址。int[][] a = new int[3][];只建一个外围数组长度3,3个位置都是null,之后可以建新数组放入内部。 4.4 Arrays 数组工具类

Arrays.toString(数组) 把数组数据连接成字符串。Arrays.sort(数组) 数组排序 基本类型:优化的快速排序;引用类型:优化的合并排序。Arrays.binarySearch(数组,目标值) 二分法查找,在有序数组中查找目标值下标,找不到返回 -(插入点+1)。Arrays.copyof(数组,长度) 复制数组成一个指定长度的新数组。 4.5 数组 复制

Arrays.copyof(数组,长度) 复制数组成一个指定长度的新数组System.arraycopy(原数组,原数组起始位置,目标数组,目标数组起始位置,复制的数量) ——不会创建新的数组,目标数组要事先存在。5. 变量1 局部变量:定义在方法中或局部代码块中,必须初始化(第一次赋值时分配内存空间)局部变量的作用域在定义它的大括号内有效,在作用范围内不能重复定义。2 成员变量:定义在类中,自动初始化默认值,访问成员变量受访问控制符限制;局部变量可以和成员变量同名。

6.Object类如果一个类不继承其他类,则默认继承Object类

内部方法:

toString()获得一个对象的字符串表示。

Object中的默认实现是:“类名@地址”可在子类中重写toString方法。

equals() 当前对象与参与对象作比较是否相等。

a.equals(b) Object中的默认实现是比较内存地址。

Object中比较内存地址,基本类型默认比较内容值。

public boolean equals(Object obj) { return (this == obj);} // Object 中的equals的默认实现。7.String 类String是封装char[] 数组的对象。

7.1 字符串创建

Char[] a ={‘a’,’b’,’c’};String s = new String(a); >>>简易语法>>> String s = “abcd” 7.2 字符串的常量池String s1 = “abcd” 字符串的字面值写法。第一次使用一个字符串字面值时,会在字符串常量池中新分配内存,再次使用相同字面值时,直接访问常量池中存在的对象,而不会重复创建。

7.3.字符串中的 equals 和 “==”“==”比较内存地址equals 看父类中的方法,object中的默认方法是比较内存地址,String类中重写了父类方法比较的是字符内容。如下说明:

char[] a = {'a','b','c','d'};String s1 = new String(a);//堆中新分配内存String s2 = "abcd"; //在常量池新分配内存String s3 = "abcd"; //访问常量池中存在的对象System.out.println(s1==s2); //false 比较内存地址System.out.println(s2==s3); //true 比较内存地址String类中重写了equals方法,方法中比较的是字符内容System.out.println(s1.equals(s2));//true 比较字符串内容System.out.println(s2.equals(s3));//true 比较字符串内容 7.4 字符串不可变且字符串连接效率低,每次连接都会新建字符串对象 7.5 字符串的常用方法

charAt(i) 获取指定位置的字符length() 字符串长度,字符的数量indexof()找第一个子串出现的初始位置,找不到返回-1indexof(子串,start)从执行位置向后找lastIndexof(子串) 从后向前找subString(start)截取start到末尾subString[start,end )截取[start,end )范围trim()去除两端的空白字符matches()用来判断是否匹配正则表达式 7.6 StringBuilder: 可变的字符序列,封装char[]数组,提供了一组方法,可以对内部封装的字符进行修改,常用来代替字符串做高效的字符串连接。

append() 追加字符内容,内部数组默认初始容量16,放满后翻倍+2;delete(start,end) 删除区间(start,end);deleteCharAt(i)删除指定位置 i;insert(i,内容) 在指定位置插入内容;insertCharAt(i,字符)在指定位置插入单个字符;replace(start,end,内容)替换指定范围的内容;StringBuilder和StringBufferStringBuilder:线程不安全,效率高;JDK1.5版本后的新类。StringBuffer:线程安全,旧版本的类。8.正则表达式一般用来判断用户的输入内容是否符合格式要求

matches()字符串的方法,用来判断是否匹配 if(s.matches(regex)) { dosomething} split(正则):用匹配的子串来拆分字符串 String s = "aaa,bbb,ccc"; String[] a = s.split(",");replace(正则,子串)替换所有匹配的子串9.基本类型的包装类把基本类型当做对象来使用byte – Byteshort – Shortint – Integerlong – Longfloat – Floatdouble – Doublechar – Characterboolean – Boolean

9.1 数字父类Number子类:Byte,Short,Integer,Long,Float,Double,BigDecimal,BigInteger

取出基本类型值的方法byteValue(),shortValue(),intValue(),longValue(),floatValue(),doubleValu()

9.2 Intger类

创建Integer对象: a= { value:6}

Integer a = new Integer(6);

Integer a = Integer.valueOf(6);

Integer 类中存在256个Integer缓存对象,封装-127到128;如果访问指定范围内的值,会访问缓存对象,如果超出范围,会新建对象。

9.3 Integer类的方法

字符串解析成int

Integer.parseInt();Byte.parseByte()……

Integer.toBinaryString() 转成二进制字符串

Integer.toOctalString() 转成八进制字符串

Integer.toHexString(255) 转成十六进制字符串

9.4 BigDcimal和BigInteger 类BigDcimal精确的浮点数运算BigInteger 超大的整数运算

BigDecimal bd = BigDecimal.valueOf(2);

方法:

add(BigDecimal bd)subtract(BigDecimal bd)multiply(BigDecimal bd)divide(BigDecimal bd)divide(BigDecimal bd,保留位数,舍入方式)setScale(保留位数,舍入方式)9.5 自动装箱,自动拆箱

基本类型值,自动装箱成包装对象

Integer a = 6; 编译器编译成: Integer a = Integer.valueOf(6);自动拆箱(自动拆箱要注意null值)

int i = a; 编译器编译成: int i = a.intValue();10.抽象类 Abstract半成品类,没有完成的类;抽象方法:没有代码,只有方法的定义,抽象类不能创建实例,主要用来被继承。

// 包含抽象方法的类一定是抽象类public abstract class A { public abstract void f(); // 抽象方法};抽象方法的作用:

作为通用方法,在父类中定义;要求子类,必须实现这个方法。

1)抽象类可以有自己的构造方法。

2)抽象类可以有具体的方法。

3)包含抽象方法的类一定是抽象类,必须使用abstract关键字修饰,这个方法必须由子类来实现。

4)抽象类不能使用new关键字来创建实例。

5)当一个类中只要有一个抽象方法,这个类就必须是抽象类。

6)抽象类可以定义实例变量和静态变量以及常量。

7)抽象类可以再继承抽象类,也可以继承普通的类。

11.关键字 final内存地址不可变,可以修饰常量、类、方法

11.1 final 常量:值不可变,但引用类型因为保存的是地址,所以内容可以变。

final Point a = new Point(3,4);

a.x = 30;//对

a.y = 40;//对

11.2 final 方法不能在子类重写,但可以被继承。;final不能用于修饰构造方法,父类的private成员方法是不能被子类方法覆盖的,因此private类型的方法默认是final类型的。

11.3 final 类 不能被继承,没有子类

Static — 静态 共享的数据

静态成员属于类,而不属于实例

静态成员

用类来调用静态成员 Soldier.count

实例成员

用实例来调用实例成员 s1.id

工具方法

Math.Random() Arrays.toString() String.valueOf()

静态方法中不能直接调用实例的成员(非静态),只能用实例调用。

class A { public static void main(String[] args) { f();//静态调静态 } static void f() { g();//错,静态不能直接调用非静态 A a = new A(); a.g();//只能用实例调用 } void g(){ }}静态变量保存在方法区类的空间中,只保存一份可以在所有实例中共享的数据

对象的加载过程 ★ ★ ★ ★ ★

加载类:

1.加载父类,为父类静态变量分配内存 – 后台执行不可见

2. 加载子类,为子类静态变量分配内存

3. 执行父类静态变量的赋值运算,和静态初始化块

4. 执行子类静态变量的赋值运算,和静态初始化块

新建实例:

5. 新建父类实例,为父类实例变量分配内存

6. 新建子类实例,为子类实例变量分配内存

7. 执行父类的实例变量赋值运算

8. 执行父类的构造方法

9. 执行子类的实例变量赋值运算

10. 执行子类的构造方法

12.集合用来存放一组数据的数据结构数组的缺点: 长度固定 ; 访问方式单一只能下标访问; 前面增删数据操作繁琐集合的继承结构:(初学者了解常用的就可以了)

Collection 是对象集合, Collection 有两个子接口 List 和 Set,

List 可以通过下标 (1,2…) 来取得值,值可以重复,而 Set 只能通过游标来取值,并且值是不能重复的

ArrayList , Vector , LinkedList 是 List 的实现类

ArrayList: 是线程不安全的, Vector 是线程安全的,这两个类底层都是由数组实现的

LinkedList:是线程不安全的,底层是由链表实现的

Map: 是键值对集合

HashTable 和 HashMap 是 Map 的实现类

HashTable:是线程安全的,不能存储 null 值

HashMap:不是线程安全的,可以存储 null 值

ArrayList

数组列表,封装了一个数组,及其操作代码和更便捷的方法,内部数组默认初始容量10 放满后,1.5倍增长

方法:

add(数据)— 添加数据;get(int i)—访问指定下标数据; remove(int i)移除指定位置的数据,返回被移除的数据; remove(数据)— 找到第一个相等的数据,找到移除并返回true,找不到返回false; size() 元素的数量;iterator() 辅助新建迭代器

效率:

访问任意位置效率高,增删数据的效率可能降低。

LinkedList — 双向链表方法和ArrayList有相同的方法LinkedList 两端数据操作方法addFirst(数据);addLast(数据);getFirst();getLast();removeFisrt()removeLast();

效率两端效率高

HashMap — 哈希表、散列表 (面试必问) ★ ★ ★ ★ ★

存放键值对的数据,用键来快速定位数据,来提取键对应的值

键:不重复,无序

Hashmap中的key-value都是储存中entry数组中的

Hashmap的实现不是同步的,意味着它不是线程安全的

Hashmap的实例有两个参数影响其性能:初始容量,和加载因子

方法:

put(key,value)放入键值对数据,重复的键会覆盖旧值

get(key)获得键对应的值,键不存在,得到null

remove(key)移除键值对数据,返回被移除的值

size()键值对的数量。

哈希运算过程

HashMap内部,使用entry[]数组存放数据 数组默认初始容量16 放满后容量翻倍+2key.hashCode()获得键的哈希值 用哈希值和数组长度,运算产生下标值 i 新建entry对象来封装键值对数据 Entry对象,放入i 位置 如果是空位置,直接放入 如果有数据,一次equals()比较是否相等 找到相等的,覆盖旧值 没有相等的,链表连接在一起 负载率、加载因子超过0.75 新建翻倍容量的新数组 所有数据,重新执行哈希值,存入新数组 Jdk 1.8 链表长度到8,转成红黑树 树上的数据减少到6,转回成链表hashCode()

hashCode()是object的方法,默认实现是用内存地址作为哈希值,

可以重写方法来获得相同的哈希值

哈希运算中要有相同的哈希值,才能保证计算出相同下标值,并且要equals()也要相等(equals方法也要重写),才可以覆盖旧值,否则会链表连接。

重写hashCode的惯用算法:(x.y是变量的值)

13.异常封装错误信息的对象错误信息:类型、提示消息、行号

异常的继承结构

捕获异常

try {} catch(AException e) {} catch(BException e) {} catch(父类型Exception e) {} finally {不管出不出错,都会执行}如果抛出异常,并且中catch中有return语句,这个return语句会先执行,执行之后将结果保存在缓存中,再去查看是否有finally,如果有finally就先执行finally语句,之后再返回缓存中return的值,如果finally中也有return,那么finally中的return会覆盖掉之前缓存中的return,即最终会返回finally中的return值throw 手动抛出异常,执行异常的抛出动作 类似 return;当程序出现逻辑错误,不自动创建并抛出异常,可以手动判断逻辑错误,手动创建异常对象并抛出。底层的异常往上层抛,在上层处理。

if(...) { AException e = new AException(); throw e;}异常包装

捕获的异常对象,包装成其他类型再做抛出,多种类型简化成一种类型,不能抛出的异常包装成能抛出的异常再抛。

RuntimeException 和 其他Exception

RuntimeException— 非检查异常,编译器不检查是否有异常处理代码,存在默认的抛出管道

其他异常 — 编译器检查是否有处理代码,不处理,不能编译。

14.接口极端的抽象类,结构设计工具,用来解耦合,隔离现实

Implements代替extends

Interface 代替class

接口的定义:

 公开的抽象方法  公开的常量  公开的内部类、内部接口

1)接口只能定义常量

2)接口只能定义抽象方法

3)接口只能继承接口,不能继承普通的类和抽象类

4)接口没有构造方法

注意:

1)在接口中定义常量时,可以不用final static修饰,因为编译器在编译时会自动加上。

2)在接口中定义抽象方法时可以省略abstract关键字,编译器在编译时同样会加上。

3)JDK1.8 中的接口可以有默认的方法实现,详情参见:interface Map。

class A implements X,Y,Z {}class A extends B implements X,Y,Z {} // 类可以同时实现多个接口interface A extends X,Y,Z {} // 接口和接口的继承15 文件、字符操作流File封装一个磁盘路径字符串,提供了一组对文件、文件夹的操作方法,可以封装文件夹路径、文件路径、不存在的路径。 {path=“d:/abc”}方法

getName() 获取文件名

getPatrent() 获取父目录

getAbsolutePath()完整路径

length() 文件字节量,对文件夹无效,会返回假数据

isFile() 判断是否是文件

isDirectory()是否是文件夹

创建、删除

createNewFile()新建文件,文件已存在不会新建,返回false;文件夹不存在会出现异常

mkdirs()逐层创建多层文件夹

delete()删除文件、空目录

目录列表

list()得到String[] 包含所有文件名 [“a.txt”, “b.mp3”, “c.jpg”]

listFiles() 得到 File[],包含所有文件的封装的File对象 [{…}, {…}, {…}]

流 Stream

数据的读写操作(io操作),抽象成数据在管道中流动

单方向流动

 输入流,只能用来读取数据(读入内存)

 输出流,只能用来输出数据(内存数据向外输出)

只能从头到尾,顺序流动一次,不能反复流动,如果要重复流动,可以重新创建新的流

InputStream,OutputStream 字节流的抽象父类

方法:

write(int b) 只输出int四个字节中,末尾的一个字节值 [1][2][3][4] —> [4]

write(byte[], start, length) 输出byte[] 数组中,从start开始的length个字节值

read() 读取一个字节值,补三个0字节,变成int [4] —> [1][2][3][4],读取结束后,再读取会返回 -1。

read(byte[] buff) 按数组的长度,读取一批字节值,存放到指定的数组中,并返回这一批的字节数量,读取结束后,再读取会返回 -1。

FileInputStream,FileOutputStream — 文件流

ObjectInputStream,ObjectOutputStream —对象序列化、反序列化

序列化 把一个对象的信息,按固定的字节格式,变成一串字节序列输出

方法:

writeObject(Object obj) 把对象变成一串字节序列输出

readObject() 读取序列化数据,反序列化恢复对象

Serializable 接口——被序列化的对象,必须实现 Serializable 接口

不序列化的变量

Static — 属于类,不随对象被序列化输出

Transient —临时,只在程序运行期间,在内存中存在,不会被序列化持久保存

字符编码

ASC-II 0到 127,英文、指令字符

iso-8859-1 Latin-1 西欧编码 ,把ASC-II扩展到255

CJK 编码 亚洲编码,中日韩

GBK 国标码 英文单字节,中文双字节

Unicode 万国码 常用表,双字节 生僻字 三字节或四字节

UTF-8 Unicode 的传输格式 Unicode Transformation format英文,单字节某些字符,双字节;中文,三字节;特殊符号,四字节

Java的char类型是 Unicode

Java的转码运算

InputStreamReader,OutputStreamWriter字符编码转换流 OutputStreamWriter — 把Java的Unicode编码字符,转成其他编码输出InputStreamReader —读取其他编码字符,转成Unicode字符

16 内部类定义在类内部、方法内部或局部代码块内部的类,用来辅助外部实例运算,封装局部数据,或局部的运算逻辑。

非静态内部类、属于实例的内部类 非静态内部类实例,必须依赖于一个外部类的实例才能存在。静态内部类 静态内部类,与普通的类没有区别。

局部内部类局部定义的类型,类似于局部变量,有作用范围,只能在局部代码块内使用这种类型局部内部类中,使用外面的局部变量,必须加 final,jdk1.8,缺省。

匿名内部类

Weapon w = new Weapon() {...}; {} - 匿名类 new - 新建匿名类的实例 Weapon - 父类型 () - super(),可传参数super(1,2,3)

17. Java内存管理 堆内存 用来存放由new创建的对象实例和数组。Java堆是所有线程共享的一块内存区域,在虚拟机启动时创建,此内存区域的唯一目的就是存放对象实例。注意创建出来的对象只包含属于各自的成员变量,并不包括成员方法。

栈内存 保存的是堆内存空间的访问地址,或者说栈中的变量指向堆内存中的变量(Java中的指针)

栈:保存局部变量的值,包括:1.用来保存基本数据类型的值;2.保存类的实例,即堆区对象的引用(指针)。也可以用来保存加载方法时的帧。常量池存在于堆中(1.7b后的新版本)。

普通类型的变量在栈中直接保存它所对应的值,而引用类型的变量保存的是一个指向堆区的指针,通过这个指针,就可以找到这个实例在堆区对应的对象。因此,普通类型变量只在栈区占用一块内存,而引用类型变量要在栈区和堆区各占一块内存。

方法区是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。

18.线程在进程内部,并行执行的任务创建线程(两种方式) 继承 Thread 实现 Runnable

继承 Thread

编写 Thread 的子类,并重写 run() 方法。启动之后,自动运行 run() 方法中的代码

实现 Runnable

实现 Runnable 接口,实现它的 run() 方法,Runnable 封装在线程中执行的代码,新建线程对象时,把Runnable对象放在线程内,启动

线程的状态

线程的方法

Thread.currentThread() 获得正在执行的线程实例

Thread.sleep(毫秒值) 让正在执行的线程,暂停指定的毫秒值时长

getName(),setName() 线程名

start() 启动线程 interrupt() 打断线程的暂停状态

join() 当前线程暂停,等待被调用的线程结束

setDaemon(true) 后台线程、守护线程

JVM虚拟机退出条件,是所有前台线程结束,当所有前台线程结束,虚拟机会自动退出

不会等待后台线程结束 例如:垃圾回收器是一个后台线程。

线程同步 synchronized

让多个线程共享访问数据时,步调一致的执行。一个线程修改时,其他线程等待修改完成后才能执行;一个线程访问时,其他线程等待访问结束任何实例,都有一个“同步锁”,synchronized 关键字,要求一个线程必须抢到同步锁才能执行

synchronized(对象) { 共享的数据访问代码} --抢对象的锁synchronized void f() {} -- 抢当前实例的锁static synchronized void f() {} --抢类的锁

本文标签:入门基础知识必备

原文链接:https://www.xgfox.com/dmfx/64.html

本文版权:如无特别标注,本站文章均为原创。