IO流
打印流
打印流只有输出流,没有输入流
public static void main(String[] args) throws IOException {
// 打印流
PrintStream ps = new PrintStream("D:\\a.txt");
//输出
// ps.write("abc".getBytes());
//打印
ps.print("grg");
ps.println("bgdfd");
ps.close();
}
合并流
将两个或者多个流合并成一个流,只有字节输入流
合并数据的时候格式要求一样,要求合并的数据的编码一致
public class SequenceDemo {
public static void main(String[] args) throws IOException {
// 创建向量
Vector<FileInputStream> v = new Vector<>();
// 创建三个字节流
FileInputStream fis1 = new FileInputStream("D:\\a.txt");
FileInputStream fis2 = new FileInputStream("D:\\b.txt");
FileInputStream fis3 = new FileInputStream("D:\\c.txt");
// 添加到向量中
v.add(fis1);
v.add(fis2);
v.add(fis3);
// 获取迭代器
Enumeration<FileInputStream> e = v.elements();
// 创建合并流
SequenceInputStream sis = new SequenceInputStream(e);
// 创建字节输出流
FileOutputStream fos = new FileOutputStream("D:\\d.txt");
byte[] bys = new byte[1024];
int len;
while ((len = sis.read(bys)) != -1){
// 使用合并流读取到了数据
fos.write(bys, 0, len);
}
// 关流
fos.close();
sis.close();
}
}
随机获取流
操作模式:
R | 读 |
---|---|
RW | 读写 |
RWS | 读写并写入硬盘 |
RWD | 读写并写入硬盘,同步保存 |
随机获取流操作文件时把文件看作是一个字节数组,从0索引开始操作
public class RandomDemo {
public static void main(String[] args) throws IOException {
// 创建对象
RandomAccessFile raf = new RandomAccessFile("D:\\a.txt","rw");
// int i = raf.read();
// System.out.println((char)i);
//
// i = raf.read();
// System.out.println((char)i);
// raf.write('a');
// 默认从第0位开始替换
// raf.write("ppl".getBytes());
// 将底层的数组索引重新置换为0
// raf.seek(0);
raf.skipBytes(4);
raf.write('u');
raf.close();
}
}
序列化和反序列化流
- 序列化:将对象和其中的内容转换为字节进行完整保存。
- 反序列化:将字节内容转换为对象。
- 需要序列化的类要实现Serializable接口
- 被static修饰的内容不会被序列化。因为没有意义。
- 被transient修饰的内容强制不让序列化
- 在进行序列化的时候,系统会根据类中的属性和方法计算出一个UID。这个UID会被序列化到对象 中。在反序列化之前,如果修改了类中的信息,那么会再次计算出一个UID。当反序列化的时候, 先进行UID的比较。如果UID不相同,那么就会抛出异常。如果相同,就反序列化成功。
public class Test {
public static void main(String[] args) throws IOException, ClassNotFoundException {
// Student stu = new Student();
// stu.setName("刘德华");
//
//
// // 序列化 -->将对象转换为字节
// ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream("p.data"));
// // 开始序列化
// oo.writeObject(stu);
// oo.close();
// 反序列化-->将字节转换为对象
ObjectInputStream os = new ObjectInputStream(new FileInputStream("p.data"));
// 开始反序列化
Student s = (Student)os.readObject();
System.out.println(s.getName());
os.close();
}
}
// 需要序列化的类要实现Serializable接口
class Student implements Serializable{
// 指定UID = 左边是固定格式
private static final long serialVersionUID = -3709298166482028107L;
private String name;
private int age;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
// 被static修饰,不会被序列化
// static String age;
// // 被transient修饰,强制不会被序列化
// transient int score;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Properties
Properties是可以持久化的映射,继承自Hashtable,键和值的类型是String类型。
Properties对象必须存放到properties文件中,而这个文件的默认编码是西欧编码,不兼容中文,所以放入中文就会变成对应的utf-16编码形式
public class PropertiesDemo {
public static void main(String[] args) throws IOException {
Properties p = new Properties();
// key和value不能为null
// p.setProperty(null, null);
p.setProperty("刘德华", "78");
p.setProperty("张学友", "90");
p.setProperty("迈克尔杰克逊", "100");
p.list(System.out);
// 持久化存储 参数二:可以给文件加注释
// p.store(new FileOutputStream("data.properties"), "this is a comment~~");
// p.load(new FileInputStream("data.properties"));
// System.out.println(p.getProperty("谷丰硕"));
// // 可以设定默认值
// String s = p.getProperty("谷丰硕", "120");
// System.out.println(s);
// System.out.println(p);
}
}
单元测试
- 单元测试就是对java中最小的单元(方法)进行测试
- 进行测试的方法需要"三无":
- 无参数
- 无返回值
- 无静态
- 使用方法
- 先导入第三方框架Junit
- 在需要测试的方法上面添加@Test
- 如果要保证某一个方法必须在其他方法之前执行,那么使用@Before注解
- 如果要保证某一个方法必须在其他方法之后执行,那么使用@After注解
断言
Java中默认没有开启断言
可以针对某个类配置断言(edit configurations)
可以选择项目进行详细的配置,断言就在全项目中都可以使用(打开 IDEA 安装目录,看到有一个 bin 目录,其中有两个 vmoptions 文件)
可变参数
JDK5部分特性:自动装箱拆箱、增强for循环、泛型、静态导入、可变参数、枚举、反射、内省、动态代理、注解
可变参数就是传入的参数个数是可变的,可以是0到n个
可变参数是在数据类型后加…
可变参数只能定义一个,而且必须放在参数列表的末尾
枚举
枚举其实就是多例,一个类有多个实例,但实例的个数不是无穷的,是有限个数的。例如音乐播放器的状态只有播放、暂停、上一曲、下一曲。开车的方向有几种:前、后、左、右。
枚举:不允许外部修改、数量是固定有限的。
在JDK1.5之前,枚举类构造方法通过private修饰,里面提供固定的使用public static final 修 饰的枚举值。
class Season{
private Season(){
}
// 春天
public final static Season Spring = new Season();
// 夏天
public final static Season Summer = new Season();
// 秋天
public final static Season Autumn = new Season();
// 冬天
public final static Season Winter = new Season();
}
在JDK1.5之后,枚举类使用enum来定义,枚举值在有效代码的第一行。多个枚举使用,隔开。 枚举本质上还是一个类,可以提供有参构造,但是构造方法必须使用private修饰,需要再提供无参构造。枚举中可以定义抽象方法,但是枚举值需要通过匿名内部类的形式来实现抽象方法。枚 举经常和switch结合使用。
public class Test {
public static void main(String[] args) {
Season s = Season.Spring;
switch(s){
case Spring:
// System.out.println("春天");
break;
case Summer:
System.out.println("夏天");
break;
case Antumn:
System.out.println("秋天");
break;
case Winter:
System.out.println("冬天");
break;
}
}
}
enum Season{
// 底层相当于public final static Season Spring = new Season();
// 枚举本质上还是一个类,枚举的内容必须在有效代码的首行
Spring() {
// 使用匿名内部类的形式实现抽象方法
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("赏花");
}
},Summer {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("吃西瓜");
}
},Antumn {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("收获");
}
},Winter {
@Override
public void show() {
// TODO Auto-generated method stub
System.out.println("吃饺子");
}
};
private int month;
public int getMonth() {
return month;
}
public void setMonth(int month) {
this.month = month;
}
// 枚举的构造方法必须是使用private修饰
// 一旦自定义了有参构造,那么默认的无参构造就没了
private Season(int month){
this.month = month;
}
private Season(){}
// 一旦提供了抽象方法,类就应该抽象类
public abstract void show();
}