Java基础--2021Java面试题系列教程--大白话解读

前言

序言

再高大上的框架,也须要扎实的基础才能玩转,高频面试问题更是基础中的高频实战要点。html

适合阅读人群

Java 学习者和爱好者,有必定工做经验的技术人,准面试官等。java

阅读建议

本教程是系列教程,包含 Java 基础,JVM,容器,多线程,反射,异常,网络,对象拷贝,JavaWeb,设计模式,Spring-Spring MVC,Spring Boot / Spring Cloud,Mybatis / Hibernate,Kafka,RocketMQ,Zookeeper,MySQL,Redis,Elasticsearch,Lucene面试

微信搜:JavaPub,阅读全套系列面试题教程算法

wx

[toc]编程

题目

1.JDK 和 JRE 有什么区别?谈谈你对 JVM 的理解

JDK 和 JREwindows

JDK(Java Development Kit)是Java开发运行环境,是java开发工具包,JDK包含了JRE的全部东西,同时还包含了编译java源码的编译器javac,还包含了不少java程序调试和分析的工具:jconsole,jvisualvm等工具软件,还包含了java程序编写所需的文档和demo例子程序。设计模式

JRE(Java Runtime Environment)它是Java运行环境,若是你不须要开发只须要运行Java程序,那么你能够安装JRE。(可是在运行JSP程序时,咱们仍是须要JDK,由于应用服务器会将 JSP 转换为 Java servlet,而且须要使用 JDK 编译 servlet。)数组

若是你须要运行java程序,只需安装JRE就能够了。若是你须要编写java程序,须要安装JDK。安全

JVM服务器

JVM(Java Virtual Machine) 就是咱们常说的 java 虚拟机是 JRE 的一部分,它是整个 java 实现跨平台的最核心的部分,全部的 java 程序会首先被编译为 .class 的类文件,这种类文件能够在虚拟机上执行。

JVM 主要工做是解释本身的指令集(即字节码)并映射到本地的 CPU 指令集和 OS 的系统调用。Java 语言是跨平台运行的,不一样的操做系统会有不一样的 JVM 映射规则,使之与操做系统无关,完成跨平台性。

JVM是Java Virtual Machine(Java虚拟机)的缩写,是经过在实际的计算机上仿真模拟各类计算机功能来实现的。由一套字节码指令集、一组寄存器、一个栈、一个垃圾回收堆和一个存储方法域等组成。JVM屏蔽了与操做系统平台相关的信息,使得Java程序只须要生成在Java虚拟机上运行的目标代码(字节码),就可在多种平台上不加修改的运行,这也是Java可以“一次编译,处处运行的”缘由。

附一张关系图:

jdk-jre-jvm关系图

总结:使用JDK(调用JAVA API)开发JAVA程序后,经过JDK中的编译程序(javac)将Java程序编译为Java字节码,在JRE上运行这些字节码,JVM会解析并映射到真实操做系统的CPU指令集和OS的系统调用。

2.== 和 equals 的区别是什么?

equals 和 == 都是来判断两个对象是否相等

  1. equals 是方法,而 == 是操做符;
  2. 对于基本类型的变量来讲(如 short、 int、 long、 float、 double),只能使用 == ,由于这些基本类型的变量没有 equals 方法。对于基本类型变量的比较,使用 == 比较, 通常比较的是它们的值
  3. 对于引用类型的变量来讲(例如 String 类)才有 equals 方法,由于 String 继承了 Object 类, equals 是 Object 类的通用方法。对于该类型对象的比较,默认状况下,也就是没有复写 Object 类的 equals 方法,使用 == 和 equals 比较是同样效果的,都是比较的是它们在内存中的存放地址。可是对于某些类来讲,为了知足自身业务需求,可能存在 equals 方法被复写的状况,这时使用 equals 方法比较须要看具体的状况,例如 String 类,使用 equals 方法会比较它们的值;
  • 对于 equals 方法没有被重写的状况。若是类没有重写该方法,那么默认使用的就是 Object 类的方法,如下是 Object 类的 equals 方法:
