文章目录
javaSE
皆来自“狂神说java”和“马士兵”
强类型语言
所有变量都必须先定义才能使用
创建一个扫描器
import java.util.Scanner;
Scanner sc = new Scanner(System.in);
String s = sc.next();//输入字符串
int k = sc.nextInt();//输入整形数
快速输入输出
详见 IO流
BufferedReader bufferedReader
= new BufferedReader(new InputStreamReader(System.in));
PrintWriter printWriter
= new PrintWriter(new OutputStreamWriter(System.out));
如何定义一组类
Node[] Hu = new Node[m];
for (int i = 0 ; i < m ; i++){
Hu[i] = new Node();
}
关于nextInt()之后nextLine()会出错
- 解释
nextInt()方法之后在缓冲区中留下了“\r”,然后nextLine()方法再去缓冲区找数据的时候首先看到了“\r”,然后就把这个“\r”扫描接收进来,并在缓冲区内清除掉 - 解决方法
- 在nextInt()和nextLine()之间加一个nextLine()
int和String的互换
- String ——> int
(1)Integer.parseInt(str)
(2)Integer.valueOf(str).intValue()
- int ——> String
(1)num + “”
(2)String.valueOf(num)
(3)Integer.toString(num)
数据类型所占字节数
- byte——1字节—— -128 ~ 127
- short——2字节
- int——4字节
- long——8字节
- float——4字节
- double——8字节
- char——2字节
- boolean——1位
整数进制表示
- 二进制——0b
- 八进制——0
- 十六进制——0x
浮点数比较问题
float 和 double 存在舍入误差
浮点数比较会结果可能出错
如何用ideal生成javadoc文档

