八、流与文件
8.1 File类
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+/: 注释代码