java是如何输出的(java输出的方式)

  • 时间:
  • 1635人关注

这是一篇关于java相关的编程问答内容,被223位程序员关注,内容涉及到java输出、java输出方式、java输出的方式等,由相妙颜 编辑补充,一起来看下大家的回答。

码农之家
精选回答2:JavaI/O深入学习之输入和输出

11小时14分钟前回答

前言

编程语言的I/O类库中常使用流这个抽象概念,它代表任何有能力产出数据的数据源对象或者是有能力接收数据的接收端对象。“流”屏蔽了实际的I/O设备中处理数据的细节。

在文章:<<Java I/O深入学习之File和RandomAccessFile>>中,我们讲到RandomAccessFile可以写入和读取文件,具备I/O功能,但是其只能针对文件,而I/O还涉及到很多其他场景比如网络、读取内存中的字符串等,所以Java类库中提供了一系列的类库来对其进行支持,也就是本文要总结学习的。

Java类库中的I/O类分成输入和输出两部分,可以在JDK文档里的类层次结构中查看到。通过继承,任何自Inputstream或Reader派生而来的类都含有名为read()的基本方法,用于读取单个字节或者字节数组。同样,任何自OutputStream或Writer派生而来的类都含有名为write()的基本方法,用于写单个字节或者字节数组。

但是,我们通常不会用到这些方法,它们之所以存在是因为别的类可以使用它们,以便提供更有用的接口。因此,我们很少使用单一的类来创建流对象,而是通过叠合多个对象来提供所期望的功能(这是装饰器设计模式的应用,也有专门写文总结过:装饰器模式)。实际上,Java中“流”类库让人迷惑的主要原因就在于:创建单一的结果流,却需要创建多个对象。

I/O需要应对的场景往往是多样化的,Java类库的设计者则是通过创建大量的类来解决这个难题,区区一篇文章难以详述,本文也只是尽力对传统I/O类库所涉及到的类提供一个总览,在把握整个脉络的前提下才能更好的理解并应用I/O类库来解决实际编程问题。如需涉及到细节,还是需要参考JDK文档。

1. InputStream/OutputStream

Java 1.0中,类库的设计者首先限定与输入有关的所有类都应该从InputStream继承,而与输出有关的所有类都应该从OutputStream继承。

1.1 InputStream

InputStream的作用是用来表示那些从不同数据源产生输入的类。这些数据源包括:

  • 字节数组;
  • String对象;
  • 文件;
  • “管道”,工作方式与实际管道相似,即从一端输入,从另一端输出;
  • 一个由其他种类的流组成的序列,以便我们可以将它们收集合并到一个流内;
  • 其他数据源,如Internet连接等;

每一种数据源都有相应的InputStream子类,作为基础构件:

  • ByteArrayInputStream,允许将内存的缓冲区当作InputStream使用;
  • StringBufferInputStream,将String转换成InputStream;
  • FileInputStream,用于从文件中读取信息;
  • PipedInputStream,产生用于写入相关PipedOutputStream的数据。实现“管道化”概念;
  • SequenceInputStream,将两个或多个InputStream对象转换成单一InputStream;

1.2 OutputStream

OutputStream的作用是表示那些可以输出到不同数据源的类,其具体的子类决定了输出所要去往的目标:字节数组、文件或管道,同样是作为基础构件:

  • ByteArrayOutputStream,在内存中创建缓冲区。所有送往“流”的数据都要放置在此缓冲区;
  • FileOutputStream,用于将信息写至文件;
  • PipedOutputStream,任何写入其中的信息都会自动作为相关PipedInputStream的输出,实现“管道化”概念;

1.3 装饰器

除了有上面的基础构件,还有两个子类:FilterInputStream/FilterOutputStream,也是InputStream和OutputStream的子类,它们为“装饰器”(decorator)类提供基类,其中,“装饰器”类可以把属性或有用的接口与基础构件连接在一起。因为上面提到的InputStream/OutputStream是单字节为单位来操作的,而真实的I/O场景远不止于此,所以就通过“装饰”(其原理是类之间的组合)的方式来扩展其功能。