2.
3. 打开输出目录,找到index.html文件。
可变参数实质上是数组
所有异常的超类java.lang.Throwable
异常(Exception)
- 一般有程序员逻辑错误引起
ArrayIndexOutOfBoundsException —— 数组下标越界
ArithmeticException —— 除0异常
NullPointerException —— 空指针异常
ArithmeticException —— 算数异常
MissingResourceException —— 丢失资源
ClassNotFoundException —— 找不到类
ConcurrentModificationException —— 并发修改异常
NotSerializableException —— 未实现Serializable接口
InvalidCastException —— 序列化版本不一致
错误(Error)
- 一般有JVM生成并抛出
OutOfMemoryError —— 内存溢出
修饰符
权限修饰符
| 修饰符 | 当前类 | 同一包内 | 子类(同一包) | 子类(不同包) | 其他包 |
|---|---|---|---|---|---|
| public | √ | √ | √ | √ | √ |
| protected | √ | √ | √ | √ / × | × |
| default(不写时默认) | √ | √ | √ | × | × |
| private | √ | × | × | × | × |
—————————————————————————————
final —— 修饰常量,被final修饰的类不能被继承
super
注意
- super调用父类的构造方法,必须在当前构造方法中的第一个;
- super必须只能出现在子类的方法或构造方法中;
- super 和 this 不能同时调用构造方法;
(因为这两个都必须写在第一个) - 在子类构造方法中会默认写一个super()在第一个;
重写(override)
前提
- 需要有继承关系,子类重写父类的方法;
(该方法不能有修饰符static,final,private) - 方法名和参数列表必须相同;
- 修饰符,范围,可以扩大,但不能缩小;
(如 父类的方法修饰符为default,则子类重写方法修饰符可以为public) - 抛出的异常,范围,可以缩小,但不能扩大
为什么要重写
- 父类的功能,子类不一定需要,或者不一定满足。
多态
多态的定义:
接口的多种不同的实现方式即为多态。
同一方法可以根据发送对象的不同而采用多种不同的行为方式。
一个对象的实例类型(new 后面的)是确定的,但可以指向对象的引用的类型(引用前面的)有很多。如,父类
注意:
1. 多态是方法的多态,属性没有多态性。
2. 在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
多态存在条件:
- 有继承关系
- 子类重写父类方法
- 父类引用指向子类
(如 Father f = new Son() )
(此时父类的引用 f 不能调用指向子类独有的方法和属性)
为什么要用多态
详情点此查看
package stduy;
abstract class Animal{
abstract void eat();
}
class Dog extends Animal{
public void eat() {
System.out.println("啃骨头!");
}
public void LookHome() {
System.out.println("看家!");
}
}
class Cat extends Animal{
public void eat() {
System.out.println("吃鱼!");
}
public void catchMouse() {
System.out.println("抓老鼠!");
}
}
/*
public class Main{
public static void main(String[] args) {
Dog dog = new Dog();
dog.eat();
dog.LookHome();
Cat cat = new Cat();
cat.eat();
cat.catchMouse();
}
}
*/
//----------------------------------------------------
//在不同类调用多个同样行为后会出现大量的代码量
public class Main{
public static void main(String[] args) {
Dog dog = new Dog();
Cat cat = new Cat();
method(dog);
method(cat);
}
public static void method(Animal a) {
a.eat();
}
}
当有多个子类的方法重写同一父类的方法时,多态可以减少代码量,提高可维护性。
instanceof
公式 : x instanceof y
(其中 x 为引用,y 为类)
返回: true 或 false
能否编译通过:x 的数据类型 和 y 之间是否存在父子关系
确定返回值: x 所指向的实例类型是不是 y 的子类型
强制转换
由高到低需要强制转换
子类向父类转换会丢失子类特有的方法;
static
跟类一起加载,且只加载一次
对类而言在内存中只有一个
abstract修饰符
修饰一个类时,该类为抽象类(抽象类存在构造器)
注意
非抽象类不能直接用new创建抽象类,只能靠new它的子类实现它 有子类要继承该抽象类时,必须重写其中的抽象方法。
修饰一个方法时,该方法为抽象方法,只能存在于抽象类中
抽象方法格式:[修饰符] abstract 返回值类型 方法名 ( [参数列表] ) ;
接口
定义
public interface 接口名 { }
接口内可以写方法和属性
方法格式: (默认 public abstract)返回值类型 方法名 ( [参数列表] ) ; 属性格式: (默认 public static final)类型名 变量名 [ = ? ] ;接口不能被实例化(new出来)
因为接口不是类,没有构造器但可以,以匿名内部类(lambda表达式)的方式实现未实现的方法,从而来达到new对象的效果
//以匿名内部类实现,
Port port = new Port(){
@Override
public void add() {
}
@Override
public void delete() {
}
@Override
public void upData() {
}
@Override
public void find() {
}
};
实现
接口都需要一个可以实现它 的类;
用 实现类 implement 接口(类似 extends)[ , 接口 ,…… ] 来实现
(可以实现伪多,即继承可以继承多个父类)子类必须重写所实现接口中的所有方法。
异常处理
有五个关键字:try (监控), catch (捕获), finally (最后都会执行), throw (主动抛出异常), throws(主动抛出异常)
throw一般用在方法中,格式: throw new 想要抛出的异常类型 throws用在方法上 void 方法名 (参数列表) throws 抛出的异常类型 假如在方法中处理不了一个异常,可以用throws把它抛到更高级去处理
//一般结构如下
try {
//-------
}catch (/*想要捕获的异常类型 标识符*/Throwable t){
//-------
//可以有多个catch连用,其中范围最大的放最下面(因为只捕获一个异常)
}finally{//善后工作
//-------
}
- 作用:可以忽略在意料之中的异常,让程序继续执行
- 可以自定义异常(很少会用到)
常用类
包装类
- 什么是包装类
将基本数据类型对应进行封装,产生一个新的类(属于引用数据类型)
- 对应关系
| 基本数据类型 | 对应的包装类 | 继承关系 |
|---|---|---|
| byte | Byte | —> Number —> Object |
| short | Short | —> Number —> Object |
| int | Integer | —> Number —> Object |
| long | Long | —> Number —> Object |
| float | Float | —> Number —> Object |
| double | Double | —> Number —> Object |
| char | Character | —> Object |
| boolean | Boolean | —> Object |
- 存在的意义
因为集合(容器)中只能存 引用数据类型。
- 没有空参构造器
能传 int 或 String
//当输入参数为String类型,且无法转换为 int 类型时,会抛出异常
public Integer(String s) throws NumberFormatException {
this.value = parseInt(s, 10);
}
java.util.Date
可以显示时间,详情见 API 或自行百度
(注:年从1900开始记,月从0开始记)
java.sql.Date
继承自 java.util.Date
常用:valueOf ( 转成Date )
java.text.DateFormat(日期转换类)
这是一个抽象类
java.text.SimpleDateFormat 继承了这个抽象类
一般用代参构造器自定义所需转换的日期格式(详见API)
常用:prase(转成Date),format(转成String)
java.util.Calendar
抽象类,这个类中有一些常量,如YEAR,DATE
java.util.GregorianCalendar 继承
也可以用 Calendar.getInstance() 来创建
常用:
get(如 get(Calendar.DATE_OF_WEAK) )
set(如 set(Calendar.YEAR,1990) )
getActualMaximum(Calendar.DATE)(获取当月的最大天数)
java.time.LocalDate(Time/DateTime)
实例化:(实例化后值不可改变)
- now() (获取当前的信息)
LocalDateTime localDateTime = LocalDateTime.now(); - of() (自己设置信息)
LocalDate localDate = LocalDate.of(2020 , 5 , 1);
get~~~
with----(相当于set,需要一个新的类来承接)
plus----(加)
minus-----(减)
java.time.format.DateTimeFormatter
作用:转换 LocalDateTime 和 String
方法一:自定义格式(常用)
ofPattern( "yyyy-MM-dd hh:mm:ss" )
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
public class Main {
public static void main(String[] args) {
DateTimeFormatter df = DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss");
//LocalDateTime ---> String
LocalDateTime now = LocalDateTime.now();
String format = df.format(now);
System.out.println(format);//2021-05-27 02:58:34
//String ---> LocalDateTIme
TemporalAccessor parse = df.parse("2021-05-27 02:58:34");
System.out.println(parse);
//{MilliOfSecond=0, HourOfAmPm=2, MicroOfSecond=0, MinuteOfHour=58, NanoOfSecond=0, SecondOfMinute=34},ISO resolved to 2021-05-27
}
}
- 以下皆为了解
方法二:预定义标准格式,如 ISO_LOCAL_DATE_TIME,ISO_LOCAL_DATE,ISO_LOCAL_TIME
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;
public class Main {
public static void main(String[] args) {
DateTimeFormatter df = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
//LocalDateTime ---> String
LocalDateTime now = LocalDateTime.now();
String format = df.format(now);
System.out.println(format);//2021-05-27T15:07:13.2636709
//String ---> LocalDateTIme
TemporalAccessor parse = df.parse("2021-05-27T15:07:13.2636709");
System.out.println(parse);//{},ISO resolved to 2021-05-27T15:07:13.263670900
}
}
方法三:本地化相关的格式。如 ofLocalizedDateTime( )
参数:FormatStyle.LONG , FormatStyle.MEDIUM , FormatStyle.SHORT
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.FormatStyle;
import java.time.temporal.TemporalAccessor;
public class Main {
public static void main(String[] args) {
//FormatStyle.LONG
//FormatStyle.MEDIUM 2021年5月27日 下午3:19:56
//FormatStyle.SHORT 2021/5/27 下午3:20
DateTimeFormatter df = DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT);
//LocalDateTime ---> String
LocalDateTime now = LocalDateTime.now();
String format = df.format(now);
System.out.println(format);
//String ---> LocalDateTIme
TemporalAccessor parse = df.parse("2021/5/27 下午3:20");
System.out.println(parse);//{},ISO resolved to 2021-05-27T15:20
}
}
java.lang.Math
构造器私有化,不能被实例化
其中所有的方法和属性都是静态的
调用:Math.方法名
向下取整:ceil()
向上取整:floor()
四舍五入:round()
随机数: random() ----->实际上调的是Random.getDouble()
java.util.Random
计算机中所有的随机数都是伪随机数;
- 有参构造器:参数为种子,若种子相同,则得到的随机数也相同,一般以时间作为种子
- 无参构造器:(实际上还是调用了有参构造器)
常用方法:
nextInt() : 返回下个伪随机数,大小在int范围内
nextInt( int i ) :返回下个伪随机数,大小在 [ 0 , i ) 之间
java.lang.String(不可变字符串)
不可变:在地址不变的情况下,string的值不可能发生变化
String aaa = "aaa";
String bbb = aaa.replace('a','b');
System.out.println(aaa == bbb);//false
常用:
compareTo():比较字符串,返回int
equals():比较字符串,返回boolean
valueOf():转成字符串
tirm():去掉收尾空格
substring():取子串
replace():替换字符串中字符
split():按需切割字符串
toUpperCase():转换成大写
toLowerCase():转换成小写
相等问题
public class Main {
public static void main(String[] args) {
String aaa = "aaa";
String b = "a" + "a" + "a";
String aa = "aa";
String c = new String("aaa");
String d = aa + "a";
System.out.println("aaa == b: " + (aaa == b));//true
System.out.println("aaa == c: " + (aaa == c));//false
System.out.println("aaa == d: " + (aaa == d));//false
System.out.println("c == d : " + (c == d));//false
}
}
==比较的是地址
常量池中创建的字符串具有唯一性。
当直接把字符串例如"aaa"赋给变量aaa时,就是把"aaa"在常量池中的地址赋给变量aaa
变量b在编译时会自动把字符串连起,也就是指向常量池中存在的"aaa",不存在则创建。
所以 aaa == b
new会在堆中开辟地址,然后指向常量池中的"aaa",在把堆中的地址赋给变量c。
所以 aaa != c
-----当把变量 aa 和 “a” 拼接然后赋给变量 d 时,在编译时不会被优化,在代码底层实现中,会先把变量 aa 和 “a” 都转成 StringBuilder类型,然后在拼接,自然 aaa != d.

