Java 总结

Java 一二讲

匿名数组

//将a赋值{-1, 0, 1};
int[] a;
//不能a = {-1, 0, 1};
a = new int[]{-1, 0, 1}; //匿名数组

二维数组

int[][] a = {{1},
             {1, 2},
             {1, 2, 3}};

//访问
for(int[] e1 : a){
    for(int x : e1){}
}

拼接数字

byte b1 = (byte)(0xaa), b2 = (byte)(0xbb), b3 = (byte)(0xcc), b4 = (byte))0xdd;
int i = b1 << 24 | (b2 << 16) & 0x00ff0000 | (b3 << 8) & 0x0000ff00 | b4 & 0x000000ff;

数逆序

public static int reverse(int n, int m){
   return n == 0 ? m : reverse(n / 10, m * 10 + n % 10);
}

Java 第四讲

数组 Arrays

fill(array, value);
sort(array);
arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
Arrays.binarySearch(int[] a, int key);
//插入位置 -(pos) - 1

String

java.lang.String 类代表的是只读的不可以修改的字符序列

String s1 = "Hello";
String s2 = "Hello";
String s3 = new String("Hello");
String s4 = new String("Hello");

s1 == s2; // true
s2 == s3; // false
s3 == s4; // false

判断字符串值是否相等,不允许使用 ==, 需要使用equals

  • 类的构造器必须有,没有构造器,自动生成一个默认无参构造器。
  • 有构造器,则不会创建构造器。

Java 第五讲

static

public class TA{
	static int sa = 10;
	int vb = 20;
    TA self = this;
    
	void f(){ // 对象的方法成员
		//最本质区别:可使用this
        TA.sa = 50;
        this.vb = 260;
        vb = 270; // this.vb = 270;
	}
    
    void f(TA t){
        TA.sa = 100;
        vb = 100; // this.vb = 100;
        t.vb = 200;
    }
    
	static void g(){ // 类的方法成员
		//最本质:不可使用this(不存在)
        TA.sa = 100;
        sa = 200; // TA.sa = 200;
        vb = 300; // error
        TA t = new TA();
        t.vb = 300;
	}
    
    static void g(TA t){
        sa = 100; // TA.sa = 100;
        t.vb = 200;
    }
	
	public static void main(String[] args){
		TA.sa = 100;
		sa = 300; // TA.sa = 300;
		TA t1 = new TA();
	}
}

重载,重写,隐藏

img

public class TB{
	void f(){
		S.o.p("null");
	}
	void f(byte b){
		S.o.p("byte!");
	}
	void f(long l){
		S.o.p("long!");
	}
	void f(double d){
		S.o.p("double");
	}
    
	void g(Object o){ //宽
		S.o.p("Object!");
	}
    void g(int[] a){  //窄 
        S.o.p("int[]!");
    } 
    
    static void h(){
        
    }
    static void h(){
        
    }
    
	public static void main(String[] args){
		TB t = new TB();
		t.f((byte)2); // byte!
		t.f((char)2); // long!
					  // char -> int -> long -> float -> double
		
        t.g(null); // 先窄后宽
	}
}

继承:

public class Point{
	private x, y;
	public Point(int x, int y){
		this.x = x;
		this.y = y;
	}
	public Point(){} //若无,子类报错
}

public class Point3D{
	private z;
	public Point3D(int x, int y, int z){
		super(x, y);
		this.z = 0;
	}
	public Point3D(){
		this(0, 0, 0);
	}
	public Point3D(int x){
		//自动加上:super(); 默认构造器, 若父类无默认构造器,则报错。	
		this.z = 20;
	}
}
public class FA{
	public void f(){
		S.o.p("FA -> f()");
	}
}
public class SubB extends FA{
	public void f(){
		S.o.p("SubB -> f()");
	}
}
public class Test{
	public static void main(String[] args){
		FA fa = new FA();
		fa.f(); //FA -> f()
		SubB sb = new SubB();
		s.f(); //SubB -> f()
        
        //向上转型:
        FA fa1 = new SubB();
        fa1.f(); //SubB -> f()
	}
}
  • 方法重写只针对非static方法。

  • static方法没有重写,只有隐藏和重载。

  • 参数名和参数列表完全相同,返回值:基本类型必须相同;引用类型要相容。

  • super.f()调用的是重写之前的方法。

