学习java Day04
泛型
- 泛型的使用可以减少代码的编写
- 格式:通过定义(可以不用T,写别的E,V …)
- 常用有三种泛型的使用
- 泛型类的定义
public class Generic<T>{
private T temp;
public void setTemp(T temp){
this.temp=temp;
}
public T getTemp(){
return this.temp;
}
public void show(T param){
System.out.println(param);
}
}
// 使用
Generic<String> g = new Generic<String>();
g.setTemp("a");
String str = g.getTemp();
g.show("sstt");
- 泛型方法的定义
public class Gcc{
public <T> void show(T nn){
System.out.println(nn);
}
}
// 使用
new Gcc().show(12); // 传递参数时自动确定泛型的具体类型
- 泛型接口的定义
//格式
public interface Gcc<T>{
void show(T param);
}
// 实现类的定义 接口使用的是泛型,实现类也必须指定泛型
public class GccImpl<T> implements Gcc<T>{...}
// 接口确定了泛型的类型,实现类就不需要指定类型的了
public class GccImpl implements Gcc<String>{...}
- 泛型通配符 <?> 用来接收任意类型的泛型 , 相当于对象中用Object obj = new xxx();任意的类
List<?> list1 = new ArrayList<String>();
List<?> list2 = new ArrayList<Double>();
// 高级使用
// extends 表示类B必须是类A及其子类
List<? extends 类A> list = new ArrayList<类B>();
// super 表示类B必须是类A及其父类
List<? super 类A> list = new ArrayList<类B>();
日期类的使用
- Date类的使用
// 获得当前时间的日期对象
Date date = new Date();
// 参数表示距离1970/1/1 0:0:0 的毫秒值 的日期(中国为1970/1/1 8:0:0)开始,时区不同
Date date = new Date(milltime);
// 得到这个日期与1970/1/1 0:0:0 的毫秒值
date.getTime();
// 设置毫秒值
date.setTime(milltime);
- SimpleDateFormat 类,对Date对象格式化,或者将字符串解析为Date对象
// 构造函数的参数是 要解析为字符串的格式 不同的字母表示不同的意义, yyyy 表示年 ...
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
String str = sdf.format(date); // 2008-10-1 10:01:00
// 还可以将指定格式的字符串转化为Date对象 不按指定格式会报出异常
String s = "2008/10/1 10:01:00";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date dt = sdf.parse(s); // 会报出异常,需要抛出或者try{...}catch(){...}
System.out.println(dt) //Wed Oct 01 10:01:00 CST 2008
- Calendar类 日历类
这是一个抽象类,但有一个静态方法可以得到该类的子类对象
Calendar cal = Calendar.getInstance() // 得到当前时间的对象
int year = cal.get(Calendar.YEAR); // 得到年
int month= cal.get(Calendar.MONTH)+1; // 得到月 这里的月份是0-11 所以需要手动加1才能与我们的对应
int date= cal.get(Calendar.DATE); // 得到日
// 设置指定时间
cal.set(2020,2,1); // 这里表示的其实是 3月1日
// 得到2月有几天
// 对指定的字段进行修改
cal.add(Calendar.DATE,-1);
date= cal.get(Calendar.DATE); // 得到 2 月的最后一天,即天数
- 获得当前时间的毫秒值的另一种方式
long milltime = System.currentTimeMillis();
File类 (常用的方法)
- 创建File类的对象:常用的3种
// 这个路径可以是不存在的
File file1 = new File("路径");
File file2 = new File(file1,"子路径");
File file3 = new File("父路径","子路径"); // 两个路径拼接得到最后的完整路径
- 使用File对象创建文件,目录(单级和多级)
//创建文件,只能在存在的目录中如果文件不存在则创建文件(返回true),文件存在也不创建(返回false)
file1.creatNewFile();
// 创建单级目录 例存在E:\a\b 只能创建E:\a\b\x 不能创建E:\a\b\x\xx
flie1.mkdir();
// 可以创建多级目录
flie1.mkdirs();
- 判断路径所在的文件和目录是否存在 :file1.exists();
- 判断路径所在的是文件还是目录
file1.isFile() // 判断是否是文件
file1.isDirectory() // 判断是否是目录
- 得到File对象的一些参数
// 此抽象路径的文件名或者目录名
String filename = file1.getName();
// 返回抽象路径的字符串形式(你在创建File对象时写的路径)
String filepath = file1.getPath();
// 返回此抽象路径的绝对路径
String fileAbsolutePath = file1.getAbsolutePath();
- 如果抽象路径表示的是目录,还可以展示此目录的所有文件和目录
String[] listfiles = file1.list() // 以字符串形式返回 [aaa, bbb, d.txt, d2.txt, file]
File[] FileLists = file1.listFiles(); // 以文件对象形式返回
IO流
** 对流的操作结束要及时关闭流**
字节流
- 字节流分为:字节输入流(InputStream)和字节输出流(OutputStream),因为是抽象类不能直接创建对象,需要用其子类创建对象
- 常用的子类有FileOutputStream和FileInputStream
- 创建文件字节输出流对象 FileOutputStream(常用的四种创建方式)
//创建文件输出流对象 常用的有四种构造方法 第一个参数可以使用字符串或者File的对象,第二个参数表示是否追加数据,默认不追加,每次从头开始写
FileOutoutStream fos = new FileOutputStream("文件的路径字符串形式"/File file,boolean append)
- 写数据 (有3种)
// 写入单个字节的数据
fos.write(97);
// 写入字节数组全部
fos.write(new byte[]{97,98,99,100,101});
// 写入字节数组某一部分
fos.write(new byte[]{97,98,99,100,101},1,3); // 写入{98,,99,100}
// 关闭流
fos.close()
- 创建文件字节输入流 FileInputStream(常用的两种创建方式)
// 根据字符串创建
FileInputStream fis = new FileInputStream("文件路径字符串");
// 根据File对象创建
FileInputStream fis = new FileInputStream(File对象);
- 读取文件数据(2种) 返回-1表示读取到文件末尾,则结束读取
// 读取单个字节
int bnum = fis.read();
// 读取一个字符数组
byte[] bytes = new byte[1024];
int len = fis.read(bytes); // bytes 里面保存每次读取的内容,返回的len表示读取的长度(用于末尾的时候)
// 关闭流
fis.close()
- 使用文件字节输入输出流实现文件的复制
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt");
byte[] bytes = new byte[1024];
int len;
if((len=fis.read(bytes))!=-1){
fos.write(bytes,0,len);
}
fos.close();
fis.close();
- 字节缓冲流(提供了缓冲区域,不必每次读取或者写入都调用系统进行处理,内部默认使用byte[8192]进行缓冲,底层还是得靠字节输入流或者字节输出流进行读写数据):BufferedInputStream,BufferedOutputStream
// 创建字节缓冲输出流对象
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("文件路径字符串"));
// 两种写入方式
bos.write(int) //写一个字节
bos.write(byte[] bytes,int off,int len); // 其实和文件字节输出流一样,其实就是其内部增加了一个byte[8192]的字节数组
// 关闭流
bos.close();
// 创建字节缓冲输入流
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("文件路径字符串"));
// 读取
int data = bis.read() // 一次读取一个字节
int len = bis.read(byte[] bytes);
// 关闭流
bis.close();
使用字节缓冲输入输出流进行文件复制
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("文件路径字符串"));
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("文件路径字符串"));
byte[] bytes = new byte[1024];
int len;
while((len=bis.read(bytes))!=-1){
bos.write(bytes,0,len);
}
bos.close();
bis.close();
字符流
因为字符由不同数目的字节组成,如一个汉字在GBK中由2个字节组成,在UTF-8中由3个字节组成,但是第一个字节为负数,要想显示字符,显然用字节流不能实现
但是使用字符流还有确定其编码和解码的字符集应该一致
字符流=字节流+编码集,所以其底层还是靠字节流写入,需要传入字节流
- 字符流有字符输入流(Reader)和字符输出流(Writer), 是抽象类不能直接使用
- 常用的字符流InputStreamReader(字节到字符的桥梁)和OutputStreamWriter(字符到字节的桥梁),可以指定字符集
// 创建字符输出流,写数据(可以直接写字符串)
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("a.txt"),"UTF-8");
osw.write("今天天气真好!");
// os.write(new char[]{'今','天','天','气','真','好','!'},0,7)
osw.close();
// 创建字符输入流,读取数据
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"UTF-8");
isr.read(); // 读取单个字符
// 读取一个字符数组
char[] chars = new char[1024];
int len = isr.read(chars);
System.out.println(new String(chars,0,len)); //今天天气真好!
字符流进行文件的复制,只能是文本文件,不能是图片,音频
InputStreamReader isr = new InputStreamReader(new FileInputStream("a.txt"),"UTF-8");
OutputStreamWriter osw = new OutputStreamWriter(new FileOutputStream("c.txt"),"UTF-8");
char[] chars = new char[1024];
int len;
while((len=isr.read(chars))!=-1){
osw.write(chars,0,len);
}
osw.close();
isr.close();
- InputStreamReader和OutputStreamWriter 分别有子类FileReader和FileWriter 设定了默认了字符集和缓冲区,如果要设置指定字符集,还是要使用InputStreamReader和OutputStreamWriter
- 使用FileWriter和FileReader进行文件复制
FileReader fr = new FileReader("a.txt");
FileWriter fw = new FileWriter("d.txt");
int len;
char[] chars = new char[1024];
while((len=fr.read(chars))!=-1){
fw.write(chars,0,len);
}
fw.close();
fr.close();
- 字符缓冲流 BufferedReader和BufferedWriter
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
int len;
char[] chars = new char[1024];
while((len=br.read(chars))!=-1){
bw.write(chars,0,len);
}
bw.close();
br.close();
- 字符缓冲流的特有功能 BufferedReader readLine():读取一行数据(但不包括换行数据) 读到末尾返回nul ,BufferedWriter newLine(); 根据系统写入行分隔符(windows的\r\n Linux的\n)
使用特有功能进行文件复制
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
String str;
while((str=br.readLine())!=null){
bw.write(str);
bw.newLine();
}
bw.close();
br.close();
特殊流 - 对象的序列化和反序列化流
- 要想对对象使用序列化操作,对象这个类必须实现Serializable接口
// 序列化操作,将对象写到文件中
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("UserObject.txt"));
// 这里的User实现了Serializable接口
User user1 = new User(21,"x");
User user2 = new User(32,"xx");
User user3 = new User(45,"xxx");
oos.writeObject(user1);
oos.writeObject(user2);
oos.writeObject(user3);
oos.close();
//反序列化操作,将文件中保存的对象读取出来
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("UserObject.txt"));
Object o = ois.readObject();
// User重写了toString方法
System.out.println(o);
- 如果在对象类中没有显式的定义serialVersionUID,jvm虚拟机会根据各方面自动生成(比较敏感,对类稍作修改,这个值就变了),如果文件中的serialVersionUID 和类的serialVersionUID 不一致则不能进行反序列化操作,建议自己显示设置
**serialVersionUID 修饰符必须是static final long ** static final long serialVersionUID =42L; - 某个字段不想被序列化,可用transient修饰符
Properties集合
- 使用方式和Map集合相似,但是有特有的方法,键和值只能传入字符串
Properties prop = new Properties();
prop.setProperty("001","这是001号");
prop.setProperty("002","这是002号");
prop.setProperty("003","这是003号");
Set<String> keys = prop.stringPropertyNames(); // 返回键的集合
for(String str:keys){ // 遍历
String value = prop.getProperty(str);
System.out.println(value);
}
- Properties集合还可以将数据通过IO流写入和读取数据
// 写数据
Properties prop = new Properties();
prop.setProperty("001","这是001号");
prop.setProperty("002","这是002号");
prop.setProperty("003","这是003号");
// 可以用字符流和字节流进行写入或者读取,但是要一一对应,即字符流写的要用字符流读取
//prop.store(new FileOutputStream("a.txt"),"注释信息,可以写null");
prop.store(new FileWriter("a.txt"),"注释信息,可以写null");
// 读取数据
Properties prop = new Properties();
//prop.load(new FileInputStream("a.txt"));
prop.load(new FileReader("a.txt"));
System.out.println(prop); // {001=这是001号, 002=这是002号, 003=这是003号}