可变字符串
可变:在 实例化一个可变字符串类然后赋给一个变量 后,该变量所存储的地址不会改变,所以字符串可以改变
StringBuilder sb = new StringBuilder();
System.out.println(sb.append("a") == sb.append("b"));//true
java.lang.StringBuilder
从JDK1.5开始,效率高,线程不安全
无参构造器,相当于初始化了一个长度为 16 的StringBuilder类型字符串
有参构造器:
参数为int,相当于初始化了一个长度为 (参数大小) 的StringBuilder类型字符串
参数为String,相当于初始化了一个长度为 (str的长度 + 16) 的StringBuilder类型字符串
StringBuilder类型的字符串长度不够时会自动加长,(详情可自行深入查看底部代码)
方法
append(" "):在当前字符串尾部追加。
(该方法为链式调用方法,因为该方法返回 return this)
delete():删
deleteCharAt()
insert():改—>插入
replace():改---->替换
charAt():查
subString():截取
java.lang.StringBuffer
基本同StringBuilder
从JDK1.0开始 效率低 线程安全
集合(容器)
数组(容器)的缺点:
- 长度不可变
- 增删效率低
- 没有方法可以得到有效数据的长度
对于无序的,不可重复的数据,数组不能满足要求

集合都可扩容
- List(有索引)
ArrayList:
本质:数组
特点:有序(按输入顺序),可重复Vector:基本和ArrayList一致
LInkedLIst
本质:双向链表
特点:有序,可重复,可以操作头尾结点
- Set
HashSet:
本质:HashMapLinkedHashSet:有序的HashMap
TreeSet:
本质:TreeMap
- Map(key–value结构,重点是key)
HashMap:
本质:哈希表(即 数组+链表)
特点:无序,无重复,重写hashCode,equals方法LinkedHashM:有序的HashMap
HashTable:和HashMap基本一致,但HashTable从JDK1.0开始
TreeMap:
本质:红黑树 (重点在比较器)
特点:有序(按升序或降序排序),无重复,重写比较器
泛型
在JDK1.5之后
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
List < E >,ArrayList < E > 这个 < E > 就是类型参数,即泛型。
(其中的 E 一定是引用数据类型)
泛型可以省略,如果省略,默认泛型是Object类型。
创建:
ArrayList<Integer> arrayList = new ArrayList<>();
例子,可以对应现实中的垃圾分类
- 泛型参数存在继承关系的情况
public class Main {
public static void main(String[] args) {
Object[] o = new Object[9];
String[] s = new String[10];
o = s;//多态
ArrayList<Object> arrayListObject = new ArrayList<>();
ArrayList<String> arrayListString = new ArrayList<>();
//在底层都是用Object数组存储的,不存在继承关系,
//泛型只是在编译时约束数据类型;
//
//! ______ arrayListObject = arrayListString; //报错
}
}
实际上引入泛型的主要目标有以下几点:
类型安全
- 泛型的主要目标是提高 Java 程序的类型安全
- 编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException 异常
- 符合越早出错代价越小原则
消除强制类型转换
- 泛型的一个附带好处是,使用时直接得到目标类型,消除许多强制类型转换
- 所得即所需,这使得代码更加可读,并且减少了出错机会
潜在的性能收益
- 由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改
- 所有工作都在编译器中完成
- 编译器生成的代码跟不使用泛型(和强制类型转换)时所写的代码几乎一致,只是更能确保类型安全而已
泛型类(泛型接口同理)
//泛型类
//____可以定义多个泛型参数
public class Genericity<A,E> {//一般习惯用E,
A i;
E element;
public void a(E e){};
public void a(E[] e){};
}
class Text{
public static void main(String[] args) {
Genericity g = new Genericity();//此时E默认为Object
//实例化的时候指定泛型类
Genericity<String,Double> g1 = new Genericity<>();
g1.element = 3.14;
//! g1.element = 3;
}
}
class Genericity0<E> {
//! ----- public Genericity0<E>(){}
public Genericity0(){}//构造器不能加泛型
E element;
}
//当父类指定了泛型类时,子类不需要再指定
class SubGenericity extends Genericity0<Integer>{}
//当父类没有指定泛型类时,子类需要加上< >
class SubGenericity1<A,E> extends Genericity<A,E>{}
范式类中的静态方法和属性不能使用类的泛型
static A i;//都报错
public static void a(E e){};
- 因为静态的东西是优先于对象存在的
不能直接创建范形参数类型数组
//! A[] a = new A[9];
A[] a = (A[])new Object[9];
泛型方法
public class Genericity<A,E> {
A i;
E element;
public void a(E e){};//不是泛型方法
//可以是静态的, 传参时确定泛型参数类型。
public static <T> void b(T t){};//是泛型方法
}
如上图,方法的参数列表有不是A或E的泛型参数类型即为泛型方法
泛型方法也可以存在于普通类中
通配符