Test

public class FA{
	int x = 10;
	static int y = 20;
	public void f(){
		S.o.p("FA->f()");
	}
	public static void g(){
		S.o.p("FA->g()");
	}
}

public class FB extends FA{
    int x = 100;
	static int y = 200;
	public void f(){
		S.o.p("FB->f()");
	}
	public static void g(){ //隐藏
		S.o.p("FB->g()");
	}
}

public class Test{
    public static void main(String[] args){
        FA fa = new FB();//
        S.o.p("x = " + fa.x); // 10;
        fa.f(); //FB->f() 
        fa.g(); //FA->g()
        S.o.p("y = " + fa.y) // 20;
    }
}

Java 第六讲

public,protected,private,默认

package java1;

public class CA1{
	private int x = 1; //只能在本类自身内部才有访问它!
	
	int y = 2; //属于同一个包的类都可访问它!
	
	protected int z = 3;//属于同一个包或不同包但必需是子类都可以访问
    					//(不同包的子类是通过继承的方式来访问的!)
	
	public int w = 4; // 任何类都可以访问它!(无论是不是同一个包)
	
	public void f();
}
package java2;

public class CB2 extends CA1{
	public void f(CA1 o){
        /**
        	访问o.×出错!因为x只能在CA1本类自身内部访问,在外部不允许访问!
        	访问o.y出!因为y只能在属于同一个包的类中访问!
        	访问o.z出错!不同包的话,必需是子类且是继承的数据或方法。
        	访问this.z正常!因为是继承的z。
        **/
		S.o.p("x = " + o.x + 
			  "y = " + o.y + 
			  "z = " + o.z +
			  "继承的z = " + this.z +
			  "继承的z = " + super.z +
			  "w = " + o.w); 
	}
}

重写

  • 重写是针对对象的方法,要求非static方法。
  • 是static方法,没有重写,只有重载或者隐藏。
  • 条件:方法名和方法参数必须一样。
  • 返回值类型:基本数据类型则必须一样;若是引用,必须相容。(父类:Object类,子类:String类)

向上转型

A a = new B(); 除了子类重写父类的方法,其他都是父类A的成员。


单例模式

public class Singleton{
	private Singleton(){}
	private static Singleton obj = new Singleton();
    public static getObj(){
    	return obj;
    }
}
  • 恶汉式单例模式
  • 懒汉式单例模式
  • DCL单例模式,双重锁机制
  • 反射可以破坏单例模式
  • 反射不可以破坏枚举的单例模式

Java 第七讲:

接口:

  1. 类之间只能单一继承(只有一个父类。)
  2. 类没有明确extends,则默认Object类
  3. 接口之间多重继承
  4. 类可以实现多个接口

抽象类:

区别:

  • 抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。

  • 默认的方法实现

    抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现。

  • 抽象类可以有构造器,而接口不能有构造器


内部类:

public class Outer{
	private int i = -1;
	private static int j = -2;
    //非staic类型
	class Inner{ //内部类
		private int i = 1;
		public void f(int i){
			Outer.this.i = this.i + i; //外部类的变量访问:外部类类名.this.变量名
			S.o.p("Outer.i = " + Outer.this.i);
		}
	}
    //static类型
    //只能访问static类型的成员,没有this
    static class Inner_2{
        public void f(){
            S.o.p("Outer.j" + Outer.j);
        }
    }
}
  • 非static类型:

Outer.Inner oi = new Outer.Inner() × 未指定是哪一个Outer.this对象

