LinkedHashMap
* LinkedHashMap:是Map接口的哈希表和链接列表实现,具有可预知的迭代顺序。
* 由哈希表保证键的唯一性
* 由链表保证键盘的有序(存储和取出的顺序一致)
LinkedHashMap l = new LinkedHashMap();
l.put(1, "hello");
System.out.println(l);
案例:统计字符串中 出现的字符数量。
*数据类型的选择和代码熟练不够啊。。。
String string="aababcabcdabcde";
HashMap<String, Integer> hm = new HashMap<>();
char[] chars = string.toCharArray();
for (int i = 0; i < chars.length; i++) {
Set<String> set3 = hm.keySet();
String key=chars[i]+"";
if(!set3.contains(key)){
hm.put(key, 1);
}else{
hm.put(key, hm.get(key)+1);
}
}
——————————————————————————————————————————————————————↑ 自己的
String string="aababcabcdabcde";
HashMap<Character, Integer> hm = new HashMap<>();
char[] chars = string.toCharArray();
for (char c : chars) {
Integer count = hm.get(c);
if(count==null){
hm.put(c, 1);
}else{
count++;
hm.put(c,count);
}
}
HashTable和HashMap的区别
注:Map本身就是一个顶层接口。
* 1:Hashtable和HashMap的区别?
* Hashtable:线程安全,效率低。不允许null键和null值
* HashMap:线程不安全,效率高。允许null键和null值
Collection和Collections的区别?
* Collection:是单列集合的顶层接口,有子接口List和Set。
* Collections:是针对集合操作的工具类,有对集合进行排序和二分查找的方法
final,finally,finalize的区别?
final 不写了。。
finally是异常捕获机制的一部分,其中代码总会执行除非jvm提前退出,一般用于资源释放工作。
finalize是Object中的方法方。垃圾收集器在确定这个对象没有被引用时会对这个对象调用的。将对象从内存中清除出去之前做必要的清理工作
关于File的一些操作:
注:File可以指向文件,也可以指向文件夹。用下面的这些方法时要注意当前对象的指向。
*public boolean createNewFile():创建文件 如果存在这样的文件,就不创建了
*public boolean mkdir():创建文件夹 如果存在这样的文件夹,就不创建了
*public boolean mkdirs():创建文件夹,如果父文件夹不存在,会帮你创建出来
* 删除功能:public boolean delete()
* A:如果你创建文件或者文件夹忘了写盘符路径,那么,默认在项目路径下。
* B:Java中的删除不走回收站。
* C:要删除一个文件夹,请注意该文件夹内不能包含文件或者文件夹
* 重命名功能:public boolean renameTo(File dest)
* 如果路径名相同,就是改名。
* 如果路径名不同,就是改名并剪切。
// 创建一个文件对象
File file = new File("林青霞.jpg");
// 需求:我要修改这个文件的名称为"东方不败.jpg"
File newFile = new File("东方不败.jpg");
System.out.println("renameTo:" + file.renameTo(newFile));
File file2 = new File("东方不败.jpg");
File newFile2 = new File("e:\\林青霞.jpg");
System.out.println("renameTo:" + file2.renameTo(newFile2));
* 获取功能:
* public String getAbsolutePath():获取绝对路径
* public String getPath():获取相对路径
* public String getName():获取名称
* public long length():获取长度。字节数
* public long lastModified():获取最后一次的修改时间,毫秒值
* public String[] list():获取指定目录下的所有文件或者文件夹的名称数组
* public File[] listFiles():获取指定目录下的所有文件或者文件夹的File数组
关于异常需要了解的东西
* 在try里面发现问题后,jvm会帮我们生成一个异常对象,然后把这个对象抛出,和catch里面的类进行匹配。
* 如果该对象是某个类型的,就会执行该catch里面的处理信息。
* public String getMessage():异常的消息字符串
* public String toString():返回异常的简单信息描述
try {
int num=1/0;
} catch (ArithmeticException e) {
System.out.println(e.getMessage()); ---->/ by zero
System.out.println(e.toString()); ---->java.lang.ArithmeticException: / by zero
}
自定义异常:
* 两种方式:
* A:继承Exception
* B:继承RuntimeException
public class MyException extends Exception {
public MyException() {
}
public MyException(String message) {
super(message);
}
}
异常注意事项: 其实就是方法重新安歇规则,异常定义中显的格外冒尖。
* A:子类重写父类方法时,子类的方法必须抛出相同的异常或父类异常的子类。(父亲坏了,儿子不能比父亲更坏)
* B:如果父类抛出了多个异常,子类重写父类时,只能抛出相同的异常或者是他的子集,子类不能抛出父类没有的异常
* C:如果被重写的方法没有异常抛出,那么子类的方法绝对不可以抛出异常,如果子类方法内有异常发生,那么子类只能try,不能throws
IO流
流的分类:输入是读,输出是写。
* 流向:
* 输入流 读取数据 InputStream Reader
* 输出流 写出数据 OutputStream Writer
* 数据类型:
* 字节流
* 字节输入流 读取数据 InputStream
* 字节输出流 写出数据 OutputStream
* 字符流
* 字符输入流 读取数据 Reader
* 字符输出流 写出数据 Writer
*
* 注意:一般我们在探讨IO流的时候,如果没有明确说明按哪种分类来说,默认情况下是按照数据类型来分的。
数据的追加写入和换行
* 如何实现数据的换行?
* 为什么现在没有换行呢?因为你只写了字节数据,并没有写入换行符号。
* 如何实现呢?写入换行符号即可呗。
* 刚才我们看到了有写文本文件打开是可以的,通过windows自带的那个不行,为什么呢?
* 因为不同的系统针对不同的换行符号识别是不一样的?
* windows:\r\n
* linux:\n
* Mac:\r
* 而一些常见的个高级记事本,是可以识别任意换行符号的。
FileOutputStream fos = new FileOutputStream("fos3.txt", true);
for (int x = 0; x < 10; x++) {
fos.write(("hello" + x).getBytes());
fos.write("\r\n".getBytes());
}
// 释放资源
fos.close();
案例:
File file = new File("D:\\temp\\wutong.txt");
FileOutputStream out = new FileOutputStream(file);
File file2 = new File("D:\\temp\\Hello.java");
FileInputStream input = new FileInputStream(file2);
byte[] bys=new byte[1024];
while((input.read(bys))!=-1){
out.write(bys);
}
input.close();
out.close();
给的字节数组太大了,会出现下图
可以这样改,去除空格。
int len;
while((len=input.read(bys))!=-1){
out.write(bys,0,len);
}
中文问题:
* 计算机是如何识别什么时候该把两个字节转换为一个中文呢?
* 在计算机中中文的存储分两个字节:
* 第一个字节肯定是负数。
* 第二个字节常见的是负数,可能有正数。但是没影响。
String s="耄耋";
byte[] bys = s.getBytes();
System.out.println(Arrays.toString(bys)); [-21, -93, -15, -13]
逆向的把这个字节数组通过流的方式写入文件,文件成功的显示:耄耋。个人向,字节数组两个为一组与汉字的标识进行匹配,匹配成功,就显示汉字,谨慎使用。
以前最头疼的递归:方法定义中调用方法本身的现象
* 注意事项:
* A:递归一定要有出口,否则就是死递归
* B:递归的次数不能太多,否则就内存溢出
* C:构造方法不能递归使用
private static int jiecheng(int n){ ----->n的阶乘名字略土。。。
if(n==1){
return 1;
}
return n*jiecheng(n-1);
}
案例: 有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?
分析: 月份 兔子对数
1 1
2 1
3 2
4 3
5 5
6 8
感觉很复杂,代码。。。数组也可以实现,初始化前两个元素。使用循环即可。
private static int tuzi(int n){
if(n==1 || n==2){
return 1;
}
return tuzi(n-1)+tuzi(n-2);
}
字符流在进行操作的时候都有指定字符集的构造:
* OutputStreamWriter(OutputStream out,String charsetName):根据指定编码把字节流数据转换为字符流
字符缓冲流的,清空缓存操作
// 封装数据源
BufferedReader br = new BufferedReader(new FileReader("a.txt"));
// 封装目的地
BufferedWriter bw = new BufferedWriter(new FileWriter("b.txt"));
// 两种方式其中的一种一次读写一个字符数组
char[] chs = new char[1024];
int len = 0;
while ((len = br.read(chs)) != -1) {
bw.write(chs, 0, len);
bw.flush(); ------>清一下缓存,别满了再请。
}
// 释放资源
bw.close();
br.close();
文件夹筛选功能
File[] fileArray = srcFolder.listFiles(new FilenameFilter() {
@Override
public boolean accept(File dir, String name) {
return new File(dir, name).isFile() && name.endsWith(".java");
}
});
BufferedReader源码解读
*debug状态下无法查看局部变量。
参考文章:https://blog.csdn.net/appleprince88/article/details/21873807
第五步中,不需要全部复制,只需要复制一个rt.jar即可,放到jdk_src同级目录下即可
自定义BufferedReader的readLine()方法
* 我要返回一个字符串,我该怎么办呢? 我们必须去看看r对象能够读取什么东西呢? 两个读取方法,一次读取一个字符或者一次读取一个字符数组
* 那么,我们要返回一个字符串,用哪个方法比较好呢? 我们很容易想到字符数组比较好,但是问题来了,就是这个数组的长度是多长呢?
* 根本就没有办法定义数组的长度,你定义多长都不合适。 所以,只能选择一次读取一个字符。
* 但是呢,这种方式的时候,我们再读取下一个字符的时候,上一个字符就丢失了 所以,我们又应该定义一个临时存储空间把读取过的字符给存储起来。
* 这个用谁比较和是呢?数组,集合,字符串缓冲区三个可供选择。
* 经过简单的分析,最终选择使用字符串缓冲区对象。并且使用的是StringBuilder
public String readLine() throws IOException {
StringBuilder sb = new StringBuilder();
int ch = 0;
while ((ch = r.read()) != -1) { //104,101,108,108,111
if (ch == '\r') {
continue;
}
if (ch == '\n') {
return sb.toString(); //hello
} else {
sb.append((char)ch); //hello
}
}
// 为了防止数据丢失,判断sb的长度不能大于0
if (sb.length() > 0) {
return sb.toString();
}
return null;
}
内存操作流有点怪,记录在这里。需要输入流的的一个byte数组初始化输出流。
ByteArrayOutputStream baos = new ByteArrayOutputStream();
for (int i = 0; i < 10; i++) {
baos.write(("hello"+i).getBytes());
}
byte[] buf = baos.toByteArray();
ByteArrayInputStream bais = new ByteArrayInputStream(buf);
int by;
while((by=bais.read())!=-1){
System.out.println((char)by);
}
baos.close();
bais.close();
打印流实现复制文件:打印流可以直接操作文本文件但是只可以输出,不能读取
* println() --->好高级的感觉。。
* 其实等价于于:
* bw.write();
* bw.newLine();
* bw.flush();
BufferedReader br = new BufferedReader(new FileReader("D:\\temp\\wutong.txt"));
PrintWriter pw = new PrintWriter("D:\\temp\\wutong2.txt"); --->不存在自行创建
String line;
while((line=br.readLine())!=null){
pw.println(line);
}
pw.close();
br.close();
* 哪些流对象是可以直接操作文本文件的呢?
* FileInputStream
* FileOutputStream
* FileReader
* FileWriter
* PrintStream
* PrintWriter
* 看API,查流对象的构造方法,如果同时有File类型和String类型的参数,一般来说就是可以直接操作文件的。
*
* 流:
* 基本流:就是能够直接读写文件的
* 高级流:在基本流基础上提供了一些其他的功能
键盘输入标准流
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
String line=br.readLine();
BufferedWriter bw = new BufferedWriter(new FileWriter("D:\\temp\\wutong.txt"));
bw.write(line);
bw.close();
br.close();
————————————————————————————————————————————————————————————————————————
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
bw.write("hello ");
bw.write("world");
bw.close();
* System类中的两个成员变量:
* public static final InputStream in “标准”输入流。
* public static final PrintStream out “标准”输出流。
随机访问流
*随机访问流不可以在写入数据后马上读取数据。
*seek(4),指针开始的位置,初始化为1,在读取了100之后其值变成了4
RandomAccessFile raf = new RandomAccessFile("D:\\temp\\wutong.txt", "rw");
// raf.writeInt(100);
// raf.writeChar('a');
// raf.writeUTF("中国人");
// int num = raf.readInt();
raf.seek(4);
char c=raf.readChar();
System.out.println(c); a
System.out.println("文件当前位置:"+raf.getFilePointer()); 6
raf.close();
混合流(两个文件):
InputStream input=new FileInputStream("D:\\temp\\a.txt");
InputStream input2=new FileInputStream("D:\\temp\\b.txt");
SequenceInputStream sis = new SequenceInputStream(input, input2);
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("D:\\temp\\c.txt"));
byte[] bys=new byte[1024];
int len=0;
while((len=sis.read(bys))!=-1){
bos.write(bys,0,len);
}
bos.close();
sis.close();
混合流(多个文件):
Vector<InputStream> v = new Vector<InputStream>();
InputStream s1 = new FileInputStream("ByteArrayStreamDemo.java");
InputStream s2 = new FileInputStream("CopyFileDemo.java");
InputStream s3 = new FileInputStream("DataStreamDemo.java");
v.add(s1);
v.add(s2);
v.add(s3);
Enumeration<InputStream> en = v.elements();
SequenceInputStream sis = new SequenceInputStream(en);
BufferedOutputStream bos = new BufferedOutputStream(
new FileOutputStream("Copy.java"));
// 如何写读写呢,其实很简单,你就按照以前怎么读写,现在还是怎么读写
byte[] bys = new byte[1024];
int len = 0;
while ((len = sis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
sis.close();
对象流:传输的对象的类一定要实现序列化。以后应该会用到
private static void read() throws IOException, ClassNotFoundException {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
"oos.txt"));
Object obj = ois.readObject();
ois.close();
System.out.println(obj);
}
private static void write() throws IOException {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(
"oos.txt"));
Person p = new Person("林青霞", 27);
oos.writeObject(p);
oos.close();
}
Properties:属性集合类。是一个可以和IO流相结合使用的集合类。
* Properties 可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。、
Properties prop = new Properties();
prop.put("1", "中国");
prop.put("2", "中国");
prop.put("3", "中国");
Set<Object> set = prop.keySet();
for (Object key : set) {
System.out.println(prop.get(key));
}
*特殊功能
Properties prop = new Properties();
// 添加元素
prop.setProperty("张三", "30");
prop.setProperty("李四", "40");
prop.setProperty("王五", "50");
// public Set<String> stringPropertyNames():获取所有的键的集合
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
String value = prop.getProperty(key);
System.out.println(key + "---" + value);
}
* public void load(Reader reader):把文件中的数据读取到集合中
* public void store(Writer writer,String comments):把集合中的数据存储到文件
Properties prop = new Properties();
prop.setProperty("wutong", "26");
prop.setProperty("wulu", "26");
prop.setProperty("wuxiao", "26");
Writer w=new FileWriter("D:\\temp\\prop.txt");
prop.store(w, "helloworld");
Reader r=new FileReader("D:\\temp\\prop.txt");
prop.load(r);
r.close();
System.out.println(prop);
案例:修改文件中的键值
Properties prop = new Properties();
Reader r=new FileReader("D:\\temp\\prop.txt");
prop.load(r);
r.close();
Set<String> set = prop.stringPropertyNames();
for (String key : set) {
if(key.equals("wutong")){
prop.setProperty(key, "wushuaige");
break;
}
}
Writer w=new FileWriter("D:\\temp\\prop.txt");
prop.store(w, "描述");
w.close();
NIO小例子
* Paths:有一个静态方法返回一个路径
* public static Path get(URI uri)
* Files:提供了静态方法供我们使用
* public static long copy(Path source,OutputStream out):复制文件
* public static Path write(Path path,Iterable<? extends CharSequence> lines,Charset cs,OpenOption... options)
ArrayList<String> a=new ArrayList<String>();
a.add("hello");
a.add("world");
a.add("java");
Files.write(Paths.get("D:\\temp\\a.txt"), a, Charset.forName("GBK"));