- 用法
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<Integer> list3 = new ArrayList<>();
//通配符 ?
List<?> list = null;
list = list1;
list = list2;
list = list3;
//A 和 B 有继承关系,但 F<A> 和 F<B> 没有继承关系,是并列的
//现在 F<?> 是 F<A> 和 F<B> 的父类
}
}
- 遍历

泛型受限
? extends Person 代表上限是Person,不能高于上限
? super Person 代表下限是Person,不能低于下限
public class Test {
public static void main(String[] args) {
//Student ---> Person ---> Object
List<Object> list1 = new ArrayList<>();
List<Person> list2 = new ArrayList<>();
List<Student> list3 = new ArrayList<>();
//? extends Person 代表 上限 是Person,不能高于上限
List<? extends Person> list0;
//! list0 = list1; //! 报错
list0 = list2;
list0 = list3;
//? super Person 代表 下限 是Person,不能低于下限
List<? super Person> list000;
list000 = list1;
list000 = list2;
//! list000 = list3;//! 报错
}
}
比较器
返回 int 值

- 自定义类的比较器
- 内部比较器
@Override
public int compareTo(Student o) {
/* 比较年龄
return this.age - o.age;
*/
//------------------------------------------------------------
//下面的compareTo是Double类中方法, 重写了Comparable接口的方法
//return ( (Double)(this.high) ).compareTo( (Double)(o.high) );
//-------------------------------------------------------------
//compare是Double类中的方法
return Double.compare((this.high), (o.high));
}
- 外部比较器
优势:可以写多个,而内部比较器只能写一个
class ComparerInt implements Comparator {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
class ComparerDouble implements Comparator {
@Override
public int compare(Object o1, Object o2) {
return 0;
}
}
Collection

接口方法详见API
遍历:能用增强for循环,iterator()

ListIterator
public class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
//想在aa后面加kk
Iterator<String> iterator = list.iterator();
while (iterator.hasNext()){
if (iterator.next().equals("aa")){
list.add("kk");//报异常:ConcurrentModificationException
}
}
}
}
原因: iterator 和 list 同时操作同一个集合。
所以引入ListIterator
public class Test {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
list.add("dd");
//想在aa后面加kk
ListIterator<String> iterator = list.listIterator();
while (iterator.hasNext()){
if (iterator.next().equals("aa")){
iterator.add("kk");
}
}
//逆向遍历
while (iterator.hasPrevious()){
iterator.previous();
}
System.out.println(list);
}
}
HashSet
特点:无序,数据不重复
注意:
放入HashSet中的数据,一定要重写 hashCode , equals 方法