我自己梳理了一下InputStream/OutputStream流继承层次结构,结合下面的解释来看可以对字节流体系有一个更清晰的认识:

JavaI/O深入学习之输入和输出

1.3.1 FilterInputStream

FilterInputStream类主要有如下子类,也就是具体装饰器:

  • DataInputStream;
  • BufferedInputStream;
  • LineNumberInputStream;

其提供的装饰功能主要在两个方面:

  • 读取不同的基本类型数据以及String对象,比如DataInputStream;
  • 在内部修改InputStream的行为方式:是否缓冲、是否保留它所读过的行,如BuffereInputStream、LineNumberInputStream;

1.3.2 FilterOutputStream

与FilterInputStream类似,FilterOutputStream主要是完成写入的功能,主要有如下装饰器:

  • DataOutputStream,与DataInputStream搭配使用,因此可以按照可移植方式向流中写入基本类型数据(int、char、long);
  • PrintStream,用于产生格式化输出。其中DataOutputStream处理数据的存储,PrintStream处理显示;
  • BufferedOutputStream,使用它以避免每次发送数据时都要进行实际的写操作。代表“使用缓冲区”。可以调用flush()清空缓冲区;

2. Writer/Reader

InputStream和OutputStream是提供面向字节形式的I/O,但是InputStream/OutputStream流继承层次结构仅支持8位字节流,并且不能很好地处理16位的Unicode字符。由于Unicode用于字符国际化(Java本身的char也是16位的Unicode),所以添加Reader/Writer继承层次结构就是为了在所有的I/O操作中都支持Unicode。

几乎所有原始的Java I/O流类都有相应的Reader和Writer类来提供天然的Unicode操作,我们可以对比一下:

JavaI/O深入学习之输入和输出

我们发现大体上,这两个不同的继承层次结构中的接口即使不能完全相同,但是也是非常相似的。

对于InputStream和OutputStream来说,我们会使用FilterInputStream和FilterOutputStream的装饰器子类来修改“流”以满足特殊需要。Reader/Writer的类继承层次结构继续沿用相同的思想,但是又并不完全采用上面说到的装饰器模式。如下是自己梳理的Reader/Writer继承层次结构:

JavaI/O深入学习之输入和输出

与前面的I/O继承层次结构图相对比可以发现,尽管BufferedOutputStream是FilterOutputStream的子类,但是BufferedWriter并不是FilterWriter的子类(FilterWriter是抽象类,但是没有任何子类,仅仅是作为一个占位符)。

2.1 适配器

有时我们必须把来自于“字节”层次结构中的类和“字符”层次结构中的类结合起来使用。为了实现这个目的,要用到“适配器”(adapter)类:InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer。

3. 总结

  • I/O需要应对的场景往往是多样化的,Java类库的设计者通过创建大量的类来解决这个难题,在实际使用中,通过装饰器模式避免“类爆炸”,但类的数量还是不少,这也是Java中“流”类库让人迷惑的主要原因;
  • InputStream和OutputStream是提供面向字节形式的I/O,而Reader和Writer则提供兼容Unicode与面向字符的IO功能;
  • 如果需要把字节流和字符流结合起来使用,可以使用适配器进行转换,InputStreamReader可以把InputStream转换为Reader,而OutputStreamWriter可以把OutputStream转换为Writer;

本文主要是梳理了传统I/O流的类继承层次结构,包括字节流(InputStream/OutputStream)和字符流(Writer/Reader),并没有一开始就一头扎进I/O类库的海洋中,主要是希望通过这种方式能够对整个I/O体系有一个清晰的认识,这对于进一步的学习可以有更明确的指导作用,下文会针对一些I/O的的典型使用方式进行总结。

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持码农之家。

展开问题
码农之家
精选回答3:Java实现的按照顺时针或逆时针方向输出一个数字矩阵功能示例

13小时21分钟前回答

本文实例讲述了Java实现的按照顺时针或逆时针方向输出一个数字矩阵功能。分享给大家供大家参考,具体如下:

题目:按照指定的长宽和输出方向,从外向内打印一个从 1 开始的数字矩阵,矩阵的开始位置在左上角。如下图

