八、流與檔案
8.1 File類
File類可以操作檔案還可以操作檔案目錄,在整個file類最常用用到這些方法:
構造方法之一:public File(String pathname)
刪除檔案:public boolean delete()
判斷檔案是否存在:public boolean exists()
建立目錄:public boolean mkdirs()
獲取父路徑file物件:public File getParentFile()
注:
①這裡的pathname是本地路徑,File類物件既能表示一個特定檔案,也能表示一個目錄,File類可以獲取檔案資訊例如檔案大小,無法處理檔案內容,若要操作檔案內容可以通過流
②路徑分隔符請用File.separator常量表示
8.2 流
8.2.1 簡介
經常說到io時後面都跟著流這個詞,它很抽象表示任何有能力產出資料的資料來源物件或者有能力接收資料的接收端物件.java所有的I/O機制都是基於資料流進行輸入輸出,按不同的角度可以分成:
①按資料流方向:輸入流和輸出流
②按處理資料的單位:位元組流(1byte = 8bit)和字元流(1char = 2byte = 16bit)
③按功能:節點流(程式直接在資料來源上讀寫資料)和處理流(在處理時包裝了下)
IO包中的類大部分派生自以下四種抽象類:
位元組流 | 字元流 | |
輸入流 | InputStream | Reader |
輸出流 | OutputStream | Writer |
8.2.2 InputStream與OutputStream
InputStream與OutputStream是面向位元組形式的I/O僅支援8位位元組流
InputStream表示輸入資料來源包括:
①位元組陣列
②String物件
③檔案
④管道
⑤其他種類的流組成的序列
⑥其他資料來源,例如Internet連線等
OutputStream表示輸出目標包括:
①位元組陣列
②檔案
③管道
InputStream與OutputStream層次結構:
8.2.3 Reader與Writer
Reader與Writer是面向字元形式的I/O相容Unicode
節點流相對應:
位元組流 | 字元流 |
InputStream / OutputStream | Reader / Writer 介面卡: InputStreamReader / OutputStreamWriter |
FileInputStream / FileOutputStream | FileReader / FileWriter |
StringBufferInputStream(已棄用) / (無相應的類) | StringReader / StringWriter |
ByteArrayInputStream/ByteArrayOutputStream | CharArrayReader / CharArrayWriter |
PipedInputStream / PipedOutputStream | PipedReader / PipedWriter |
位元組流 | 字元流 |
FilterInputStream / FilterOutputStream | FilterReader / FilterWriter(抽象類,無子類) |
BufferedInputStream / BufferedOutputStream | BufferedReader(有readLine()) / BufferedWriter |
PrintStream | PrintWriter |
LineNumberInputStream(已棄用) | LineNumberReader |
PushbackInputStream | PushbackReader |
8.3 示例
8.3.1 檔案操作
8.3.1.1 讀檔案
public static String readFile(String fileName) {
File file = new File(fileName).getAbsoluteFile();
if (!file.isFile()) {
return "";
}
StringBuilder sb = new StringBuilder();
try (InputStreamReader isr = new InputStreamReader(new
FileInputStream(file), "UTF-8");
BufferedReader br = new BufferedReader(isr)) {
String str;
while ((str = br.readLine()) != null) {
sb.append(str).append("\r\n");
}
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
複製程式碼
8.3.1.1 寫檔案
public static void writeFile(String fileName, String msg) {
File file = new File(fileName);
try {
BufferedWriter bf = null;
try {
bf = new BufferedWriter(new FileWriter(file, true));
bf.write(msg);
bf.newLine();
bf.write(msg);
} finally {
if (bf != null) {
bf.flush();
bf.close();
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
複製程式碼
8.3.2 記憶體操作
public static void memoryOpt(){
String msg = "hello world !!!";
try(InputStream in = new ByteArrayInputStream(msg.getBytes());
OutputStream out = new ByteArrayOutputStream();){
int temp = 0;
while((temp = in.read()) != -1){
out.write(Character.toUpperCase(temp));
}
System.out.println(out);
} catch (IOException e) {
e.printStackTrace();
}
}
複製程式碼
8.3.3 管道流
static class Writer implements Runnable {
PipedOutputStream out;
public Writer(PipedOutputStream out) {
this.out = out;
}
@Override
public void run() {
try {
String message = "I'm K^Joker";
try {
out.write(message.getBytes());
} finally {
out.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
static class Reader implements Runnable {
PipedInputStream in;
public Reader(PipedInputStream in) {
this.in = in;
}
@Override
public void run() {
byte data[] = new byte[1024];
try {
try {
int len = in.read(data);
System.out.println(new String(data, 0, len));
} finally {
in.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
PipedOutputStream out = new PipedOutputStream();
PipedInputStream in;
try {
in = new PipedInputStream(out);
Thread read = new Thread(new Reader(in));
Thread write = new Thread(new Writer(out));
read.start();
write.start();
} catch (IOException e) {
e.printStackTrace();
}
}
複製程式碼
8.3.4 物件流
public class Person implements Serializable {
private String name;
private transient Integer age;
private final Integer height = 180;
private static Integer weight = 160;
private transient final String nickName = "取毛名";
private transient static String phone = "110";
public Person(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", height=" + height +
", nickName='" + nickName + '\'' +
'}';
}
public static void serialize() {
File file = new File("E:" + File.separator + "serializable.txt");
try (ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file))) {
out.writeObject(new Person("K^Joker", 23));
} catch (IOException e) {
e.printStackTrace();
}
}
public static void deserialize() {
File file = new File("E:" + File.separator + "serializable.txt");
try(ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));){
Object obj = in.readObject();
System.out.println(obj);
} catch (IOException e){
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void main(String[] args) throws IOException {
// serialize();
deserialize();
}
}
複製程式碼
九、列舉
9.1 特性
① 列舉經常用來表示一組相同型別的常量,例如性別、學歷、日期。
② 列舉是一種特殊的類,它與普通類一樣,不過構造器訪問修飾符只能private,enum關鍵字定義,預設繼承了 java.lang.Enum 類,故不能繼承其他類,並實現了 java.lang.Seriablizable 和 java.lang.Comparable 兩個介面。
③ 定義為列舉類後編譯器會加上final聲名,所以該類無法被繼承
④ 所有的列舉值都是 public static final 的,且必須在第一行定義
⑤ 若在列舉中定義了抽象方法,那所有列舉變數必須實現其抽象方法
9.2 實現機制
我們先定義一個列舉:
public enum ColorEnum {
RED(), YELLOW(), BLUE();
}
複製程式碼
javac編譯,生成.class檔案:
我們可以看到編譯器預設生成的構造方法是private修飾的,然後javap看一下編譯後的位元組碼:
我們可以看到列舉其實就是一個類,並且該類被宣告為final,繼承了Enum類,列舉定義的變數被宣告為public static final,另外多出了靜態程式碼塊,和兩個靜態方法values()和valueOf()。Enum類是一個抽象類,主要有name(列舉變數的名稱)和ordinal(列舉變數的位置索引)兩個屬性,在多出的靜態程式碼塊中做了這樣的操作:
RED = new ColorEnum("RED", 0);
YELLOW = new ColorEnum("YELLOW", 1);
BLUE = NEW ColorEnum("BLUE", 2);
$VALUES = new ColorEnum[]{RED, YELLOW, BLUE};
複製程式碼
values()方法是返回$VALUES陣列的複製,valueOf方法是根據傳入的變數名稱返回對應列舉例項。從下面那張圖我們可以大致看出這些。
9.3 列舉使用
① 列舉可以實現介面,具有抽象方法
public enum ColorEnum implements ColorInterface{
RED("紅色"){
@Override
void say(){
System.out.println("我是紅色");
}
}, YELLOW("黃色"){
@Override
void say(){
System.out.println("我是黃色");
}
}, BLUE("藍色"){
@Override
void say(){
System.out.println("我是藍色");
}
}; //必須第一行
private String color;
private ColorEnum(String color){
this.color = color;
}
@Override
public String getColor(){
return color;
}
abstract void say();
public static void main(String[] args) {
System.out.println(ColorEnum.RED); //RED
System.out.println(ColorEnum.RED.getColor()); //紅色
System.out.println(ColorEnum.RED.name()); //RED
System.out.println(ColorEnum.RED.ordinal()); //0
for(ColorEnum color : ColorEnum.values()){
System.out.println(color); //RED YELLOW BLUE
}
ColorEnum.RED.say(); //我是紅色
}
}
複製程式碼
② 介面中使用列舉
public interface Food {
enum Appetizer implements Food{
SALAD, SOUP, SPRING_ROLLS;
}
enum Dessert implements Food{
FRUIT, TIRAMISU, GELATO
}
}
複製程式碼
十、註解
10.1 基本註解
在java.lang包下,JAVA內建了5種註解
① @Override
表示當前的方法定義將覆蓋超類中的方法。若方法簽名對不上被覆蓋的方法編譯器會報錯,@Override只能作用於方法.
② @Deprecated
表示元素已過時,若使用了註解為它的元素,編譯器會發出警告資訊.
③ @SuppressWarnings
關閉不當的編譯器警告資訊
④ @SafeVarargs
抑制堆汙染警告
⑤ @FunctionalIterface
宣告介面為函式式介面(函式式介面指介面中僅僅只包含一個抽象方法)
10.2 自定義註解
10.2.1 元註解
@Target | 表示該註解可以用於什麼地方,其ElementType引數包括: CONSTRUCTOR: 構造器的宣告 FIELD: 域宣告(包括enum例項) LOCAL_VARIABLE: 區域性變數宣告 METHOD: 方法宣告 PACKAGE: 包宣告 PARAMTER: 引數宣告 TYPE: 類、介面(包括註解型別)或enum宣告 |
@Retention | 表示需要在什麼級別儲存該註解資訊,其RetentionPolicy引數包括: SOURCE: 註解將被編譯器弄丟 CLASS: 註解在class檔案中可用,但會被JVM弄丟 RUNTIME: JVM執行期有效,可以通過反射機制讀取註解的資訊 |
@Documented | 將此註解包含在Javadoc中 |
@Inherited | 允許子類繼承父類中的註解 |
10.2.2 規則
註解元素可用的型別如下:
① 所有基本資料型別
② String
③ Class型別
④ Annotation
⑤ 以上所有型別的陣列
注:
使用@interface自定義註解,預設繼承了java.lang.annotation.Annotation,只能用public或預設這兩個訪問修飾符,若只有一個引數成員,最好把引數名稱設為"value",註解不支援繼承,可以巢狀.
10.2.3示例
public class Person {
@MyValidation(nullable = false, message = "姓名不能為空")
private String name;
public Person(){
}
public Person(String name) {
this.name = name;
}
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyValidation {
boolean nullable() default true;
String message() default "";
}
public class Validation {
public void validate(Object object) throws Exception {
Class obj = object.getClass();
Field[] fields = obj.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
verify(field, object);
field.setAccessible(false);
}
}
private void verify(Field field, Object object) throws Exception {
MyValidation mv = field.getAnnotation(MyValidation.class);
if (mv != null && !mv.nullable()) {
Object name = field.get(object);
if("".equals(name) || name == null){
throw new Exception(mv.message());
}
}
}
public static void main(String[] args) throws Exception {
Validation v = new Validation();
// v.validate(new Person(""));
v.validate(new Person());
}
}
複製程式碼
十一、結語
參考了《Thinking in java》和《java core》,整個java基礎有很多東西未寫例如反射,NIO,JUC、集合等後續會慢慢寫。。,最後提下自己常用的快捷鍵:(Eclipse,idea快捷鍵可以設定成eclipse的)
① ctrl+o : 檢視當前類有哪些屬性和方法
② ctrl+h : 全域性搜尋
③ ctrl+f : 當前檔案搜尋
④ Alt+←/→ : 上一個/下一個游標所在位置
⑤ ctrl+shift+f:格式化(不要全部格式化,不然code view很。。。)
⑥ Ctrl+l : 跳到某行
⑦ ctrl+t : 直接從介面找到實現類
⑧ f6/f8 : debug下一步/調到下個斷點
⑨ ctrl+shift+r:開啟資源列表
⑩ alt+/:自動補全程式碼或者提示程式碼
⑪ ctrl+d:刪除當前行
⑫ ctrl+shift+o:導包
⑬ Ctrl+/: 註釋程式碼