Map

HashMap
public class Test {
public static void main(String[] args) {
Map<String, Integer> map = new HashMap<>();
map.put("a",111);
map.put("a",222);
map.put("b",1010);
System.out.println(map);//{a=222, b=1010}
Map<String, Integer> map1 = new HashMap<>();
map1.put("a",1);
map1.put("a",222);
map1.put("b",1010);
System.out.println(map1);//{a=222, b=1010}
System.out.println(map.equals(map1));//true
map1.remove("a");
System.out.println(map1);//{b=1010}
}
}
- 发生哈希冲突时,只替换value不替换key。
负载因子为什么是0.75?
原因:
若是设置为1:则扩容边界和数组长度相等,空间利用率高---->容易发生哈希碰撞,产生链表的几率高------->查询效率低
若设置为0.5:则扩容边界是数组长度的一半,空间利用率低 ---->发生哈希碰撞和产生链表的概率低------>查询效率高
所以折中取0.75
Collections工具类
类似Arrays工具类和Math类
构造器私有化,只能通过 类名.方法名(属性名)调用
IO流
字符流能操作 ——文本文件
字节流能操作 ——非文本文件
(在utf-8编码中,中文字符在底层占3个字节)
文件以 -1 结尾
File类(只能获得表层信息)
创建:File f = new File("d:" + File.separator + "text.txt");
其中File.separator 可以获取当前操作体统的路径拼接符号
| 方法名 | 作用 |
|---|---|
| canRead() | 是否可读 |
| canWrite() | 是否可写 |
| getName() | 得到文件名 |
| getParent() | 得到上级目录 |
| getAbsolutePath() | 得到绝对路径 |
| getPath() ( toString() ) | 得到相对路径 |
| isDirectory() | 是否为目录 |
| isFile() | 是否为文件 |
| isHidden() | 是否隐藏 |
| length() | 文件大小 |
| exists() | 是否存在 |
| delete() | 删除 |
| createNewFile() | 创建 |
| equals() | 比较路径 |
| 对目录 | |
| delete() | 只会删除一层(且这一层里面必须为空) |
| list() | 查看文件下所有,返回String[] |
| listFile() | 查看文件下所有,返回File[] |
IO流的体系结构