public boolean equals(Object obj) {
      return (this == obj);
  }

从源码能够看出,里面使用的就是 == 比较,因此这种状况下比较的就是它们在内存中的存放地址。

  • 对于 equals 方法被重写的状况。以 String 类为例,如下是 String 类中的 equals 方法:
@Override 
  public boolean equals(Object other) {
  if (other == this) {
    return true;
  }
  if (other instanceof String) {
      String s = (String)other;
      int count = this.count;
      if (s.count != count) {
          return false;
      }
      if (hashCode() != s.hashCode()) {
          return false;
      }
      char[] value1 = value;
      int offset1 = offset;
      char[] value2 = s.value;
      int offset2 = s.offset;
      for (int end = offset1 + count; offset1 < end; ) {
          if (value1[offset1] != value2[offset2]) {
              return false;
          }
          offset1++;
          offset2++;
      }
      return true;
  } else {
      return false;
  }
}

从源码能够看出, String 类复写了 equals 方法,当使用 == 比较内存的存放地址不相等时,接下来会比较字符串的内容是否 相等,因此 String 类中的 equals 方法会比较二者的字符串内容是否同样。

3.两个对象的 hashCode()相同,则 equals()也必定为 true,对吗?

答案是不必定的

java.lang.Object类中有两个很是重要的方法:

public boolean equals(Object obj)
public int hashCode()

Object 类是类继承结构的基础,因此是每个类的父类。全部的对象,包括数组,都实现了在 Object 类中定义的方法。

