javaSE笔记

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

注意

  1. super调用父类的构造方法,必须在当前构造方法中的第一个;
  2. super必须只能出现在子类的方法或构造方法中;
  3. super 和 this 不能同时调用构造方法;
    (因为这两个都必须写在第一个)
  4. 在子类构造方法中会默认写一个super()在第一个;

重写(override)

前提

  1. 需要有继承关系,子类重写父类的方法
    (该方法不能有修饰符static,final,private)
  2. 方法名和参数列表必须相同;
  3. 修饰符,范围,可以扩大,但不能缩小;
    (如 父类的方法修饰符为default,则子类重写方法修饰符可以为public)
  4. 抛出的异常,范围,可以缩小,但不能扩大

为什么要重写

  1. 父类的功能,子类不一定需要,或者不一定满足。

多态

多态的定义:

	接口的多种不同的实现方式即为多态。
 	同一方法可以根据发送对象的不同而采用多种不同的行为方式。

一个对象的实例类型(new 后面的)是确定的,但可以指向对象的引用的类型(引用前面的)有很多。如,父类

注意:
1. 多态是方法的多态,属性没有多态性。
2. 在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。

多态存在条件:

  1. 有继承关系
  2. 子类重写父类方法
  3. 父类引用指向子类
    (如 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{//善后工作
	//-------
}
  • 作用:可以忽略在意料之中的异常,让程序继续执行
  • 可以自定义异常(很少会用到)

常用类

包装类

  • 什么是包装类

将基本数据类型对应进行封装,产生一个新的类(属于引用数据类型)

  • 对应关系
基本数据类型对应的包装类继承关系
byteByte—> Number —> Object
shortShort—> Number —> Object
intInteger—> Number —> Object
longLong—> Number —> Object
floatFloat—> Number —> Object
doubleDouble—> Number —> Object
charCharacter—> Object
booleanBoolean—> 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)

实例化:(实例化后值不可改变)

  1. now() (获取当前的信息)
    LocalDateTime localDateTime = LocalDateTime.now();
  2. 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开始 效率低 线程安全

集合(容器)

数组(容器)的缺点:

  1. 长度不可变
  2. 增删效率低
  3. 没有方法可以得到有效数据的长度
  4. 对于无序的,不可重复的数据,数组不能满足要求

在这里插入图片描述
集合都可扩容

  • List(有索引)
  1. ArrayList:
    本质:数组
    特点:有序(按输入顺序),可重复

  2. Vector:基本和ArrayList一致

  3. LInkedLIst
    本质:双向链表
    特点:有序,可重复,可以操作头尾结点

  • Set
  1. HashSet:
    本质:HashMap

  2. LinkedHashSet:有序的HashMap

  3. TreeSet:
    本质:TreeMap

  • Map(key–value结构,重点是key)
  1. HashMap:
    本质:哈希表(即 数组+链表)
    特点:无序,无重复,重写hashCode,equals方法

  2. LinkedHashM:有序的HashMap

  3. HashTable:和HashMap基本一致,但HashTable从JDK1.0开始

  4. 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 值

在这里插入图片描述

  • 自定义类的比较器
  1. 内部比较器
 @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));
 }
  1. 外部比较器

优势:可以写多个,而内部比较器只能写一个

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
在这里插入图片描述

注意:

  1. 被序列化的类的内部的所有属性,必须都是可序列化的
    (基本数据类型和String是可直接序列化的)
  2. static,transient修饰的属性,不可以被序列化

多线程

注解(annotation)和反射(Reflection)


版权声明:本文为weixin_52757736原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。