容器/IO/线程知识补漏

7-22王旭东知识补漏

1 迭代器(Iterator)

  1. 使用方法iterator()要求容器返回一个Iterator.第一次调用Iterator的next()方法时,它返回序列的第一个元素.注意:iterator()方法时java.lang.Iterable接口被Collection继承.
  2. 使用next()获得序列中的下一个元素.
  3. 使用hasNext()检查序列中是否还有元素.
  4. 使用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:\\红玫瑰.mp39.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

  1. Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
  2.     
  3. for (Map.Entry<Integer, Integer> entry : map.entrySet()) {  
  4.     
  5.     System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());  
  6.     
  7. }  

注意:for-each循环在Java 5中被引入所以该方法只能应用于java 5或更高的版本中。如果你遍历的是一个空的map对象,for-each循环将抛出NullPointerException,因此在遍历前你总是应该检查空引用。

 方法二 在for-each循环中遍历keys或values。

如果只需要map中的键或者值,你可以通过keySet或values来实现遍历,而不是用entrySet。

[java] view plain copy

  1. Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
  2.     
  3. //遍历map中的键  
  4.     
  5. for (Integer key : map.keySet()) {  
  6.     
  7.     System.out.println("Key = " + key);  
  8.     
  9. }  
  10.     
  11. //遍历map中的值  
  12.     
  13. for (Integer value : map.values()) {  
  14.     
  15.     System.out.println("Value = " + value);  
  16.     
  17. }  


该方法比entrySet遍历在性能上稍好(快了10%),而且代码更加干净。

 方法三使用Iterator遍历

使用泛型:

[java] view plain copy

  1. Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
  2.     
  3. Iterator<Map.Entry<Integer, Integer>> entries = map.entrySet().iterator();  
  4.     
  5. while (entries.hasNext()) {  
  6.     
  7.     Map.Entry<Integer, Integer> entry = entries.next();  
  8.     
  9.     System.out.println("Key = " + entry.getKey() + ", Value = " + entry.getValue());  
  10.     
  11. }  

    不使用泛型:

[java] view plain copy

  1. Map map = new HashMap();  
  2.     
  3. Iterator entries = map.entrySet().iterator();  
  4.     
  5. while (entries.hasNext()) {  
  6.     
  7.     Map.Entry entry = (Map.Entry) entries.next();  
  8.     
  9.     Integer key = (Integer)entry.getKey();  
  10.     
  11.     Integer value = (Integer)entry.getValue();  
  12.     
  13.     System.out.println("Key = " + key + ", Value = " + value);  
  14.     
  15. }  

你也可以在keySet和values上应用同样的方法。

该种方式看起来冗余却有其优点所在。首先,在老版本java中这是惟一遍历map的方式。另一个好处是,你可以在遍历时调用iterator.remove()来删除entries,另两个方法则不能。根据javadoc的说明,如果在for-each遍历中尝试使用此方法,结果是不可预测的。

从性能方面看,该方法类同于for-each遍历(即方法二)的性能。

 方法四、通过键找值遍历(效率低)

[java] view plain copy

  1. Map<Integer, Integer> map = new HashMap<Integer, Integer>();  
  2.     
  3. for (Integer key : map.keySet()) {  
  4.     
  5.     Integer value = map.get(key);  
  6.     
  7.     System.out.println("Key = " + key + ", Value = " + value);  
  8.     
  9. }  

作为方法一的替代,这个代码看上去更加干净;但实际上它相当慢且无效率。因为从键取值是耗时的操作(与方法一相比,在不同的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接口

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值