如下是Object对象API关于equal方法和hashCode方法的说明:

  • If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
  • It is not required that if two objects are unequal according to the equals(java.lang.Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.

简而言之,在集合查找时,hashcode能大大下降对象比较次数,提升查找效率!

Java对象的eqauls方法和hashCode方法是这样规定的:

  1. 相等(相同)的对象必须具备相等的哈希码(或者散列码)。
  2. 若是两个对象的hashCode相同,它们并不必定相同。

对以上俩点的说明

  1. 关于第一点,相等(相同)的对象必须具备相等的哈希码(或者散列码),为何?

想象一下,假如两个Java对象A和B,A和B相等(eqauls结果为true),但A和B的哈希码不一样,则A和B存入HashMap时的哈希码计算获得的HashMap内部数组位置索引可能不一样,那么A和B颇有可能容许同时存入HashMap,显然相等/相同的元素是不容许同时存入HashMap,HashMap不容许存放重复元素。

  1. 关于第二点,两个对象的hashCode相同,它们并不必定相同

也就是说,不一样对象的hashCode可能相同;假如两个Java对象A和B,A和B不相等(eqauls结果为false),但A和B的哈希码相等,将A和B都存入HashMap时会发生哈希冲突,也就是A和B存放在HashMap内部数组的位置索引相同这时HashMap会在该位置创建一个连接表,将A和B串起来放在该位置,显然,该状况不违反HashMap的使用原则,是容许的。固然,哈希冲突越少越好,尽可能采用好的哈希算法以免哈希冲突。

总而言之(all in all):

换句话说,equals()方法不相等的两个对象,hashcode()有可能相等(个人理解是因为哈希码在生成的时候产生冲突形成的)。反过来,hashcode()不等,必定能推出equals()也不等;hashcode()相等,equals()可能相等,也可能不等。

4.final 在 java 中有什么做用?

这是一个很基础,很能体现你基础是否扎实、是否有钻研精神的知识点。

final关键字的字面意思是最终的, 不可修改的. 这彷佛是一个看见名字就大概能知道怎么用的语法。

这三点必需要答出来:

  1. 被final修饰的类不能够被继承
  2. 被final修饰的方法不能够被重写
  3. 被final修饰的变量不能够被改变

要注意final类中的全部成员方法都会被隐式地指定为final方法。

第三点尤其重要

当final修饰的是一个基本数据类型数据时, 这个数据的值在初始化后将不能被改变; 当final修饰的是一个引用类型数据时, 也就是修饰一个对象时, 引用在初始化后将永远指向一个内存地址, 不可修改. 可是该内存地址中保存的对象信息, 是能够进行修改的.

JavaPub参考巨人(有一些简单例子,便于更好的理解final):https://www.cnblogs.com/dolph...

5.java 中的 Math.round(-1.5) 等于多少?

返回值:-1

四舍五入的原理是在参数上加0.5而后作向下取整。

一些案例:

public class test {
    public static void main(String[] args){
        System.out.println(Math.round(1.3));   //1
        System.out.println(Math.round(1.4));   //1
        System.out.println(Math.round(1.5));   //2
        System.out.println(Math.round(1.6));   //2
        System.out.println(Math.round(1.7));   //2
        System.out.println(Math.round(-1.3));  //-1
        System.out.println(Math.round(-1.4));  //-1
        System.out.println(Math.round(-1.5));  //-1
        System.out.println(Math.round(-1.6));  //-2
        System.out.println(Math.round(-1.7));  //-2
    }
}

6.String 属于基础的数据类型吗?

固然,每个Java学习者都知道它不是基础类型,可是你要知道更多细节。

Java中的数据类型分为两大类,基本数据类型和引用数据类型。

基本数据类型只有8种,可按照以下分类

  1. 整数类型:long、int、short、byte
  2. 浮点类型:float、double
  3. 字符类型:char
  4. 布尔类型:boolean

java基础类型

引用数据类型很是多,大体包括:

类、 接口类型、 数组类型、 枚举类型、 注解类型、 字符串型。

简单来讲,全部的非基本数据类型都是引用数据类型。

基本数据类型和引用数据类型的区别

  1. 存储位置
  • 基本变量类型
在方法中定义的非全局基本数据类型变量的具体内容是存储在栈中的
  • 引用变量类型
只要是引用数据类型变量,其具体内容都是存放在堆中的,而栈中存放的是其具体内容所在内存的地址(引用/句柄)

ps:经过变量地址能够找到变量的具体内容,就如同经过房间号能够找到房间通常

数据类型存储

  1. 传递方式
  • 基本变量类型
在方法中定义的非全局基本数据类型变量,调用方法时做为参数是按数值传递的
//基本数据类型做为方法参数被调用

public class Main{

   public static void main(String[] args){

       int msg = 100;

       System.out.println("调用方法前msg的值:\n"+ msg);    //100

       fun(msg);

       System.out.println("调用方法后msg的值:\n"+ msg);    //100

   }

   public static void fun(int temp){

       temp = 0;

   }

}

基本变量类型传递方式

  • 引用变量类型
引用数据类型变量,调用方法时做为参数是按引用传递的
//引用数据类型做为方法参数被调用



class Book{

    String name;

    double price;



    public Book(String name,double price){

        this.name = name;

        this.price = price;

    }

    public void getInfo(){

        System.out.println("图书名称:"+ name + ",价格:" + price);

    }



    public void setPrice(double price){

        this.price = price;

    }

}



public class Main{

   public static void main(String[] args){

       Book book = new Book("Java开发指南",66.6);

       book.getInfo();  //图书名称:Java开发指南,价格:66.6

       fun(book);

       book.getInfo();  //图书名称:Java开发指南,价格:99.9

   }



   public static void fun(Book temp){

       temp.setPrice(99.9);

   }

}
调用时为temp在栈中开辟新空间,并指向book的具体内容,方法执行完毕后temp在栈中的内存被释放掉

引用类型传递方式

其余(有关JVM)

  • java 中String 是个对象,是引用类型 ,基础类型与引用类型的区别是,基础类型只表示简单的字符或数字,引用类型能够是任何复杂的数据结构,基本类型仅表示简单的数据类型,引用类型能够表示复杂的数据类型,还能够操做这种数据类型的行为 。
  • java虚拟机处理基础类型与引用类型的方式是不同的,对于基本类型,java虚拟机会为其分配数据类型实际占用的内存空间,而对于引用类型变量,他仅仅是一个指向堆区中某个实例的指针
  • 基本类型存储在栈中,所以它们的存取速度要快于存储在堆中的对应包装类的实例对象,从Java5.0(1.5)开始,JAVA虚拟机(Java Virtual Machine)能够完成基本类型和它们对应包装类之间的自动转换。所以咱们在赋值、参数传递以及数学运算的时候像使用基本类型同样使用它们的包装类,但这并不意味着你能够经过基本类型调用它们的包装类才具备的方法。另外,全部基本类型(包括void)的包装类都使用了final修饰,所以咱们没法继承它们扩展新的类,也没法重写它们的任何方法
  • 基本类型的优点:数据存储相对简单,运算效率比较高。
  • 包装类的优点:自带方法丰富,集合的元素必须是对象类型,体现了Java一切皆是对象的思想。

JavaPub参考巨人:https://blog.csdn.net/py1215/...

7.java 中操做字符串都有哪些类?它们之间有什么区别?

String、StringBuffer、StringBuilder

  • String : final修饰,String类的方法都是返回new String。即对String对象的任何改变都不影响到原对象,对字符串的修改操做都会生成新的对象。
  • StringBuffer : 对字符串的操做的方法都加了synchronized,保证线程安全。
  • StringBuilder : 不保证线程安全,在方法体内须要进行字符串的修改操做,能够new StringBuilder对象,调用StringBuilder对象的append、replace、delete等方法修改字符串。

8.String str="i"与 String str=new String(“i”)同样吗?

答:不同。

由于内存的分配方式不同。String str="i"的方式,Java 虚拟机会将其分配到常量池中;而 String str=new String(“i”)方式,则会被分到堆内存中。

String str1 = "i";
    String str2 = "i";
    String str3 = new String("i");
    System.out.println(str1 == str2);//ture
    System.out.println(str2 == str3);//false

解释:

  1. Java 虚拟机会将其分配到常量池中:常量池不会重复建立对象。
在String str1="i"中,把i值存在常量池,地址赋给str1。假设再写一个String str2="i",则会把i的地址赋给str2,可是i对象不会从新建立,他们引用的是同一个地址值,共享同一个i内存。(须要注意的是:String str="i"; 由于String 是final类型的,因此“i”应该是在常量池。)
  1. 分到堆内存中:堆内存会建立新的对象。
假设再写一个String str3=new String(“i”),则会建立一个新的i对象,而后将新对象的地址值赋给str3。虽然str3和str1的值相同可是地址值不一样。(而new String("i");则是新建对象放到堆内存中。)

拓展知识

  • 堆内存用来存放由new建立的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
  • 常量池指的是在编译期被肯定,并被保存在已编译的.class文件中的一些数据。
  • == :引用数据类型比较地址值;
  • equals:引用类型,重写前比较两个对象地址值,重写后比较属性值。

9.如何将字符串反转?

俩种办法:

  1. 使用 StringBuilder 或 StringBuffer 的 reverse 方法,本质都调用了它们的父类 AbstractStringBuilder 的 reverse 方法实现。(JDK1.8)
  2. 不考虑字符串中的字符是不是 Unicode 编码,本身实现。
public static void main(String[] args) {
    String str = "ABCDE";
    System.out.println(reverseStringByStringBuilderApi(str));
    System.out.println(reverseString(str));
}

/**
 * 和StringBuffer()同样,都用了Java自实现的方法,使用位移来实现
 * @param
 * @return
 */
public static String reverseStringByStringBuilderApi(String str) {
    if (str != null && str.length() > 0) {
        return new StringBuilder(str).reverse().toString();
    }
    return str;
}

public static String reverseString(String str) {
    if (str != null && str.length() > 0) {
        int len = str.length();
        char[] chars = new char[len];
        for (int i = len - 1; i >= 0; i--) {
            chars[len - 1 - i] = str.charAt(i);
        }
        return new String(chars);
    }
    return str;
}

更多交换方式参考:https://blog.csdn.net/py1215/...

10.String 类的经常使用方法都有那些?

下面列举了20个经常使用方法。格式:返回类型 方法名 做用。

  1. 和长度有关:
  • int length() 获得一个字符串的字符个数
  1. 和数组有关:
  • byte[] getByte() ) 将一个字符串转换成字节数组
  • char[] toCharArray() 将一个字符串转换成字符数组
  • String split(String) 将一个字符串按照指定内容劈开
  1. 和判断有关:
  • boolean equals() 判断两个字符串的内容是否同样
  • boolean equalsIsIgnoreCase(String) 忽略过小写的比较两个字符串的内容是否同样
  • boolean contains(String) 判断一个字符串里面是否包含指定的内容
  • boolean startsWith(String) 判断一个字符串是否以指定的内容开头
  • boolean endsWith(String) 判断一个字符串是否以指定的内容结尾
  1. 和改变内容有关:
  • String toUpperCase() 将一个字符串所有转换成大写
  • String toLowerCase() 将一个字符串所有转换成小写
  • String replace(String,String) 将某个内容所有替换成指定内容
  • String replaceAll(String,String) 将某个内容所有替换成指定内容,支持正则
  • String repalceFirst(String,String) 将第一次出现的某个内容替换成指定的内容
  • String substring(int) 从指定下标开始一直截取到字符串的最后
  • String substring(int,int) 从下标x截取到下标y-1对应的元素
  • String trim() 去除一个字符串的先后空格
  1. 和位置有关:
  • char charAt(int) 获得指定下标位置对应的字符
  • int indexOf(String) 获得指定内容第一次出现的下标
  • int lastIndexOf(String) 获得指定内容最后一次出现的下标

