Java面试题字节流字符流

这篇具有很好参考价值的文章主要介绍了Java面试题字节流字符流。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

String 编码UTF-8 GBK的区别

GBK编码:是指中国的中文字符,其实它包含了简体中文与繁体中文字符,另外还有一种字符

“gb2312”,这种字符仅能存储简体中文字符。

UTF-8编码:它是一种全国家通过的一种编码,如果你的网站涉及到多个国家的语言,那么建议你

选择UTF-8编码。

GBKUTF8有什么区别?

while(true){

SocketChannel socketChannel =

serverSocketChannel.accept();

//do something with socketChannel...

}

ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

serverSocketChannel.socket().bind(new InetSocketAddress(9999));

serverSocketChannel.configureBlocking(false);

while(true){

SocketChannel socketChannel =

serverSocketChannel.accept();

if(socketChannel != null){

//do something with socketChannel...

}

}UTF8编码格式很强大,支持所有国家的语言,正是因为它的强大,才会导致它占用的空间大小要比GBK

大,对于网站打开速度而言,也是有一定影响的。

GBK编码格式,它的功能少,仅限于中文字符,当然它所占用的空间大小会随着它的功能而减少,打开

网页的速度比较快。

什么时候使用字节流、什么时候使用字符流,二者的区别

先来看一下流的概念:

在程序中所有的数据都是以流的方式进行传输或保存的,程序需要数据的时候要使用输入流读取数据,

而当程序需要将一些数据保存起来的时候,就要使用输出流完成。

InputStream OutputStream,两个是为字节流设计的,主要用来处理字节或二进制对象,

Reader Writer.两个是为字符流(一个字符占两个字节)设计的,主要用来处理字符或字符串.

字符流处理的单元为2个字节的Unicode字符,操作字符、字符数组或字符串,

字节流处理单元为1个字节,操作字节和字节数组。

所以字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,

所以它对多国语言支持性比较好!

如果是音频文件、图片、歌曲,就用字节流好点,

如果是关系到中文(文本)的,用字符流好点

所有文件的储存是都是字节(byte)的储存,在磁盘上保留的并不是文件的字符而是先把字符编码成字

节,再储存这些字节到磁盘。在读取文件(特别是文本文件)时,也是一个字节一个字节地读取以形成

字节序列

字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;

字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以

字节流是最基本的,所有的InputStremOutputStream的子类都是,主要用在处理二进制数据,它是按

字节来处理的

但实际中很多的数据是文本,

又提出了字符流的概念,

它是按虚拟机的encode来处理,也就是要进行字符集的转化

这两个之间通过 InputStreamReader,OutputStreamWriter来关联,

实际上是通过byte[]String来关联

在实际开发中出现的汉字问题实际上都是在字符流和字节流之间转化不统一而造成的

Reader类的read()方法返回类型为int :作为整数读取的字符(占两个字节共16位),范围在 0

65535 之间 (0x00-0xffff),如果已到达流的末尾,则返回 -1

inputStreamread()虽然也返回int,但由于此类是面向字节流的,一个字节占8个位,所以返回 0

255 范围内的 int 字节值。如果因为已经到达流末尾而没有可用的字节,则返回值 -1。因此对于不能用

0-255来表示的值就得用字符流来读取!比如说汉字.

字节流和字符流的主要区别是什么呢?

**.字节流在操作时不会用到缓冲区(内存),是直接对文件本身进行操作的。而字符流在操作时使用了

缓冲区,通过缓冲区再操作文件。** 上面两点能说明什么呢?

递归读取文件夹下的文件,代码怎么实现

**.在硬盘上的所有文件都是以字节形式存在的(图片,声音,视频),而字符值在内存中才会形成。**

针对第一点,

我们知道,如果一个程序频繁对一个资源进行IO操作,效率会非常低。此时,通过缓冲区,先把需要操作的数

据暂时放入内存中,以后直接从内存中读取数据,则可以避免多次的IO操作,提高效率

针对第二点,