生成Inner对象时必须指定Outer.this对象

Outer o = new Outer()

Outer.Inner oi = o.new Inner()

  • staic类型 :

    Outer.Inner_2 oi2 = new Outer.Inner_2()

局部内部类:

public class Outer{
	private int i = -1;
	private static int j = -2;
    
	class Inner{ //内部类
		private int i = 1;
		public void f(final int i){
			final int w = 20; //局部内部类可以访问方法内的final变量
			class LocalClass{
				private int i = 100;
				public void f(){
					Outer.this.i = Inner.this.i + i + this.i + w; // -1, 1, f(), 100
                    S.o.p("Outer.this.i = " + Outer.this.i);
				}
			}
		}
	}
}

Java 第八讲:

public  class Outer{
	private int i;
	public void f(){}
	public class Inner_1{}
	public static class Inner_2{}
}

内部类:

  1. 不能使用Outer.this

  2. static类型的内部类直接初始化:Outer.Inner_2 oi = new Outer.Inner_2()

  3. 非static类型的内部类对象初始化:Outer o = new Outer()

Outer.Inner_1 oi2 = o.new Inner_1()


局部内部类:非static类型,可以访问方法内final类型的局部变量。

public void g(){
	final int m = 10;
	public void f(final int x){
        class Local{} // <-局部内部类
    }
}

匿名内部类:

Runnable类,Thread类

public class Outer{
	private int i = 40;
    /*
	private class MyWork implements Runnable {
		@Override
		public void run(){
			S.o.p("i = " + i);
		}
	}
    MyWork m = new MyWork();
    Thread t = new Thread(m);
    */
    //改为匿名内部类:
	Thread t1 = new Thread(
    	new Runnable(){
            @Override
			public void run(){
				S.o.p("i = " + i);
			}
        }
    );
    
    //局部匿名内部类
    public void g(final int no){
        /*
        class MyWork1 implements Runnable{
            @Override
            public void run(){
                S.o.p("i = " + i + " no =" + no);
            }
        }
        MyWork1 w = new MyWork1();
        new Thread(w).start();
        */
        
        //①
        new Thread(
        	new Runnable(){
                @Override
                public void run(){
                    S.o.p("i = " + i + " no =" + no);
                }
            }
        ).start();
       	
        // JDK8:
        new Thread(
            //lambda 表达式
        	()/*参数列表*/ -> S.o.p("i = " + i + " no =" + no);
        ).strat();
    }
}

类的初始化块

public class CA{
	private static int i = 10;
	static{ // <--类的初始化块
		S.o.p("i = " + i + " j = " + j);
	}
	private static int j = 20;
}

​ 执行过程:

  1. 类代码(.class)从硬盘调到内存中时,执行类的初始化动作。

  2. 类的初始化动作:

    按照定义的先后次序,依次进行初始化。

​ 编译器把代码重整:

public class CA_New{
	private static int i = 0;
	private static int j = 0;
	static {
		i = 10;
		S.o.p("i = " + i + " j = " + j); // -> i = 10, j = 0
		j = 20;
	}
}

执行次序

  • 父类的初始化 (1. 父类 硬盘 - > 内存, 2. 类的初始化)
  • 自己的类的初始化(1. 自己 硬盘 - > 内存 2.类的初始化)

对象的初始化块

流程:

* 所有的类的初始化(块)
* 所有的1. 对象的初始化块和2. 构造器
public class CA{
	private static int i = 10;
    int k = 30;
	static{ // <--类的初始化块
		S.o.p("i = " + i + " j = " + j);
	}
	private static int j = 20;
    {
        S.o.p("对象初始化块:k = " + k);
    }
    public CA(){
        S.o.p("构造器: k = " + k);
    }
    public static void main(String[] args){
        new CA();
        new CA();
    }
}
/*
1. 
i = 10,j = 0
对象初始化块: k = 30
构造器:k = 30
2.
对象初始化块: k = 30
构造器:k = 30
*/