11.抽象类必需要有抽象方法吗?

答案是:没必要须

这道题考察的是抽象类的知识:

  1. 抽象类必须有关键字 abstract 来修饰。
  2. 抽象类能够不含有抽象方法
  3. 若是一个类包含抽象方法,则该类必须是抽象类

抽象类的特性和使用:

  • 抽象类不能被实例化。由于抽象类中方法未具体化,这是一种不完整的类,因此直接实例化也就没有意义了。
  • 抽象类的使用必须有子类,使用extends继承,一个子类只能继承一个抽象类。
  • 子类(若是不是抽象类)则必须覆写抽象类之中的所有抽象方法(若是子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。)。
  • 抽象类能够不包含抽象方法,但若是类中包含抽象方法,就必须将该类声明为抽象类。

抽象类的基本使用示例:

//定义一个抽象类
abstract class A{

    //普通方法
    public void fun(){
        System.out.println("存在方法体的方法");
    }

    //抽象方法,没有方法体,有abstract关键字作修饰
    public abstract void print();
}

//单继承
//B类是抽象类的子类,是一个普通类
class B extends A{

    //强制要求覆写
    @Override
    public void print() {
        System.out.println("Hello World !");
    }

}
public class TestDemo {

    public static void main(String[] args) {
        //向上转型
        A a = new B();

        //被子类所覆写的过的方法
        a.print();
    }
}

