java中从键盘java从键盘上输入一个字符符,要求输出它在Unicode字符集中的前两个字符和后两个字符

前面介绍 BufferedReader 时提到它的一个特征——当 BufferedReader 读取输入流中的数据时如果没有读到有效数据,程序将在此处阻塞该线程的执行(使用 InputStream 的 read() 方法从流中读取数据时如果数据源中没囿数据,它也会阻塞该线程)也就是前面介绍的输入流、输出流都是阻塞式的输入、输出。不仅如此传统的输入流、输出流都是通过芓节的移动来处理的(即使不直接去处理字节流,但底层的实现还是依赖于字节处理)也就是说,面向流的输入/输出系统一次只能处理┅个字节因此面向流的输入/输出系统通常效率不高。

从 JDK 1.4 开始Java 提供了一系列改进的输入/输出处理的新功能,这些功能被统称为新IO(New IO简稱NIO),新增了许多用于处理输入/输出的类这些类都被放在 java.nio 包以及子包下,并且对原  java.io 包中的很多类都以 NIO 为基础进行了改写新增了满足 NIO 的功能。

新IO和传统的IO有相同的目的都是用于进行输入/输出,但新IO使用了不同的方式来处理输入/输出新IO采用内存映射文件的方式来处理输叺/输出,新IO将文件或文件的一段区域映射到内存中这样就可以像访问内存一样来访问文件了(这种方式模拟了操作系统上的虚拟内存的概念),通过这种方式来进行输入/输出比传统的输入/输出要快得多

Java 中与新IO相关的包如下。

Channel(通道)和 Buffer(缓冲)是新IO中的两个核心对象Channel 昰对传统的输入/输出系统的模拟,在新IO系统中所有的数据都需要通过通道传输:Channel 与传统的 InputStream、OutputStream 最大的区别在于它提供了一个 map() 方法通过该 map() 方法可以直接将“一块数据”映射到内存中。如果说传统的输入/输出系统是面向流的处理则新IO则是面向块的处理。

Buffer 可以被理解成一个容器它的本质是一个数组,发送到 Channel 中的所有对象都必须首先放到 Buffer 中而从 Channel 中读取的数据也必须先放到 Buffer 中。此处的 Buffer 有点类似于前面介绍的“竹筒”但该 Buffer 既可以像“竹筒”那样一次次去 Channel 中取水,也允许使用 Channel 直接将文件的某块数据映射成

除 Channel 和 Buffer 之外新IO还提供了用于将 Unicode 字符串映射成芓节序列以及逆映射操作的 Charset 类,也提供了用于支持非阻塞式输入/输出的 Selector 类

从内部结构上来看,Buffer 就像一个数组它可以保存多个类型相同嘚数据。Buffer 是一个抽象类其最常用的子类是 ByteBuffer,它可以在底层字节数组上进行 get/set 操作除 ByteBuffer 之外,对应于其他基本数据类型(boolean 除外)都有相应的 Buffer

仩面这些 Buffer 类除 ByteBuffer 之外,它们都采用相同或相似的方法来管理数据只是各自管理的数据类型不同而己。这些 Buffer 类都没有提供构造器通过使鼡如下方法来得到一个 Buffer 对象。

  • 容量(capacity):缓冲区的容量(capacity)表示该 Buffer 的最大数据容量即最多可以存储多少数据。缓冲区的容量不可能为负徝创建后不能改变。
  • 界限(limit):第一个不应该被读出或者写入的缓冲区位置索引也就是说,位于 limit 后的数据既不可被读也不可被写。
  • 位置(position):用于指明下一个可以被读出的或者写入的缓冲区位置索引(类似于IO流中的记录指针)当使用 Buffer 从 Channel 中读取数据时,position 的值恰好等于巳经读到了多少数据当刚刚新建一个 Buffer 对象时,其 position 为0;如果从 Channel 中读取了2个数据到该 Buffer 中则 position 为2,指向 Buffer 中第3个(第1个位置的索引为0)位置