Java实现的按照顺时针或逆时针方向输出一个数字矩阵功能示例

代码及注释如下:

public class NumberMatrix {
  public static void main(String[] args) {
    int width = 25;
    int height = 12;
    boolean clockwise = false;
    System.out.println("码农之家测试结果:");
    outputMatrix(width, height, clockwise);
  }
  /**
   * 按照指定的长宽和输出方向,从外向内打印一个从 1 开始的数字矩阵,矩阵的开始位置在左上角。
   *
   * @param width   矩阵宽度
   * @param height  矩阵高度
   * @param clockwise 是否是顺时针方向
   */
  private static void outputMatrix(int width, int height, boolean clockwise) {
    // 首先判断最大数字的位数,以决定输出如何对齐
    int numLength = (int) Math.log10(width * height) + 1;
    // 决定输出的格式(最大位数 + 1个空格)
    String format = "%" + (numLength + 1) + "d";
    // 定义要输出的二维数组,注意维度是从高到低的
    // 此时 matrix 中所有元素的值都是 0
    int[][] matrix = new int[height][width];
    // 定义一个位置指针和一个计数器,位置指针进行移动,而计数器负责递增,递增后的数字
    // 被填充进矩阵,当 width * height 个数字填充完毕,这个矩阵就完成了。
    // 注意这里位置指针的第一个元素对应 matrix 的第一个维度 y,第二个元素对应第二个维度 x。
    int[] pointer = {0, 0};
    int counter = 1;
    // 定义当前移动的方向:1、2、3、4 分别表示上、右、下、左。
    // 顺时针的起始方向为右,逆时针的起始方向为下。
    int direction = clockwise ? 2 : 3;
    // 开始循环填充,每个填充分为三步
    for (int i = 1, max = width * height; i <= max; i++) {
      // 1. 填充内容
      int y = pointer[0];
      int x = pointer[1];
      matrix[y][x] = counter;
      // 2. 计数器自增
      counter += 1;
      // 3. 移动到下一个位置,因为这地方比较复杂,所以开个方法实现
      direction = move(matrix, width, height, pointer, direction, clockwise);
    }
    // 矩阵填充完毕,按照正常的方式循环输出即可
    for (int y = 0; y < height; y++) {
      for (int x = 0; x < width; x++) {
        System.out.printf(format, matrix[y][x]);
      }
      System.out.println(); // 完成一行后输出换行
    }
  }
  /**
   * 在矩阵中移动
   *
   * @param matrix  矩阵,用于判断前进方向的下一个位置是否已经填充了数字,如果是则转向
   * @param width   矩阵的宽
   * @param height  矩阵的高
   * @param pointer  指针的当前位置。调用本方法后里面的值会改变,除非方法返回 0
   * @param direction 指针当前移动的方向
   * @param clockwise 是否是要按顺时针方向转向
   *
   * @return 移动后的新方向(与原来的方向可能相同也可能不同)。如果无法再继续移动,则返回 0
   */
  private static int move(int[][] matrix, int width, int height, int[] pointer, int direction, boolean clockwise) {
    // 先尝试按照原来的方向移动到 newPointer
    int[] newPointer = moveDirectly(pointer, direction);
    // 检查 newPointer 是否合法,如果合法则将其赋值给 pointer 并保持原来的方向,方法完成
    if (isValid(newPointer, matrix, width, height)) {
      System.arraycopy(newPointer, 0, pointer, 0, 2);
      return direction;
    }
    // 进行转向,重新从 pointer 朝新的方向移动
    direction = turn(direction, clockwise);
    newPointer = moveDirectly(pointer, direction);
    // 检查 newPointer 是否合法(同前面一样)
    if (isValid(newPointer, matrix, width, height)) {
      System.arraycopy(newPointer, 0, pointer, 0, 2);
      return direction;
    }
    // 既无法前进也无法转向,那么无法继续移动。
    return 0;
  }
  // 判断矩阵中指定的位置是否可以填充
  private static boolean isValid(int[] newPointer, int[][] matrix, int width, int height) {
    // 位置不能超出矩阵范围
    if (newPointer[0] >= height
        || newPointer[0] < 0
        || newPointer[1] >= width
        || newPointer[1] < 0) {
      return false;
    }
    // 位置的内容应该为空
    if (matrix[newPointer[0]][newPointer[1]] != 0) {
      return false;
    }
    return true;
  }
  // 转向。根据我们对 direction 的定义,顺时针就是 +1,逆时针就是 -1
  private static int turn(int direction, boolean clockwise) {
    int newDirection = clockwise ? direction + 1 : direction - 1;
    if (newDirection > 4) {
      newDirection = 1;
    } else if (newDirection < 1) {
      newDirection = 4;
    }
    return newDirection;
  }
  /**
   * 朝指定的方向移动,并返回新的位置
   *
   * @param pointer  当前位置
   * @param direction 方向
   *
   * @return 新的位置
   */
  private static int[] moveDirectly(int[] pointer, int direction) {
    int y = pointer[0];
    int x = pointer[1];
    switch (direction) {
      case 1:
        return new int[]{y - 1, x};
      case 2:
        return new int[]{y, x + 1};
      case 3:
        return new int[]{y + 1, x};
      case 4:
        return new int[]{y, x - 1};
    }
    throw new IllegalArgumentException("方向不正确: " + direction);
  }
}