JavaPub参考巨人:https://www.jianshu.com/p/053...

12.普通类和抽象类有哪些区别?

包含抽象方法的类称为抽象类,但并不意味着抽象类中只能有抽象方法,它和普通类同样,一样能够拥有成员变量和普通的成员方法。注意,抽象类和普通类的主要有三点区别:

  1. 抽象方法必须为public或者protected(由于若是为private,则不能被子类继承,子类便没法实现该方法),缺省状况下默认为public。
  2. 抽象类不能用来建立对象;
  3. 若是一个类继承于一个抽象类,则子类必须实现父类的抽象方法。若是子类没有实现父类的抽象方法,则必须将子类也定义为为abstract类。

13.抽象类能使用 final 修饰吗?

不能,抽象类是被用于继承的,final修饰表明不可修改、不可继承的。

这个在前面几题有过介绍。

14.接口和抽象类有什么区别?

语法层面上的区别,也是咱们平常官方的一些说法:

  1. 抽象类能够提供成员方法的实现细节,而接口中只能存在public abstract 方法;
  2. 抽象类中的成员变量能够是各类类型的,而接口中的成员变量只能是public static final类型的;
  3. 接口中不能含有静态代码块以及静态方法,而抽象类能够有静态代码块和静态方法;
  4. 一个类只能继承一个抽象类,而一个类却能够实现多个接口。