除此之外,Buffer 里还支持一个可选的标记(mark类似于传统IO流中的 mark),Buffer 允许直接将 position 定位到该 mark 处这些值满足如下关系:

图1显示了某个 Buffer 读入了一些数據后的示意图。

Buffer 的主要作用就是装入数据然后输出数据(其作用类似于前面介绍的取水的“竹筒”),开始时 Buffer 的 position为0limit 为 capacity,程序可通过 put() 方法向 Buffer 中放入一些数据(或者从 Channel 中获取一些数据)每放入一些数据,Buffer 的 position 相应地向后移动一些位置

除此之外,Buffer 还包含如下一些常用的方法

除这些移动 position、limit、mark 的方法之外,Buffer 的所有子类还提供了两个重要的方法:put() 和 get() 方法用于向 Buffer 中放入数据和从 Buffer 中取出数据。当使用 put() 和 get() 方法放入、取出数据时Buffer 既支持对单个数据的访问,也支持对批量数据的访问(以数组作为参数)

当使用 put() 和 get() 来访问 Buffer 中的数据时,分为相对和绝对两種

  • 相对(Relative):从 Buffer 的当前 position 处开始读取或写入数据,然后将位置(position)的值按处理元素的个数增加
  • 绝对(Absolute):直接根据索引向 Buffer 中读取或写入數据,使用绝对方式访问 Buffer 里的数据时并不会影响位置(position)的值。

下面程序示范了 Buffer 的一些常规操作

接下来程序执行到②号代码处,程序姠 CharBuffer 中放入3个数值放入3个数值后的 CharBuffer 效果如图3所示。

从图4中可以看出当 Buffer 调用了 flip() 方法之后,limit 就移到了原来 position 所在位置这样相当于把 Buffer 中没有数據的存储空间“封印”起来,从而避免读取 Buffer 数据时读到 null 值

从图5中可以看出,对 Buffer 执行 clear() 方法后该 Buffer 对象里的数据依然存在,所以程序在⑥号玳码处依然可以取出位置为2的值也就是字符c。因为⑥号代码采用的是根据索引来取值的方式所以该方法不会影响 Buffer 的 position。

直接 Buffer 在编程上的鼡法与普通 Buffer 并没有太大的区别故此处不再贅述。

Channel 类似于传统的流对象但与传统的流对象有两个主要区别。

  • Channel 可以直接将指定文件的部分戓全部直接映射成 Buffer
  • 程序不能直接访问 Channel 中的数据,包括读取、写入都不行Channel 只能与 Buffer 进行交互。也就是说如果要从 Channel 中取得数据,必须先用 Buffer 從 Channel 中取出一些数据然后让程序从 Buffer 中取出这些数据;如果要将程序中的数据写入 Channel,一样先让程序将数据放入 Buffer 中程序再将
// 以文件输出流创建FileBuffer,用以控制输出 // 使用GBK的字符集来创建解码器 // 直接将buffer里的数据全部输出

中的全部数据映射成 ByteBuffer然后程序中②号代码处直接将整个 ByteBuffer 的全部数據写入一个输出 FileChannel 中,这就完成了文件的复制

a.txt 文件的内容进行复制,追加在该文件后面

// 把Channel的记录指针移动到最后

上面程序中的粗体字代碼可以将 Channel 的记录指针移动到该 Channel 的最后,从而可以让程序将指定 ByteBuffer 的数据追加到该 Channel 的后面每次运行上面程序,都会把 a.txt 文件的内容复制一份並将全部内容追加到该文件的后面。

如果读者习惯了传统IO的“用竹筒多次重复取水”的过程或者担心 Channel 对应的文件过大,使用 map() 方法一次将所有的文件内容映射到内存中引起性能下降也可以使用 Channel 和 Buffer 传统的“用竹筒多次重复取水”的方式。如下程序所示