FileReader和FileWriter
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
public class Test {
public static void main(String[] args) throws IOException {
//文件-----> 程序//FileReader
//----------------
//1.创建File对象
File f = new File("text.txt");
//2.创建FileReader对象,传入File对象,抛出异常
FileReader fileReader = new FileReader(f);
//3.读取字符
//
//(1)一个字符一个字符的读 —————— read(),返回ASCII码值
/*
int n;
while ((n = fileReader.read()) != -1){//文本文件以-1结尾
System.out.print((char)n + " ");
}
System.out.println("\n-----------------------");
*/
//
//(2)一堆字符一起读 ————————read(char[]),返回有效长度
char[] ch = new char[5];//缓冲数组
int len;
while ((len = fileReader.read(ch)) != -1){
String s = new String(ch,0,len);
//有效长度?-----》数组是同一个,只能反复覆盖
System.out.print(s);
}
//4.关闭流
fileReader.close();
//程序————> 文件//FileWriter
//1.创建目标文件对象,若不存在则自动创建
File file = new File("text0000.txt");
//2.创建FileWriter对象,传入File对象,true为追加,false为覆盖(默认)
FileWriter fileWriter = new FileWriter(file, true);
//3.写入字符
//
//(1)一个一个字符写入
fileWriter.write('a');
//(2)一堆一堆字符写入
fileWriter.write("abcdefg");
//4.关闭流
fileWriter.close();
}
}
FileInputStream和FileOutputStream
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
//1.创建File对象
File f = new File("cry.jpg");
File file = new File("cryyyyy.jpg");
System.out.println(f.length());
//2.创建FileReader对象,传入File对象,抛出异常
FileInputStream fileInputStream = new FileInputStream(f);
//2.创建FileOutputStream对象,传入File对象,true为追加,false为覆盖(默认)
FileOutputStream fileOutputStream = new FileOutputStream(file);
//3.读取/写入字节
//
//一堆字节一起读 ————————read(byte[]),返回有效长度
byte[] b = new byte[1024 * 5];//缓冲数组
int len;
while ((len = fileInputStream.read(b)) != -1){
fileOutputStream.write(b,0,len);
//有效长度?-----》数组是同一个,只能反复覆盖
}
//4.关闭流
fileOutputStream.close();
fileInputStream.close();
}
}
BufferedInputStream和BufferedOutputStream
(处理流)(缓冲流)
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
//1.创建File对象
File f = new File("cry.jpg");
File file = new File("cryyyyy.jpg");
System.out.println(f.length());
//2.创建FileReader对象,传入File对象,抛出异常
FileInputStream fileInputStream = new FileInputStream(f);
//2.创建FileOutputStream对象,传入File对象,true为追加,false为覆盖(默认)
FileOutputStream fileOutputStream = new FileOutputStream(file);
//2.创建处理流BufferedInputStream和BufferedOutputStream
//----------------------------
//功能加强----多了两个缓冲区,使程序尽可能少的访问内存,缓冲数组读写缓冲区
BufferedInputStream bufferedInputStream
= new BufferedInputStream(fileInputStream);
BufferedOutputStream bufferedOutputStream
= new BufferedOutputStream(fileOutputStream);
//3.读取/写入字节
//
//一堆字节一起读 ————————read(byte[]),返回有效长度
byte[] b = new byte[1024 * 5];//缓冲数组读写缓冲区------------
int len;
//底层会自动刷新缓冲区 bufferedOutputStream.flush()
while ((len = bufferedInputStream.read(b)) != -1){
bufferedOutputStream.write(b,0,len);
//有效长度?-----》数组是同一个,只能反复覆盖
}
//---------------------------------------------
//4.关闭流,只要关闭高级流(外层的处理流),被包含的节点流也会被关闭
bufferedOutputStream.close();
bufferedInputStream.close();
}
}
BufferedReader和BufferedWriter
读:readLine() ————> 读一行
写:newLine() ————> 新起一行(换行)
InputStreamReader和OutputStreamWriter
(处理流)(转换流)
在创建对象时,需要制定一个编码(如 utf-8),不写则默认获取程序的编码
System.in和System.out
System.in(从键盘录入)
返回的是InputStream(标准输入流)System.out(输出到控制台)
返回的是PrintStream(输出流)(打印流)
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
public class Test {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
int read = in.read();//等待键盘输入,所以这是一个阻塞方法
//在 new Scanner(System.in)中出现过
//所以Scanner只是一个扫描器,而且可以传入其他IO流参数
PrintStream out = System.out;
out.println(read);
}
}
键盘输入到文件
import java.io.*;
public class Test {
public static void main(String[] args) throws IOException {
InputStream in = System.in;
InputStreamReader inputStreamReader = new InputStreamReader(in);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
File file = new File("in.txt");
FileWriter fileWriter = new FileWriter(file);
BufferedWriter bufferedWriter = new BufferedWriter(fileWriter);
String s = bufferedReader.readLine();
while (!s.equals("exit")){//当碰到有 一行 和"exit"相等时才结束。
bufferedWriter.write(s);
bufferedWriter.newLine();
s = bufferedReader.readLine();
}
bufferedWriter.close();
bufferedReader.close();
}
}
DataInputStream和DataOutputStream
(数据流)
DataInputStream
将文件中的基本数据类型和字符串 写入 内存变量中。DataOutputStream
将内存中的基本数据类型和字符串的变量 写出 文件中
(文件中的东西是给程序看的,我们看不懂)
ObjectInputStream和ObjectOutputStream
- 序列化
把内存中的Java对象转换成平台无关的二进制数据,从而允许把这种二进制数据永久保存在磁盘上,或通过网络将这种二进制数据传输到另一个网络节点 - 反序列化
当其他程序获取了这种二进制数据,就可以恢复成原来的Java对象
想要序列化的对象所在类必须要实现 Serializable 接口
这个接口是标识接口(里面什么都没有)
只有实现了Serializable接口的类才能序列化
具体代码如下
import java.io.*;
class Czc implements Serializable{
int anInt;
String s;
Double aDouble;
public Czc(int anInt, String s, Double aDouble) {
this.anInt = anInt;
this.s = s;
this.aDouble = aDouble;
}
}
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
ObjectOutputStream objectOutputStream
= new ObjectOutputStream(new FileOutputStream(new File("Object.txt")));
ObjectInputStream objectInputStream
= new ObjectInputStream(new FileInputStream(new File("Object.txt")));
objectOutputStream.writeObject(new Czc(1,"-----",0.9));
Czc o = (Czc)objectInputStream.readObject();
System.out.println(o);//Experance.Czc@1ed6993a
System.out.println(o.aDouble);//0.9
System.out.println(o.s);//-----
objectInputStream.close();
objectOutputStream.close();
}
}
- 序列号
某个对象实现了Serializable,java虚拟机会对加上Serializable的对象做一些特殊的处理,就是加上版本号SerialversionUID(java虚拟机的特殊照顾,加上SerialversionUID)
(尽量自己写出这个序列号)
(自动分配这个UID时,文件里的UID可能和实际上不一样)
因为文件里的序列号是写死的,在类中更新任何内容后又会重新分配序列号,
所以可能会出现不匹配,报异常

在IDEA中配置序列号(快速生成)
然后在类上alt+enter
注意:
- 被序列化的类的内部的所有属性,必须都是可序列化的
(基本数据类型和String是可直接序列化的) - static,transient修饰的属性,不可以被序列化