运行结果:

Java实现的按照顺时针或逆时针方向输出一个数字矩阵功能示例

更多关于java算法相关内容感兴趣的读者可查看本站专题:《Java数据结构与算法教程》、《Java操作DOM节点技巧总结》、《Java文件与目录操作技巧汇总》和《Java缓存操作技巧汇总》

希望本文所述对大家java程序设计有所帮助。

展开问题

参考资料

  • Java经典实例

    Java经典实例

    Java经典实例(第三版) 从lambda表达式、JavaFX 8,到网络编程和支持移动设备等方面,Java 8都有许多更新。包含了数百个经过实践验证的技巧,内容涵盖了广泛的Java主题,可帮助你快速进入编程

    大小:167.8 MBJava

    立即下载
  • JavaWeb开发实战1200例(第2卷)

    JavaWeb开发实战1200例(第2卷)

    大小:63 MBJavaWeb

    立即下载
  • JavaScript for PHP Developers

    JavaScript for PHP Developers

    大小:27.4 MBJavaScript

    立即下载
  • Java EE互联网轻量级框架整合开发:SSM框架和Redis实现

    Java EE互联网轻量级框架整合开发:SSM框架和Redis实现

    随着移动互联网的兴起,以Java技术为后台的互联网技术占据了市场的主导地位,而在Java互联网后台开发中,SSM框架(Spring Spring MVC MyBatis)成为了主要架构,《 Java EE互联网轻量级框架整合开发

    大小:489.1 MBJavaEE

    立即下载
  • Java精彩编程200例

    Java精彩编程200例

    《Java精彩编程200例》汇集了与Java桌面程序开发相关的200个实例及源代码,每个实例都按实例说明、关键技术、实现过程、扩展学习的顺序进行分析解读。全书主要内容有Java基础应用、图形与图表操作、文字操作与数据库、网络安全与多线程、Swing程序设计。每个实例都是经过一线工程师精心编选的,具有很强的实用性,这些实例为开发人员提供了全面的解决方案。配书光盘附赠了实例的完整源程序及部分讲解视频。《Java精彩编程200例》既适合Java程序员

    大小:79 MBJava编程

    立即下载
  • 代码不朽:编写可维护软件的10大要则(Java版)

    代码不朽:编写可维护软件的10大要则(Java版)

    本书提供代码示例,能够让读者一步步了解到如何对代码进行重构,从大量实践项目中提取出了编写可维护软件的10个最佳原则,帮助读者编写出高质量、简洁的代码,开发出松耦合、高可维护

    大小:25.1 MBJava

    立即下载
  • 《基于SpringBoot实现:Java分布式中间件开发入门与实战》源码文件

    《基于SpringBoot实现:Java分布式中间件开发入门与实战》源码文件

    内容简介 本书主要是围绕构建分布式系统架构的中间件开发实战展开。开篇介绍了分布式系统架构的相关知识要点,包括其功能、作用以及演进历程,并由此引出了分布式中间件的相关介绍;紧接着是重点介绍了目前在实际生产环境中应用比较广泛的几款Java中间件,包括缓存中间件Redis、消息中间件RabbitMQ、统一协调管理中间件ZooKeeper以及综合中间件Redisson等,详尽介绍了这几款中间件的基本概念、典型应用场景以及相应的功能组件。值得一提的是,在

    大小:206 MBSpringBoot

    立即下载
  • Offer来了:Java面试核心知识点精讲(框架篇)

    Offer来了:Java面试核心知识点精讲(框架篇)

    《 Offer来了:Java面试核心知识点精讲(框架篇) 》是对Java程序员面试中常见的微服务、网络编程、分布式存储、分布式计算等必备知识点的总结,包括Spring原理与应用、SpringCloud原理与应用、Netty网络编程原理与应用、ZooKeeper原理与应用、Kafka原理与应用、Hadoop原理与应用、HBase原理与应用、Cassandra原理与应用、ElasticSearch原理与应用、Spark原理与应用、Flink原理与应用。 这本书有11章。第一章阐述Spring的原理和应用,涉及

    大小:218 MBJava面试

    立即下载
  • Java语言程序设计教程

    Java语言程序设计教程

    本书基础知识和实际应用完美结合,经典案例完美诠释,以培养学生的面向对象的思维和面向对象的编程技术为核心,通过精选案例详细地介绍Java的基础知识和实用核心技术

    大小:55.5 MBJava

    立即下载