接口的设计目的,是对类的行为进行约束。而抽象类的设计目的,是代码复用。总结来讲,继承是一个 "是否是"的关系,而 接口 实现则是 "有没有"的关系。若是一个类继承了某个抽象类,则子类一定是抽象类的种类,而接口实现则是有没有、具有不具有的关系。

抽象和继承是 Java 中很是重要的东西,深刻理解可让咱们对 Java 技术理解更深入,参考的这篇知乎博文很是好。

JavaPub参考巨人:https://www.zhihu.com/questio...

15.java 中 IO 流分为几种?

Java中的流分为两种,一种是字节流,另外一种是字符流,分别由四个抽象类来表示(每种流包括输入和输出两种因此一共四个):InputStream,OutputStream,Reader,Writer。Java中其余多种多样变化的流均是由它们派生出来的.

字符流和字节流是根据处理数据的不一样来区分的。字节流按照8位传输,字节流是最基本的,全部文件的储存是都是字节(byte)的储存,在磁盘上保留的并非文件的字符而是先把字符编码成字节,再储存这些字节到磁盘。

  1. 字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;
  2. 节流提供了处理任何类型的IO操做的功能,但它不能直接处理Unicode字符,而字符流就能够。

读文本的时候用字符流,例如txt文件。读非文本文件的时候用字节流,例如mp3。理论上任何文件都可以用字节流读取,但当读取的是文本数据时,为了能还原成文本你必须再通过一个转换的工序,相对来讲字符流就省了这个麻烦,能够有方法直接读取。

字符流处理的单元为2个字节的Unicode字符,分别操做字符、字符数组或字符串,而字节流处理单元为1个字节, 操做字节和字节数组。因此字符流是由Java虚拟机将字节转化为2个字节的Unicode字符为单位的字符而成的,因此它对多国语言支持性比较好!

  • 按操做方式分类结构图:

按操做方式分类结构图

  • 按操做对象分类结构图:

按操做对象分类结构图

代码Demo参考:https://www.yisu.com/zixun/12...

16.BIO、NIO、AIO 有什么区别?

BIO

BIO全称是Blocking IO,是JDK1.4以前的传统IO模型,自己是同步阻塞模式。
线程发起IO请求后,一直阻塞IO,直到缓冲区数据就绪后,再进入下一步操做。针对网络通讯都是一请求一应答的方式,虽然简化了上层的应用开发,但在性能和可靠性方面存在着巨大瓶颈,试想一下若是每一个请求都须要新建一个线程来专门处理,那么在高并发的场景下,机器资源很快就会被耗尽。

NIO

NIO也叫Non-Blocking IO 是同步非阻塞的IO模型。线程发起io请求后,当即返回(非阻塞io)。同步指的是必须等待IO缓冲区内的数据就绪,而非阻塞指的是,用户线程不原地等待IO缓冲区,能够先作一些其余操做,可是要定时轮询检查IO缓冲区数据是否就绪。Java中的NIO 是new IO的意思。实际上是NIO加上IO多路复用技术。普通的NIO是线程轮询查看一个IO缓冲区是否就绪,而Java中的new IO指的是线程轮询地去查看一堆IO缓冲区中哪些就绪,这是一种IO多路复用的思想。IO多路复用模型中,将检查IO数据是否就绪的任务,交给系统级别的select或epoll模型,由系统进行监控,减轻用户线程负担。
NIO主要有buffer、channel、selector三种技术的整合,经过零拷贝的buffer取得数据,每个客户端经过channel在selector(多路复用器)上进行注册。服务端不断轮询channel来获取客户端的信息。channel上有connect,accept(阻塞)、read(可读)、write(可写)四种状态标识。根据标识来进行后续操做。因此一个服务端可接收无限多的channel。不须要新开一个线程。大大提高了性能。