Java第九讲

  • equals()方法:

    //源码
    public boolean equals(Object obj){ 
    	return (this == obj);
    }
    
  • hashCode() 方法:需要重写

    如果obj1.equals(obj2),则obj1.hashCode() == obj2.hashCode()

  • toString() 方法:需要重写

    //源码:
    public String toString(){
    	reutrn getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    

包装类

>- byte -> Byte
>- short -> Short
>- int -> Integer
>- long -> Long
>- float -> Float
>- double -> Double
>- boolean -> Boolean
>- char -> Character
  • 所有的包装类都是final类型,不能创建他们的子类。
  • 包装类是不可变类,同(String)类。
  • 自动装箱,自动拆箱。 数值3 - > 对象3 对象3 - > 数值3
  • 将字符串转换为基本值的parseType()方法,如Integer.parseType(args[0])
  • 与String类的转换

Java 第十讲

正则表达式语法

字符 说明
\ 将下一字符标记为特殊字符、文本、反向引用或八进制转义符。例如,"n"匹配字符"n"。"\n"匹配换行符。序列"\\"匹配"\","\("匹配"("。
^ 匹配输入字符串开始的位置。如果设置了 RegExp 对象的 Multiline 属性,^ 还会与"\n"或"\r"之后的位置匹配。
$ 匹配输入字符串结尾的位置。如果设置了 RegExp 对象的 Multiline 属性,$ 还会与"\n"或"\r"之前的位置匹配。
* 零次或多次匹配前面的字符或子表达式。例如,zo* 匹配"z"和"zoo"。* 等效于 {0,}。
+ 一次或多次匹配前面的字符或子表达式。例如,"zo+"与"zo"和"zoo"匹配,但与"z"不匹配。+ 等效于 {1,}。
? 零次或一次匹配前面的字符或子表达式。例如,"do(es)?"匹配"do"或"does"中的"do"。? 等效于 {0,1}。
{n} n 是非负整数。正好匹配 n 次。例如,"o{2}"与"Bob"中的"o"不匹配,但与"food"中的两个"o"匹配。
{n,} n 是非负整数。至少匹配 n 次。例如,"o{2,}"不匹配"Bob"中的"o",而匹配"foooood"中的所有 o。"o{1,}"等效于"o+"。"o{0,}"等效于"o*"。
{n,m} mn 是非负整数,其中 n <= m。匹配至少 n 次,至多 m 次。例如,"o{1,3}"匹配"fooooood"中的头三个 o。'o{0,1}' 等效于 'o?'。注意:您不能将空格插入逗号和数字之间。
? 当此字符紧随任何其他限定符(、+、?、{n}、{n,}、{n,m*})之后时,匹配模式是"非贪心的"。"非贪心的"模式匹配搜索到的、尽可能短的字符串,而默认的"贪心的"模式匹配搜索到的、尽可能长的字符串。例如,在字符串"oooo"中,"o+?"只匹配单个"o",而"o+"匹配所有"o"。
. 匹配除"\r\n"之外的任何单个字符。若要匹配包括"\r\n"在内的任意字符,请使用诸如"[\s\S]"之类的模式。
(pattern) 匹配 pattern 并捕获该匹配的子表达式。可以使用 \(0…9\) 属性从结果"匹配"集合中检索捕获的匹配。若要匹配括号字符 ( ),请使用"("或者")"。
(?:pattern) 匹配 pattern 但不捕获该匹配的子表达式,即它是一个非捕获匹配,不存储供以后使用的匹配。这对于用"or"字符 (|) 组合模式部件的情况很有用。例如,'industr(?:y|ies) 是比 'industry|industries' 更经济的表达式。
(?=pattern) 执行正向预测先行搜索的子表达式,该表达式匹配处于匹配 pattern 的字符串的起始点的字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?=95|98|NT|2000)' 匹配"Windows 2000"中的"Windows",但不匹配"Windows 3.1"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
(?!pattern) 执行反向预测先行搜索的子表达式,该表达式匹配不处于匹配 pattern 的字符串的起始点的搜索字符串。它是一个非捕获匹配,即不能捕获供以后使用的匹配。例如,'Windows (?!95|98|NT|2000)' 匹配"Windows 3.1"中的 "Windows",但不匹配"Windows 2000"中的"Windows"。预测先行不占用字符,即发生匹配后,下一匹配的搜索紧随上一匹配之后,而不是在组成预测先行的字符后。
x|y 匹配 xy。例如,'z|food' 匹配"z"或"food"。'(z|f)ood' 匹配"zood"或"food"。
[xyz] 字符集。匹配包含的任一字符。例如,"[abc]"匹配"plain"中的"a"。
[^xyz] 反向字符集。匹配未包含的任何字符。例如,"[abc]"匹配"plain"中"p","l","i","n"。
[a-z] 字符范围。匹配指定范围内的任何字符。例如,"[a-z]"匹配"a"到"z"范围内的任何小写字母。
[^a-z] 反向范围字符。匹配不在指定的范围内的任何字符。例如,"[a-z]"匹配任何不在"a"到"z"范围内的任何字符。
\b 匹配一个字边界,即字与空格间的位置。例如,"er\b"匹配"never"中的"er",但不匹配"verb"中的"er"。
\B 非字边界匹配。"er\B"匹配"verb"中的"er",但不匹配"never"中的"er"。
\cx 匹配 x 指示的控制字符。例如,\cM 匹配 Control-M 或回车符。x 的值必须在 A-Z 或 a-z 之间。如果不是这样,则假定 c 就是"c"字符本身。
\d 数字字符匹配。等效于 [0-9]。
\D 非数字字符匹配。等效于 [0-9]。
\f 换页符匹配。等效于 \x0c 和 \cL。
\n 换行符匹配。等效于 \x0a 和 \cJ。
\r 匹配一个回车符。等效于 \x0d 和 \cM。
\s 匹配任何空白字符,包括空格、制表符、换页符等。与 [ \f\n\r\t\v] 等效。
\S 匹配任何非空白字符。与 [ \f\n\r\t\v] 等效。
\t 制表符匹配。与 \x09 和 \cI 等效。
\v 垂直制表符匹配。与 \x0b 和 \cK 等效。
\w 匹配任何字类字符,包括下划线。与"[A-Za-z0-9_]"等效。
\W 与任何非单词字符匹配。与"[A-Za-z0-9_]"等效。
\xn 匹配 n,此处的 n 是一个十六进制转义码。十六进制转义码必须正好是两位数长。例如,"\x41"匹配"A"。"\x041"与"\x04"&"1"等效。允许在正则表达式中使用 ASCII 代码。
num 匹配 num,此处的 num 是一个正整数。到捕获匹配的反向引用。例如,"(.)\1"匹配两个连续的相同字符。
n 标识一个八进制转义码或反向引用。如果 n 前面至少有 n 个捕获子表达式,那么 n 是反向引用。否则,如果 n 是八进制数 (0-7),那么 n 是八进制转义码。
nm 标识一个八进制转义码或反向引用。如果 nm 前面至少有 nm 个捕获子表达式,那么 nm 是反向引用。如果 nm 前面至少有 n 个捕获,则 n 是反向引用,后面跟有字符 m。如果两种前面的情况都不存在,则 nm 匹配八进制值 nm,其中 nm 是八进制数字 (0-7)。
\nml n 是八进制数 (0-3),ml 是八进制数 (0-7) 时,匹配八进制转义码 nml
\un 匹配 n,其中 n 是以四位十六进制数表示的 Unicode 字符。例如,\u00A9 匹配版权符号 (©)。
S.o.p("A".matches("\\x41")); //十六进制匹配字符
 [\\u4e00 - \\u9fa5]           //表示一个汉字

最小最大匹配

字符串:abcabcabcabcabc
最小匹配:a.*c  //任一字符0次或多次
最大匹配:a.*?c    //非贪婪匹配

英文单词或汉字:
^[a-zA-Z]*|[\u4e00-\u9fa5]*$

在正则表达式中引用与该组相匹配的内容。

((A)(B(C)))
1. ((A)(B(C)))
2. (A)
3. (B(C))
4. (C)
//0号组代表整个正则表达式
习题
C16O12H2N5  --算分子量
"([CHON](\d)*)"
Pattern pattern = Pattern.compile("([CHON](\\d*))(\\1)*"); 
// 第1组:([CHON](\\d+))
// 第2组:(\\d+)
// [CHON] CHON中一个字符
// (\\d*)0个或多个数字
// (\\1)第一组
// *第一组0个或多个
Matcher matcher = pattern.matcher(s);
double sum = 0.0;
while(matcher.find()){
	System.out.print(matcher.group(1).charAt(0) + " ");
	System.out.println(matcher.group(2));
	sum += C(matcher.group(1).charAt(0)) * Double.parseDouble(matcher.group(2));
}

用HashMap
字符压缩
aaavvcdddq222(((333)))
s.replaceAll("(.)(\\1)*", "$1");
// regx: 1号组:(.)
// (\\1) 与1号组相匹配的内容
// * 0次或多次
// $1 / [$1] 1号组

分割

String s = "  copy c:/a.txt  d:/e.txt   ";
String[] str = s.split("\\s+", num); //num小于0表示显示末尾空串,大于零表示分割成几份
for(String e : ss){
    sout("-->" + e);
}

//--> 
//-->c:/a.txt
//-->d:/e.txt
//没有末尾空
//匹配数字
s = "aasfs43124fafa654gsddg6(3424)fa)";
String str = s.split("[^0-9]+");//以非数字分割

抓取

//匹配数字
s = "aasfs43124fafa654gsddg6(3424)fa)";
Pattern pattern = Pattern.compile("\\d+"); //"\\d{1,4}"1到4位数字
Matcher matcher = pattern.matcher(s);
while(matcher.find()){
    String str = matcher.group();
}
//替换
appendReplacement();
appendTail();
System.out.println("请输入模板串:");
String temp = in.nextLine();
System.out.println("请输入数据源串:");
String src = in.nextLine();
String[] aim = src.split(",");
Map<String, String> map = new HashMap<>();
for(String sp : aim){
	if(sp > 0){
        String[] r_e = e.split(":", 2);
        map.put(r_e[0], r_e[1]);
    }
}
Pattern pattern = Pattern.compile("\\$\\{([\\u4e00-\\u9fa5]+?)\\}");
Matcher matcher = pattern.matcher(temp);
StringBuilder sb = new StringBuilder();
while(matcher.find()){
	//System.out.println(matcher.group(1));
	matcher.appendReplacement(sb, map.get(matcher.group(1)));
}
matcher.appendTail(sb);
System.out.println("结果:" + sb.toString());

Java 异常

img

异常处理

  • 检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
  • 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
  • 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。

img


语义

try{
    f1();
    f2();
    f3();
}
catch(MyExcptyion e1){}
catch(MyException e2){}
finally{}

无论是否抛出异常,finally语句块都会执行。

java抛出异常的三种情况:

  • 首先执行try块,若没有异常,则直接执行finally块。
  • 若执行f1()块抛出异常,f2(),f3()方法不会被执行,程序直接跳至第一条catch语句。如果抛出的异常与e1相符,执行e1语句块,不匹配跳到第二个catch语句。最后执行finally语句。
    • 判断是否相匹配用语句instanceof
  • 若执行try块抛出异常,并且catch语句块没有与之相匹配的异常,那么先执行finally语句块,然后向外抛出异常。

public class KBException extends IOException{
    String str;
	KBException(String _str) {
		this.str = _str;
	}
	public String toString() {
		sout(str);
	}
}

public class KBPress{
    public static int read() throws KBException{
        //throws是声明异常。
        int ch;
        try{
            ch = System.in.read();
            if(ch == 'A'){
                throw new KBException ("A键已坏");
            }
        }
        catch(IOException e){
            throw new KBException(e.getMessage());
            //throw是抛出异常。
        }
        return ch;
    }
}

public class Client{
    public static String[] main(String[] args){
        int ch;
        try{
	        while((ch = KBPress.read()) != -1){
    	        sout("" + ch);
    	    }
        }catch(KBException e){
            sout("" + e.getMessage());
        }
    }
}
try{
    //异常
    return 1;
}
catch(){
    return 2;
}
finally{
    return 3;
}
  • 无论有没有异常,都要执行finally,所以都是return 3;
FA -> FB
//FB继承FA
catch()语句的顺序一定是从小到大,否则FB永远不会执行

Java IO

img

字节流:

输入流

image-20200609080923786

abstract int read() throws IOException
/*
功能:读取一个字节数据,并返回读到的数据,如果返回-1,表示读到了输入流的末尾。
*/
int read(byte[] b) throws IOException
/**
功能:从输入流中读取一定数量的字节,并将其存储在缓冲区数组b中,并以整数形式返回实际读取的字节数,如果返回-1,表示读到了输入流的末尾。
*/
//读取尽可能多的数据
int read(byte[] b, int off, int len) throws IOException:
/**
功能:将数据读入一个字节数组,同时返回实际读取字节数,如果返回-1,表示读到了输入流的末尾。off指定在数组b中存放数据的起始偏移位置,len指定读取的最大字节数。如果返回-1,表示读到了输入流的末尾。
*/

输出流

image-20200609084625844

abstract void write(int b) throws IOException:
// 将b的最低的一个字节写入此输出流,b的高位字节(3个)丢弃。
void write(byte[] b) throws IOException
// 将b.length个字节从指定的byte数组写入此输出流。
void write(byte[] b,int off,int len)throws IOException
// 将指定byte数组中从偏移量 off 开始的len个字节写入此输出流。
void flush()throws IOException
// 刷新此输出流并强制写出所有缓冲的输出字节。
void close()throws IOException
// 关闭此输出流并释放与此流有关的所有系统资源。

InputStream/OutputStream

在键盘上读入,在屏幕上输出,按ctrl+z结束

//java换行:13 10
class Exp1{
    public static void main(String[] args) throws Exception{
        int ch;
        while((ch = System.in.read()) != -1){
           	System.out.println(ch);
        }
    }
}

FileOutputStream/FileInputStream

处理文件

FileOutputStream(String name, boolean append) throws FileNotFoundException
//功能:创建一个向具有指定name的文件中写入数据的输出文件流。如果第二个参数为 true,则以添加方式写入字节,文件中的原有内容不会被清除。
class Exp2{
    public static void main(String[] args) throws Exception{
        //没有文件则添加,有文件就删除,
        FileInputStream fileInputStream = new FileInputStream("F://1.jpg");
        //
        FileInputStream fileInputStream = new FileInputStream("F://1.jpg", true);
        FileOutputStream fileOutputStream = new FileOutputStream("F://2.jpg");
        int ch2;
        while((ch2 = fileInputStream.read()) != -1){
            fileOutputStream.write(ch2);
        }

        fileOutputStream.close();
        fileInputStream.close();
    }
}

键盘到文件:

class Exp3{
    public static void main(String[] args) throws Exception{
        FileOutputStream fileOutputStream = new FileOutputStream("D://1.dat");
        int ch2;
        while((ch2 = System.in.read()) != -1){
            fileOutputStream.write(ch2);
        }

        fileOutputStream.flush();
        fileOutputStream.close();
    }
}

DataInputStream/DataOutputStream

装饰模式

class Exp3{
    public static void main(String[] args) throws Exception{
		DataOutputStream dataOutputStream = new DataOutputStream(new 				FileOutputStream("F://1.dat"));//装饰模式
        dataOutputStream.writeInt(10);
        for (int i = 0; i <= 10; i++) {
            dataOutputStream.writeInt(i*3);
        }
        dataOutputStream.writeInt(5);
        for (int i = 0; i <= 5; i++) {
            dataOutputStream.writeDouble(i*3D);
        }
        //88字节
        dataOutputStream.flush();
        dataOutputStream.close();   
    }
}    

对字节文件以基本数据类型为准读。

DataInputStream(InputStream in);
//Dis读到文件末尾
//个数未知
try{
    while(true){
        v = dis.readInt();
    }
}catch(EOFException e){
    e.printStackException();
}
  • 关闭文件
public class TestDio{
    putlic stattic ovid main(String[] args) throws Exception{
        DataInputStream dos = new DataInputStream(new FileInputStream("f:/t.dat"));
        int len = dis.readInt();
        System.out.println("len:" + len);
        for(int i = 1; i <= len; i++){
            int v = dis.readInt();
            System.out.print(" " + v);
        }
        len = dis.readInt();
        for(int i = 1; i <= len; i++){
            double d = dis.readDouble();
            System.out.print(" " + d);
        }
        dos.close();
    }
}

File

  1. 列出f盘目录下所有内容
  2. 过滤.txt文件
public class Test{
    public static void main(String[] args){
        File f = new File("f:/");
        String[] fs = f.list();
        for(String s : fs){
            System.out.println(s);
        }
        
        //过滤器
       	fs = f.list(
            //局部匿名内部类
        	new FilenameFilter(){
                @Override
                public boolean accept(File dir, String name){
                    return name.endsWith(".txt");
                }
            }
        );
        
        for(String s : fs){
            System.out.println(s);
        }
    }
}
  1. 文件夹的复制
public class Test{
    public static void main(String[] args){
        
    }
}

字符流

文本流

  1. 显示文本文件内容
public class Test{
    public static void main(String[] args) trows Exception{
        FileReader fr = new FileReader("d:/test.txt"); //默认GBK
        //按照UTF-8
        InputStreamReader isr = new InputStreamReader(
            new FileInputStream("d:/test.txt"), "utf-8");
        System.out.println("编码:" + fr.getEncoding());
        int ch;
        while((ch = fr/*isr*/.read()) != -1){
            System.out.println((char)ch);
        }
        isr.close();
        fr.close();
    }
}

/**
* 输出第一个字符是‘?’
* Windows 记事本的BOM头,有?,需要处理
**/

文本行

  • BufferedReader类
  1. 以文本行为单位读取文件
public class Test{
    public static void main(String[] args) throws Exception{
        Bufferedreader br = new BufferedReader(new FileReader("d:/test.txt"));
    	String line = null;
        while((line = br.read) != null){
            System.out.println(line);
        }
        br.close();
    }
}
  1. 从键盘读入一系列整数值,以','分割,计算和
public class Test{
    public static void main(String[] args) throws Exception{
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("请输入一行整数值, 以逗号分隔:");
        String line = reader.readLine();
        String[] split = line.split(",");
        int sum = 0;
        for (String s : split) {
            if(s.trim().length() > 0) {
                //trim() 去掉头尾空格
                sum += Integer.parseInt(s.trim());
            }
        }
        System.out.println("和为:" + sum);
    }
}

/**
 * 输出第一个字符是‘?’
 * Windows 记事本的BOM头,有?,需要处理
 **/

思路:

  1. 键盘字节流转换为字符流 InputStreamReader
  2. 按行读取BufferedReader
  3. 正则表达式