更多回答

2小时15分钟前回答

java 按行读取文件并输出到控制台的方法

如下所示: public static void main(String[] args) throws IOException { /* * 1.打开一个file * 2.new一个InputStreamReader←FileInputStream←file * 3.用BufferedReader(←InputStreamReader)的readLine()方法读取 * */ File ctoFile = new File("C://Users//gl//Desktop//ku//51cto.txt"); InputStreamReader rdCto = new InputStreamReader(new FileInputStream(ctoFile)); BufferedReader bfReader = new BufferedReader(rdCto); String txtline = null; while ((txtline = bfReader.readLine()) != null) { System.out.println(txtline); } bfReader.close(); }; 以上这篇java 按行读取文件并输出到控制台的方法就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持码农之家。 ……

11小时45分钟前回答

JavaScript基本的输出和嵌入式写法教程

JavaScript 没有任何打印或者输出的函数。 在 HTML 中, JavaScript 通常用于操作 HTML 元素。 操作 HTML 元素 如需从 JavaScript 访问某个 HTML 元素,您可以使用 document.getElementById(id) 方法。 请使用 "id" 属性来标识 HTML 元素,并 innerHTML 来获取或插入元素内容: 实例 !DOCTYPE htmlhtmlbodyh1我的第一个 Web 页面/h1p id="demo"我的第一个段落/pscriptdocument.getElementById("demo").innerHTML = "段落已修改。";/script/body/html 以上 JavaScript 语句(在 script 标签中)可以在 web 浏览器中执行: document.getElementById("demo") 是使用 id 属性来查找 HTML 元素的 JavaScript 代码 。 innerHTML = "Paragraph changed." 是用于修改元素的 HTML 内容(innerHTML)的 JavaScript 代码。 写……

26小时47分钟前回答

java 键盘输入一个数,输出数组中指定元素的示例

如下所示: package com.lcn.day05;import java.util.Scanner;public class ArrayDemo7 { /** *键盘输入一个数,输出数组中指定元素 */public static void main(String[] args) {// 定义一个数组int[] array = new int[]{123,456,789,321,654,987};//创建输入对象Scanner sc = new Scanner(System.in);System.out.println("请输入数组下标:");int input = sc.nextInt();System.out.println("你输入的是:"+input+"对应数组元素是:"+array[input]);} } 输出: 请输入数组下标: 5 你输入的是:5对应数组元素是:987 以上这篇java 键盘输入一个数,输出数组中指定元素的示例就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持码农之家。 ……