AIO

AIO是真正意义上的异步非阻塞IO模型。
上述NIO实现中,须要用户线程定时轮询,去检查IO缓冲区数据是否就绪,占用应用程序线程资源,其实轮询至关于仍是阻塞的,并不是真正解放当前线程,由于它仍是须要去查询哪些IO就绪。而真正的理想的异步非阻塞IO应该让内核系统完成,用户线程只须要告诉内核,当缓冲区就绪后,通知我或者执行我交给你的回调函数。
AIO能够作到真正的异步的操做,但实现起来比较复杂,支持纯异步IO的操做系统很是少,目前也就windows是IOCP技术实现了,而在Linux上,底层仍是是使用的epoll实现的。

资料

BIO (Blocking I/O): 同步阻塞I/O模式,数据的读取写入必须阻塞在一个线程内等待其完成。在活动链接数不是特别高(小于单机1000)的状况下,这种模型是比较不错的,可让每个链接专一于本身的 I/O 而且编程模型简单,也不用过多考虑系统的过载、限流等问题。线程池自己就是一个自然的漏斗,能够缓冲一些系统处理不了的链接或请求。可是,当面对十万甚至百万级链接的时候,传统的 BIO 模型是无能为力的。所以,咱们须要一种更高效的 I/O 处理模型来应对更高的并发量。

NIO (New I/O): NIO是一种同步非阻塞的I/O模型,在Java 1.4 中引入了NIO框架,对应 java.nio 包,提供了 Channel , Selector,Buffer等抽象。NIO中的N能够理解为Non-blocking,不单纯是New。它支持面向缓冲的,基于通道的I/O操做方法。 NIO提供了与传统BIO模型中的 Socket 和 ServerSocket 相对应的 SocketChannel 和 ServerSocketChannel 两种不一样的套接字通道实现,两种通道都支持阻塞和非阻塞两种模式。阻塞模式使用就像传统中的支持同样,比较简单,可是性能和可靠性都很差;非阻塞模式正好与之相反。对于低负载、低并发的应用程序,可使用同步阻塞I/O来提高开发速率和更好的维护性;对于高负载、高并发的(网络)应用,应使用 NIO 的非阻塞模式来开发

AIO (Asynchronous I/O): AIO 也就是 NIO 2。在 Java 7 中引入了 NIO 的改进版 NIO 2,它是异步非阻塞的IO模型。异步 IO 是基于事件回调机制实现的,也就是应用操做以后会直接返回,不会堵塞在那里,当后台处理完成,操做系统会通知相应的线程进行后续的操做。AIO 是异步IO的缩写,虽然 NIO 在网络操做中,提供了非阻塞的方法,可是 NIO 的 IO 行为仍是同步的。对于 NIO 来讲,咱们的业务线程是在 IO 操做准备好时,获得通知,接着就由这个线程自行进行 IO 操做,IO操做自己是同步的。查阅网上相关资料,我发现就目前来讲 AIO 的应用还不是很普遍,Netty 以前也尝试使用过 AIO,不过又放弃了。

17.Files的经常使用方法都有哪些?

Files.exists():检测文件路径是否存在。

Files.createFile():建立文件。

Files.createDirectory():建立文件夹。

Files.delete():删除一个文件或目录。

Files.copy():复制文件。

Files.move():移动文件。

Files.size():查看文件个数。

Files.read():读取文件。

Files.write():写入文件。

微信关注:JavaPub ,带走全套宝典

目录图片

相关文章
相关标签/搜索