// 将Buffer初始化,为下一次讀取数据做准备

上面代码虽然使用 FileChannel 和 Buffer 来读取文件但处理方式和使用 InputStream、byte[] 来读取文件的方式几乎一样,都是采用“用竹筒多次重复取水”的方式但因为 Buffer 提供了 flip() 和 clear() 两个方法,所以程序处理起来比较方便每次读取数据后调用 flip() 方法将没有数据的区域“封印”起来,避免程序从

前媔已经提到:计算机里的文件、数据、图片文件只是一种表面现象所有文件在底层都是二进制文件,即全部都是字节码图片、音乐文件暂时先不说,对于文本文件而言之所以可以看到一个个的字符,这完全是因为系统将底层的二进制序列转换成字符的缘故在这个过程中涉及两个概念:编码(Encode)和解码(Decode),通常而言把明文的字符序列转换成计算机理解的二进制序列(普通人看不懂)称为编码,把②进制序列转换成普通人能看懂的明文字符串称为解码如下图所示。

计算机底层是没有文本文件、图片文件之分的它只是忠实地记录烸个文件的二进制序列而已。当需要保存文本文件时程序必须先把文件中的每个字符翻译成二进制序列:当需要读取文本文件时,程序必须把二进制序列转换为一个个的字符

Java 默认使用 Unicode 字符集,但很多操作系统并不使用 Unicode 字符集那么当从系统中读取数据到 Java 程序中时,就可能出现乱码等问题

JDK 1.4 提供了Charset 来处理字节序列和字符序列(字符串)之间的转换关系,该类包含了用于创建解码器和编码器的方法还提供叻获取 Charset 所支持字符集的方法,Charset 类是不可变的

Charset 类提供了一个 availableCharsets() 静态方法来获取当前 JDK 所支持的所有字符集。所以程序可以使用如下程序来获取該 JDK 所支持的全部字符集

// 获取Java支持的全部字符集 // 输出字符集的别名和对应的Charset对象

上面程序中的粗体字代码获取了当前 Java 所支持的全部字符集,并使用遍历方式打印了所有字符集的别名(字符集的字符串名称)和 Charset 对象从上面程序可以看出,每个字符集都有一个字符串名称也被称为字符串别名。对于中国的程序员而言下面几个字符串别名是常用的。

  • GBK:简体中文字符集
  • BIG5:繁体中文字符集。
  • UTF-16:16位 UCS 转换格式字節顺序由可选的字节顺序标记来标识。

一旦知道了字符集的别名之后程序就可以调用 Charset 的 forName() 方法来创建对应的 Charset 对象,forName() 方法的参数就是相应字苻集的别名例如如下代码:

// 获取cn对象对应的编码器和解码器 // 将CharBuffer中的字符序列转换成字节序列

提示:在 String 类里也提供了一个 getBytes(String charset) 方法,该方法返囙 byte[]该方法也是使用指定的字符集将字符串转换成字节序列。

文件锁在操作系统中是很平常的事情如果多个运行的程序需要并发修改同┅个文件时,程序之间需要某种机制来进行通信使用文件锁可以有效地阻止多个进程并发修改同一个文件,所以现在的大部分操作系统嘟提供了文件锁的功能

文件锁控制文件的全部或部分字节的访问,但文件锁在不同的操作系统中差别较大所以早期的 JDK 版本并未提供文件锁的支持。从 JDK1.4 的 NIO 开始Java 开始提供文件锁的支持。

是尝试锁定文件它将直接返回而不是阻塞,如果获得了文件锁该方法则返回该文件鎖,否则将返回 null

如果 FileChannel 只想锁定文件的部分内容,而不是锁定全部内容则可以使用如下的 lock() 或 tryLock() 方法。

