7-22王旭东知识补漏
1 迭代器(Iterator)
-
使用方法iterator()要求容器返回一个Iterator.第一次调用Iterator的next()方法时,它返回序列的第一个元素.注意:iterator()方法时java.lang.Iterable接口被Collection继承.
-
使用next()获得序列中的下一个元素.
-
使用hasNext()检查序列中是否还有元素.
-
使用remove()将迭代器新返回的元素删除.
2 java IO 基本概念
流的分类:
流的方向不同:输入流,输出流
流的单位不同:字节流,字符流
流的功能不同:字节流,处理流
流分类 | 使用分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
| 抽象基类 | InputStream | OutputStream | Reader | Writer |
节点流 | 访问文件 | FileInputStream | FileOutStream | FileReader | FileWriter |
访问数值 | ByteArrayInputStream | ByteArrayOutStream | CharArrayReader | CharArrayWriter | |
访问管道 | PipedInputStream | PipedOutStream | PipedReader | PipedWriter | |
访问字符串 |
|
| StringReader | StringWriter | |
处理流 | 缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
转换流 |
|
| InputStreamReader | OutputStreamWriter | |
对象流 | ObjectInputStream | ObjectOutputStream |
|
| |
抽象基类(过滤) | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter | |
打印流 |
| PrintStream |
| PrintWriter | |
推回输入流 | PushbackInputStream |
| PushbackReader |
| |
特殊流 | DataInputStream | DataOutputStream |
|
|
3 java获取键盘输入的三种方法
通过代码显示:
import java.util.Scanner;
public class Test01 {
public static void main(String args[]) {
// Java获取键盘输入方法一:
// System.in.read()只能针对一个字符的获取
/*System.out.println("enter a char:");
char i = 0;
try {
i = (char)System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("your char is:" + i);*/
// Java获取键盘输入方法二:
// 需要用到BufferedReader类和InputStreamReader类
/*BufferedReader br = new BufferedReader(new InputStreamReader(System.in));//能读取一行
String str = null;
System.out.println("Enter you value:");
try {
str = br.readLine();
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("your value is:" + str);*/
// Java获取键盘输入方法三:
// 用Scanner类
Scanner sc = new Scanner(System.in);
System.out.println("请输入你的姓名:");
String name = sc.nextLine();
System.out.println("请输入你的年龄:");
int age = sc.nextInt();
System.out.println("请输入你的工资:");
float salary = sc.nextFloat();
System.out.println("你的信息:");
System.out.println("你的姓名:" + name + " 你的年龄:" + age + " 你的工资:" + salary);
}
}
4 java获取文件的绝对路径
若是已经对文件初始化了,就可用下述办法,
File A=new File("文件名及其路径");
String filePath=A.getAbsolutePath();
5 通过IO流进行文件复制
5.1 基本的文件复制
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
FileOutputStream fos = new FileOutputStream("b.txt");
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
fos.close();
fis.close();
}
}
5.2 计算机是如何识别应该把2个字节转换为一个汉字
在GBK字符编码集中,汉字是由2个字节组成,因为GBK兼容ISO-8859-1,正数的单字节已被占用
所以汉字的第一个字节必须为负数第二个字节大多也为负数。如:
public class StringDemo {
public static void main(String[] args) throws UnsupportedEncodingException {
String s1 = "Xyz123";
String s2 = "手可摘星辰";
byte[] bys1 = s1.getBytes();
byte[] bys2 = s2.getBytes();
System.out.println(Arrays.toString(bys1));
System.out.println(Arrays.toString(bys2));
}
}
/* GBK编码字符集下:
[88, 121, 122, 49, 50, 51]
[-54, -42, -65, -55, -43, -86, -48, -57, -77, -67]
* */
5.3 IO操作时定义一个字节数组作为缓存
public class CopyFileDemo {
public static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("c:\\a.txt");
FileOutputStream fos = new FileOutputStream("d:\\b.txt");
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
fos.close();
fis.close();
}
}
***通过带有缓冲区的字节类[高效类]
public class BufferedOutputStream extends FilterOutputStream {
protected byte buf[]; //内部缓冲区
protected int count; //缓冲区存储的字节个数
public BufferedOutputStream(OutputStream out) {
this(out, 8192);
}
public BufferedOutputStream(OutputStream out, int size) {
super(out);
if (size <= 0) {
throw new IllegalArgumentException("Buffer size <= 0");
}
buf = new byte[size];//开辟一个缓冲区
}
//刷新内部缓冲区
private void flushBuffer() throws IOException {
if (count > 0) {
out.write(buf, 0, count);
count = 0;
}
}
//将指定的字节写入此缓冲的输出流
public synchronized void write(int b) throws IOException {
if (count >= buf.length) {
flushBuffer();
}
buf[count++] = (byte)b;
}
//将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此缓冲的输出流
public synchronized void write(byte b[], int off, int len) throws IOException {
if (len >= buf.length) {
flushBuffer();
out.write(b, off, len);
return;
}
if (len > buf.length - count) {
flushBuffer();
}
System.arraycopy(b, off, buf, count, len);
count += len;
}
public synchronized void flush() throws IOException {
flushBuffer();
out.flush();
}
}
***比较四种IO复制操作的效率
/*
* 需求:把F:\\红玫瑰.mp3【9.25M】复制到当前项目目录下的copy.mp4中
*/
public class CopyMp4Demo {
public static void main(String[] args) throws IOException {
long start = System.currentTimeMillis();
method4("F:\\红玫瑰.mp3", "copy.mp3");
long end = System.currentTimeMillis();
System.out.println("共耗时:" + (end - start) + "毫秒");
}
//1、基本字节流一次读写一个字节
public static void method1(String srcString, String destString)throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);
int by = 0;
while ((by = fis.read()) != -1) {
fos.write(by);
}
fos.close();
fis.close();
}
//2、基本字节流一次读写一个字节数组
public static void method2(String srcString, String destString)throws IOException {
FileInputStream fis = new FileInputStream(srcString);
FileOutputStream fos = new FileOutputStream(destString);
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
fos.write(bys, 0, len);
}
fos.close();
fis.close();
}
//3、高效字节流一次读写一个字节:
public static void method3(String srcString, String destString)throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcString));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destString));
int by = 0;
while ((by = bis.read()) != -1) {
bos.write(by);
}
bos.close();
bis.close();
}
//4、高效字节流一次读写一个字节数组:
public static void method4(String srcString, String destString)throws IOException {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(srcString));
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(destString));
byte[] bys = new byte[1024];
int len = 0;
while ((len = bis.read(bys)) != -1) {
bos.write(bys, 0, len);
}
bos.close();
bis.close();
}
}
/*
* 字节流4种方式复制文件所耗费的时间:
* method1基本字节流一次读写一个字节: 共耗时:115906毫秒
* method2基本字节流一次读写一个字节数组:共耗时:342毫秒
* method3高效字节流一次读写一个字节: 共耗时:550毫秒
* method4高效字节流一次读写一个字节数组:共耗时:61毫秒
**/
IO流字符集可能出现的乱码
/*
* 字节流读取中文可能出现的乱码问题:
* a.txt文件的具体内容
* 手可摘星辰
* 2017.01.18.Java
*/
public
class FileInputStreamDemo {
public
static void main(String[] args) throws IOException {
FileInputStream fis = new FileInputStream("a.txt");
/*//读取数据,英文正常,中文乱码异常。【此方案仅对单字节字符有效】
int by = 0;
while ((by = fis.read()) != -1) {
System.out.print((char) by);
} */
/*运行结果:??????????
2017.01.18.Java */
//解决:采用系统默认的编码字符集
byte[] bys = new byte[1024];
int len = 0;
while ((len = fis.read(bys)) != -1) {
System.out.print(new String(bys, 0, len));
}
fis.close();
/* 手可摘星辰
* 2017.01.18.Java*/
}
}
关于字符串的编解码说明
/*
* 乱码产生原因:编解码采用不同方案所致。
* 解决方案:编解码采用同一套字符集。
* 编码:byte[] -- String : new String(byte[] bytes, String CharsetName )
* 解码:String -- byte[] : getBytes(String CharsetName);
* */
public
class StringDemo {
public
static void main(String[] args) throws UnsupportedEncodingException {
String s = "中国";
byte[] bys1 = s.getBytes();
byte[] bys2 = s.getBytes("GBK");
byte[] bys3 = s.getBytes("UTF-8");
System.out.println(Arrays.toString(bys1));
System.out.println(Arrays.toString(bys2));
System.out.println(Arrays.toString(bys3));
String s1 = new String(bys1);
String s2 = new String(bys2, "GBK");
String s3 = new String(bys3, "UTF-8");
System.out.println(s1);
System.out.println(s2);
System.out.println(s3);
}
}
/* 运行结果:
[-42, -48, -71, -6]
[-42, -48, -71, -6]
[-28, -72, -83, -27, -101, -67]
中国
中国
中国
* *
6 Java中如何遍历Map对象的四种方法
方法一 在for-each循环中使用entries来遍历
这是最常见的并且在大多数情况下也是最可取的遍历方式。在键值都需要时使用。
[java] view plain copy
-
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
-
-
for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
-
-
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
-
-
}
注意:for-each循环在Java 5中被引入所以该方法只能应用于java 5或更高的版本中。如果你遍历的是一个空的map对象,for-each循环将抛出NullPointerException,因此在遍历前你总是应该检查空引用。
方法二 在for-each循环中遍历keys或values。
如果只需要map中的键或者值,你可以通过keySet或values来实现遍历,而不是用entrySet。
[java] view plain copy
-
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
-
-
//遍历map中的键
-
-
for (Integer key : map.keySet()) {
-
-
System.out.println("Key = " + key);
-
-
}
-
-
//遍历map中的值
-
-
for (Integer value : map.values()) {
-
-
System.out.println("Value = " + value);
-
-
}
该方法比entrySet遍历在性能上稍好(快了10%),而且代码更加干净。
方法三使用Iterator遍历
使用泛型:
[java] view plain copy
-
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
-
-
Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();
-
-
while (entries.hasNext()) {
-
-
Map.Entry<Integer, Integer> entry = entries.next();
-
-
System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());
-
-
}
不使用泛型:
[java] view plain copy
-
Map map = new HashMap();
-
-
Iterator entries = map.entrySet().iterator();
-
-
while (entries.hasNext()) {
-
-
Map.Entry entry = (Map.Entry) entries.next();
-
-
Integer key = (Integer)entry.getKey();
-
-
Integer value = (Integer)entry.getValue();
-
-
System.out.println("Key = " + key + ", Value = " + value);
-
-
}
你也可以在keySet和values上应用同样的方法。
该种方式看起来冗余却有其优点所在。首先,在老版本java中这是惟一遍历map的方式。另一个好处是,你可以在遍历时调用iterator.remove()来删除entries,另两个方法则不能。根据javadoc的说明,如果在for-each遍历中尝试使用此方法,结果是不可预测的。
从性能方面看,该方法类同于for-each遍历(即方法二)的性能。
方法四、通过键找值遍历(效率低)
[java] view plain copy
-
Map<Integer, Integer> map = new HashMap<Integer, Integer>();
-
-
for (Integer key : map.keySet()) {
-
-
Integer value = map.get(key);
-
-
System.out.println("Key = " + key + ", Value = " + value);
-
-
}
作为方法一的替代,这个代码看上去更加干净;但实际上它相当慢且无效率。因为从键取值是耗时的操作(与方法一相比,在不同的Map实现中该方法慢了20%~200%)。如果你安装了FindBugs,它会做出检查并警告你关于哪些是低效率的遍历。所以尽量避免使用。
总结
如果仅需要键(keys)或值(values)使用方法二。如果你使用的语言版本低于java 5,或是打算在遍历时删除entries,必须使用方法三。否则使用方法一(键值都要)。
7 线程安全
一、线程安全(Thread-safe)的集合对象:
- Vector 线程安全:
- HashTable 线程安全:
-
StringBuffer 线程安全:
二、非线程安全的集合对象:
- ArrayList :
- LinkedList:
- HashMap:
- HashSet:
- TreeMap:
- TreeSet:
-
StringBulider:
8 File类型中定义了什么方法来创建一级目录
boolean
createNewFile()
当且仅当不存在具有此抽象路径名指定的名称的文件时,原子地创建由此抽象路径名指定的一个新的空文件。boolean
exists()
测试此抽象路径名表示的文件或目录是否存在。boolean
mkdir()
创建此抽象路径名指定的目录。boolean
mkdirs()
创建此抽象路径名指定的目录,包括创建必需但不存在的父目录。9进程和线程之间有什么不同?
一个进程是一个独立的运行环境,它可以被看过一个程序或者一个应用.而线程是在进程中执行的一个任务.javay运行环境是一个包含了不同的类和程序的单一进程.线程可以被称为轻量级进程.线程需要较少的资源来创建和驻留在进程中,并且可以共享进程中的资源.
10 同步方法和同步块,哪个是更好的选择?为什么?
同步块是更好的选择,因为它不会锁住整个对象(当然你也可以让它锁住整个对象.).同步方法会锁住整个对象,哪怕这个类中有多个不相关联的同步块,这通常会导致他们停止执行并需要等待获得这个对象上的锁.
11 volatile关键字在java中有什么作用?
当我们使用volatile关键字去修饰变量的时候,所有线程都会直接读取该变量并且不缓存它.这就确保了线程读取到的变量是同内存中是一致的.
12 什么是java序列化,如何实现java序列化?
Java对象的序列化指将一个java对象写入IO流中,于此对应的是,对象的反序列化则从IO流中恢复该java对象.]
如果要让某个对象支持序列化机制.则必须让它的类是可序列化的,为了让某个类是可序列化的,该类必须实现Serializable接口或Externalizable接口