真正存储和传输数据时都是以字节为单位的,字符只是存在与内存当中的,所以,字节流适用范围更为宽广

/**

* 递归读取文件夹下的 所有文件

*

* @param testFileDir 文件名或目录名

*/

private static void testLoopOutAllFileName(String testFileDir) {

if (testFileDir == null) {

//因为new File(null)会空指针异常,所以要判断下

return;

}

File[] testFile = new File(testFileDir).listFiles();

if (testFile == null) {

return;

}

for (File file : testFile) {

if (file.isFile()) {

System.out.println(file.getName());

} else if (file.isDirectory()) {

System.out.println("-------this is a directory, and its files are as

follows:-------");

testLoopOutAllFileName(file.getPath());

} else {

System.out.println("文件读入有误!");

}

}SynchronousQueue实现原理

前言

SynchronousQueue是一个比较特别的队列,由于在线程池方面有所应用,为了更好的理解线程池的实

现原理,笔者花了些时间学习了一下该队列源码(JDK1.8),此队列源码中充斥着大量的CAS语句,理解起

来是有些难度的,为了方便日后回顾,本篇文章会以简洁的图形化方式展示该队列底层的实现原理。

SynchronousQueue简单使用

经典的生产者-消费者模式,操作流程是这样的:

有多个生产者,可以并发生产产品,把产品置入队列中,如果队列满了,生产者就会阻塞;

有多个消费者,并发从队列中获取产品,如果队列空了,消费者就会阻塞;

如下面的示意图所示:

SynchronousQueue

也是一个队列来的,但它的特别之处在于它内部没有容器,一个生产线程,当它生产产品(即put的时

候),如果当前没有人想要消费产品(即当前没有线程执行take),此生产线程必须阻塞,等待一个消费线

程调用take操作,take操作将会唤醒该生产线程,同时消费线程会获取生产线程的产品(即数据传

递),这样的一个过程称为一次配对过程(当然也可以先takeput,原理是一样的)

我们用一个简单的代码来验证一下,如下所示:

}

package com.concurrent;import java.util.concurrent.SynchronousQueue;

public class SynchronousQueueDemo {

public static void main(String[] args) throws InterruptedException {

final SynchronousQueue<Integer> queue = new SynchronousQueue<Integer>();

Thread putThread = new Thread(new Runnable() {

@Override

public void run() {

System.out.println("put thread start");

try {

queue.put(1);

} catch (InterruptedException e) {

}

System.out.println("put thread end");

}

});

Thread takeThread = new Thread(new Runnable() {

@Override

public void run() {

System.out.println("take thread start");

try {

System.out.println("take from putThread: " + queue.take());

} catch (InterruptedException e) {

}

System.out.println("take thread end");

}

});

putThread.start();

Thread.sleep(1000);

takeThread.start();

}

}

一种输出结果如下:

put thread start

take thread start

take from putThread: 1

put thread end

take thread end

从结果可以看出,put线程执行queue.put(1) 后就被阻塞了,只有take线程进行了消费,put线程才可以

返回。可以认为这是一种线程与线程间一对一传递消息的模型。SynchronousQueue实现原理

不像ArrayBlockingQueueLinkedBlockingDeque之类的阻塞队列依赖AQS实现并发操作,

SynchronousQueue直接使用CAS实现线程的安全访问。由于源码中充斥着大量的CAS代码,不易于理

解,所以按照笔者的风格,接下来会使用简单的示例来描述背后的实现模型。

队列的实现策略通常分为公平模式和非公平模式,接下来将分别进行说明。

公平模式下的模型:

公平模式下,底层实现使用的是TransferQueue这个内部队列,它有一个headtail指针,用于指向当

前正在等待匹配的线程节点。

初始化时,TransferQueue的状态如下:

接着我们进行一些操作:

1、线程put1执行 put(1)操作,由于当前没有配对的消费线程,所以put1线程入队列,自旋一小会后睡

眠等待,这时队列状态如下:

2、接着,线程put2执行了put(2)操作,跟前面一样,put2线程入队列,自旋一小会后睡眠等待,这时队

列状态如下:3、这时候,来了一个线程take1,执行了

take操作,由于tail指向put2线程,put2线程跟take1线程配对了(puttake),这时take1线程不需要

入队,但是请注意了,这时候,要唤醒的线程并不是put2,而是put1。为何?

大家应该知道我们现在讲的是公平策略,所谓公平就是谁先入队了,谁就优先被唤醒,我们的例子明显

put1应该优先被唤醒。至于读者可能会有一个疑问,明明是take1线程跟put2线程匹配上了,结果是

put1线程被唤醒消费,怎么确保take1线程一定可以和次首节点(head.next)也是匹配的呢?其实大家可

以拿个纸画一画,就会发现真的就是这样的。

公平策略总结下来就是:队尾匹配队头出队。

执行后put1线程被唤醒,take1线程的 take()方法返回了1(put1线程的数据),这样就实现了线程间的一

对一通信,这时候内部状态如下:

4、最后,再来一个线程take2,执行take操作,这时候只有put2线程在等候,而且两个线程匹配上了,

线程put2被唤醒,

take2线程take操作返回了2(线程put2的数据),这时候队列又回到了起点,如下所示:以上便是公平模式下,SynchronousQueue的实现模型。总结下来就是:队尾匹配队头出队,先进先

出,体现公平原则。

非公平模式下的模型:

我们还是使用跟公平模式下一样的操作流程,对比两种策略下有何不同。非公平模式底层的实现使用的

TransferStack

一个栈,实现中用head指针指向栈顶,接着我们看看它的实现模型:

1、线程put1执行 put(1)操作,由于当前没有配对的消费线程,所以put1线程入栈,自旋一小会后睡眠

等待,这时栈状态如下:

2、接着,线程put2再次执行了put(2)操作,跟前面一样,put2线程入栈,自旋一小会后睡眠等待,这时

栈状态如下:3、这时候,来了一个线程take1,执行了take操作,这时候发现栈顶为put2线程,匹配成功,但是实现

会先把take1线程入栈,然后take1线程循环执行匹配put2线程逻辑,一旦发现没有并发冲突,就会把栈

顶指针直接指向 put1线程

4、最后,再来一个线程take2,执行take操作,这跟步骤3的逻辑基本是一致的,take2线程入栈,然后

在循环中匹配put1线程,最终全部匹配完毕,栈变为空,恢复初始状态,如下图所示:

可以从上面流程看出,虽然put1线程先入栈了,但是却是后匹配,这就是非公平的由来。

总结

SynchronousQueue由于其独有的线程一一配对通信机制,在大部分平常开发中,可能都不太会用到,

但线程池技术中会有所使用,由于内部没有使用AQS,而是直接使用CAS,所以代码理解起来会比较困

难,但这并不妨碍我们理解底层的实现模型,在理解了模型的基础上,有兴趣的话再查阅源码,就会有

方向感,看起来也会比较容易,希望本文有所借鉴意义。 文章来源地址https://www.toymoban.com/news/detail-430888.html

到了这里,关于Java面试题字节流字符流的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • JavaScript实现字符编码转换utf-8/gbk(附完整源码)

    以上代码中,我们使用了JavaScript内置的TextEncoder和TextDecoder类来实现字符编码转换。这两个类是ES6新增的特性,需要在支持ES6的浏览器上才能正常运行。 使用示例: 运行结果说明转换成功。需要注意的是,在不同的浏览器中,对字符编码的支持程度可能不同,因此在使用时需

    2024年02月04日
    浏览(26)
  • Java基础09 —— 字符序列--String、StringBuilder、StringBuffer区别及其方法介绍

    字符与字符串 字符类型(char)是Java中的基本数据类型,占2个字节16位,默认值是 ‘u0000’ 。字符是用单引号引住的单个符号. 字符串(String)是用双引号引住的任意个字符,是引用数据类型,默认值是null 。字符串其实就是字符组成的序列 字符串声明 举例: 字符序列 多个字符

    2024年02月09日
    浏览(25)
  • Java-String、StringBuffer、StringBuilder区别及相关面试题

    在Java编程中,经常会遇到处理字符串的需求。Java提供了多个类来处理字符串,其中最常用的是String、StringBuffer和StringBuilder类。本文将介绍这三个类的基本用法和区别。 String是Java中最常用的字符串类,它是不可变的,也就是说一旦被创建,它的值就不能被改变。下面是Stri

    2024年02月11日
    浏览(28)
  • 数据库编码 问题 mysql 修改字符集为utf8mb4

    数据库编码 问题 mysql 修改字符集为utf8mb4 问题 ; 当向数据库插入表,或者在表中插入数据时,出现 ERROR 1366 (HY000): Incorrect string value: ‘xBDxF0xD3xB9’ for column ‘name’ at row 1 原因 数据库编码方式 和 表编码方式 以及 插入数据(字符串)的编码方式不同 我们可以查看建表,

    2023年04月08日
    浏览(28)
  • PostgreSQL——编码“GBK“的字符0x0xa8 0x27在编码“UTF8“没有相对应值`

    问题:编码\\\"GBK\\\"的字符0x0xa8 0x27在编码\\\"UTF8\\\"没有相对应值 原因:客户端编码与服务端编码不一致  解决方案:修改客户端编码方式和服务端一致  

    2024年02月15日
    浏览(31)
  • linux C.UTF-8和en-US.UTF-8语言环境有什么区别?(中文乱码问题)locale命令 centos、ubuntu修改编码集(没搞定!)

    我在ubuntu16.04虚拟机和英伟达盒子ubuntu18.04上分别部署了ngrest服务 用postman请求,ubuntu16.04虚拟机返回的中文是乱码,英伟达盒子ubuntu18.04不是乱码 用vi打开文件,ubuntu16.04虚拟机显示中文不是乱码,英伟达盒子ubuntu18.04是乱码 我用 echo $LANG 命令查看发现(或者直接用 locale 命令

    2024年02月06日
    浏览(37)
  • linux修改locale字符集编码为UTF-8/GBK,修改语言区域为zh-CN(中文-中国)

    linux系统的语言、区域、字符集编码由`locale’ [loʊˈkæl] 决定。 对应配置文件路径: centos7 /etc/locale.conf centos6 /etc/sysconfig/i18n 以下以centos&为例 LANG= LC_CTYPE=“POSIX” LC_NUMERIC=“POSIX” LC_TIME=“POSIX” LC_COLLATE=“POSIX” LC_MONETARY=“POSIX” LC_MESSAGES=“POSIX” LC_PAPER=“POSIX” LC_NAME=“

    2024年02月13日
    浏览(63)
  • 通过String字符生成base64编码在生成图片

         * base64转图片        //对字节数组字符串进行Base64解码并生成图片      * @param base64str base64码      * @return  判断是否为base64编码 生成base64编码,处理字符串            //Base64解码 判断base63str是否为空  生成图片

    2024年02月15日
    浏览(42)
  • java-字符流和字节流(一)

    File类介绍 它是 文件 和 目录 路径名的抽象表示 文件和目录是可以通过File封装成对象的 对于File而言,其封装的并不是一个真正存在的文件,仅仅是一个路径名而已。它可以是存在的,也可以是不存在的。将来是要通过具体的操作把这个路径的内容转换为具体存在的 File类的

    2024年02月07日
    浏览(22)
  • java基础入门-19-【IO(字节流&字符流)】

    生活中,你肯定经历过这样的场景。当你编辑一个文本文件,忘记了 ctrl+s ,可能文件就白白编辑了。当你电脑上插入一个U盘,可以把一个视频,拷贝到你的电脑硬盘里。那么数据都是在哪些设备上的呢?键盘、内存、硬盘、外接设备等等。 我们把这种数据的传输,可以看做

    2024年02月07日
    浏览(26)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包