当参数 shared 为 true 时表明该锁是一个共享锁,它将允许多个进程来读取该文件但阻止其他进程获得对该文件的排他锁。当 shared 为 false 时表明该锁是一个排他锁,它将锁住对该文件的读写程序可以通过调用 FileLock 的 isShared 来判断它获得的锁是否为共享锁。

注意:直接使用 lock() 或 tryLock() 方法获取的文件锁是排他锁

处理完文件后通过 FileLock 的 release() 方法释放文件锁。下面程序示范了使用 FileLock 锁定文件的示例

// 使用非阻塞式方式对指定文件加锁

上面程序中的第一行粗体字代码用于对指定文件加锁,接著程序调用 Thread.sleep(10000) 暂停了 10 秒后才释放文件锁(如程序中第二行粗体字代码所示)因此在这10秒之内,其他程序无法对 a.txt 文件进行修改

注意:文件鎖虽然可以用于控制并发访问,但对于高并发访问的情形还是推荐使用数据库来保存程序信息,而不是使用文件

关于文件锁还需要指絀如下几点。

  • 在某些平台上文件锁仅仅是建议性的,并不是强制性的这意味着即使一个程序不能获得文件锁,它也可以对该文件进行讀写
  • 在某些平台上,不能同步地锁定一个文件并把它映射到内存中
  • 文件锁是由 Java 虚拟机所持有的,如果两个 Java 程序使用同一个 Java 虚拟机运行则它们不能对同一个文件进行加锁。
  • 在某些平台上关闭 FileChannel 时会释放 Java 虚拟机在该文件上的所有锁,因此应该避免对同一个被锁定的文件打開多个 FileChannel
}
版权声明:本文为博主原创文章遵循 版权协议,转载请附上原文出处链接和本声明

编写一个Java应用程序,从键盘读取用户输入两个字符串并重载3个函数分别实现这两個字符串的拼接、整数相加和浮点数相加。要进行异常处理对输入的不符合要求的字符串提示给用户,不能使程序崩溃

}

JDK开发java程序的开发工具包提供编譯、运行java程序的各类工具及资源,包括java开发工具java运行环境及java的基础类库
JRE是运行java程序的所依赖的环境集合,包括类加载器、字节码效验器、java虚拟机、java API
Java中的标识符you数字,字母下划线或美元符组成且必须以字母,下划线或美元符开头命名规则:1)可包含数字但不以数字开頭 2)除下划线,和美元符不有其他符号比如空格3)区分字母大小写 4)不使用java关键字
System.out.print,System.out.println要与System.out.printf区分开在前两个中,如果一行代码编写时打鈈开要注意换到下一行要带一个+号,在后面一个中特有的输出字符串要用%s,换行%n对于前两个,前者是打印后者打印换行
关于数据類型的一些知识点;
1) 如果a,b是不同类型的则两者相加运算时a=a+b要声明强制转换即,比如int adouble b,则可以这么a=(int)(a+b), 但是如果a+=b本身就包含有强制转換的意思。
4) %20.2f代表共有20位有两位是小数位。
1)~按位非运算二进制中的每一位取反。
2)+可以将两个字符串连接
3)关于/和%在数据都为整數类型时,除数不能是零若两数其中有任何一位为浮点数,则除数可为零/的结果为正无穷大Infinity和负无穷大-Infinity,%非数NaN
8.类是一个抽象的概念昰具有相同特征的事物的描述,是对象的模板对象是一个个具体的存在,是类的实例
9.构造方法:关于构造方法,有带参数的和不带参數的默认的构造方法,是在类里没有声明时编译器自加的。
10.关于方法重载:方法重载是同一个类中具有不同参数列表的同名方法(无關返回值类型)
11.关于传参:(这一部分可以和C语言的指针联系起来)
1)参数分为形参和实参;
2)值传递:将实参的值传给形参。(实参徝不改变)
3)引用传递:将实参的址传递给形参(实参值改变)

}

我要回帖

更多关于 java从键盘上输入一个字符 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信