从0开始回顾Java---系列六

简介: IO1、Java中IO流分为几种?流按照不同的特点,有很多种划分方式:• 按照流的流向分,可以分为输入流和输出流;• 按照操作单元划分,可以划分为字节流和字符流;• 按照流的角色划分为节点流和处理流。Java Io流共涉及40多个类,看上去杂乱,其实都存在一定的关联, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。• InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。• OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。IO流用到了什么设计模式?装饰器模式2、既

IO


1、Java中IO流分为几种?

流按照不同的特点,有很多种划分方式:

  • 按照流的流向分,可以分为输入流和输出流;
  • 按照操作单元划分,可以划分为字节流字符流
  • 按照流的角色划分为节点流和处理流。

Java Io流共涉及40多个类,看上去杂乱,其实都存在一定的关联, Java I0流的40多个类都是从如下4个抽象类基类中派生出来的。

  • InputStream/Reader: 所有的输入流的基类,前者是字节输入流,后者是字符输入流。
  • OutputStream/Writer: 所有输出流的基类,前者是字节输出流,后者是字符输出流。

IO流用到了什么设计模式?

装饰器模式

2、既然有了字节流,为什么还要有字符流?

  1. 其实字符流是由 Java 虚拟机将字节转换得到的,问题就出在这个过程还比较耗时,并且,如果我们不知道编码类型就很容易出现乱码问题
  2. 所以, I/O  流就干脆提供了一个直接操作字符的接口,方便我们平时对字符进行流操作。如果是音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。

3、字节流和字符流的区别?

  1. 操作单元不同:
  • 字符流处理的单元为2个字节的Unicode字符,分别操作字符、字符数组或字符串  ;
  • 字节流处理单元为1个字节, 操作字节和字节数组。
  1. 作用对象不同:
  • 字节流可用于任何类型的对象,包括二进制对象,而字符流只能处理字符或者字符串;  
  • 字节流提供了处理任何类型的IO操作的功能,但它不能直接处理Unicode字符,而字符流就可以。
  1. 用途不同:
  • 如果是音频文件、图片等媒体文件用字节流比较好,如果涉及到字符的话使用字符流比较好。

4、BIO,NIO,AIO的区别?

BIO

同步并阻塞,在服务器中实现的模式为一个连接一个线程。也就是说,客户端有连接请求的时候,服务器就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线程开销,当然这也可以通过线程池机制改善。

一般适用于连接数目小且固定的架构,这种方式对于服务器资源要求比较高,而且并发局限于应用中,是JDK1.4之前的唯一选择,但好在程序直观简单,易理解。

NIO

同步并非阻塞,在服务器中实现的模式为一个请求一个线程服务器端用一个线程处理多个连接,客户端发送的连接请求会注册到多路复用器上,多路复用器轮询到连接有IO请求就进行处理:

NIO一般适用于连接数目多且连接比较短(轻操作)的架构,并发局限于应用中,编程比较复杂,从JDK1.4开始支持。

AIO

异步并非阻塞,在服务器中实现的模式为一个有效请求一个线程,也就是说,客户端的IO请求都是通过操作系统先完成之后,再通知服务器应用去启动线程进行处理。

AIO一般适用于连接数目多且连接比较长(重操作)的架构,充分调用操作系统参与并发操作,编程比较复杂,从JDK1.7开始支持。

序列化

1、什么是序列化?什么是反序列化?

什么是序列化,序列化就是把Java对象转为二进制流,方便存储和传输。

所以反序列化就是把二进制流恢复成对象

2、如果有些变量不想序列化,怎么办?

对于不想进行序列化的变量,使用transient关键字修饰。

transient 关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。transient 只能修饰变量,不能修饰类和方法。

3、说说有几种序列化方式?

Java序列化方式有很多,常见的有三种:

  1. Java对象流序列化 :Java原生序列化方法即通过Java原生流(InputStreamOutputStream之间的转化)的方式进行转化,一般是对象输出流 ObjectOutputStream和对象输入流 ObjectInputStream  。
  2. Json序列化:这个可能是我们最常用的序列化方式,Json序列化的选择很多,一般会使用jackson包,通过ObjectMapper类来进行一些操作,比如将对象转化为byte数组或者将json串转化为对象。
  3. ProtoBuff序列化:ProtocolBuffer是一种轻便高效的结构化数据存储格式,ProtoBuff序列化对象可以很大程度上将其压缩,可以大大减少数据传输大小,提高系统性能。


泛型

1、什么是泛型,有什么作用?

JDK5中引入的一个新特性,泛型就是将类型参数化,其在编译时才确定具体的参数。泛型一般有三种使用方式:泛型类泛型接口泛型方法

泛型的好处:

  1. 类型安全
  • 泛型的主要目标是提高 Java 程序的类型安全
  • 编译时期就可以检查出因 Java 类型不正确导致的 ClassCastException类转换异常) 异常
  • 符合越早出错代价越小原则
  1. 消除强制类型转换
  • 泛型的一个附带好处是,使用时直接得到目标类型,消除许多强制类型转换
  • 所得即所需,这使得代码更加可读,并且减少了出错机会
  1. 潜在的性能收益
  • 由于泛型的实现方式,支持泛型(几乎)不需要 JVM 或类文件更改
  • 所有工作都在编译器中完成
  • 编译器生成的代码跟不使用泛型(和强制类型转换)时所写的代码几乎一致,只是更能确保类型安全而已

2、泛型擦除是什么?


泛型擦除使用泛型的时候加上的类型参数,编译器在编译的时候去掉类型参数。

泛型是一种语法糖,泛型这种语法糖的基本原理是类型擦除。Java中的泛型基本上都是在编译器这个层次来实现的,也就是说:泛型只存在于编译阶段,而不存在于运行阶段

编译后的字节码文件不包含泛型类型信息,因为虚拟机没有泛型类型对象,所有对象都属于普通类。例如定义 List<Object>List<String>,在编译后都会变成 List

3、为什么要泛型擦除?


主要是为了向下兼容,因为JDK5之前是没有泛型的,为了让JVM保持向下兼容,就出了泛型擦除这个策略。

注解

1、说一下你对注解的理解?


注解本质上是一个标记注解可以标记在类上、方法上、属性上等,标记自身也可以设置一些值,有了标记之后,我们就可以在编译或者运行阶段去识别这些标记,然后做一些事情,这就是注解的用处。例如 @Override标识一个方法是重写方法。


2、什么是元注解?


元注解是自定义注解的注解,例如:

  1. @Target:约束作用位置,值是 ElementType 枚举常量,包括 METHOD 方法、VARIABLE 变量、TYPE 类/接口、PARAMETER 方法参数、CONSTRUCTORS 构造方法和 LOACL_VARIABLE 局部变量等。
  2. @Rentention:约束生命周期,值是 RetentionPolicy 枚举常量,包括 SOURCE 源码、CLASS 字节码和 RUNTIME 运行时。
  3. @Documented:表明这个注解应该被 javadoc 记录。

3、注解的实现原理?


  1. 注解本质是一个继承了Annotation 的特殊接口,其具体实现类是Java 运行时生成的动态代理类。而
  2. 我们通过反射获取注解时,返回的是Java 运行时生成的动态代理对象$Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用AnnotationInvocationHandlerinvoke方法。该方法会从memberValues 这个Map 中索引出对应的值。而memberValues 的来源是Java 常量池。

反射

1、什么是反射?

我们通常都是利用new方式来创建对象实例,这可以说就是一种“正射”,这种方式在编译时候就确定了类型信息。而如果,我们想动态地获取类信息、创建类实例、调用类方法这时候就要用到反射

反射 在运行状态中,对于任意一个类都能知道它的所有属性和方法对于任意一个对象都能调用它的任意方法和属性,这种动态获取信息及调用对象方法的功能称为反射

反射最核心的四个类:

2、反射的原理?

通过将类对应的字节码文件加载到JVM内存中得到一个Class对象,通过这个Class对象可以反向获取实例的各个属性以及调用它的方法。


3、反射的使用场景?


  1. 通过反射运行配置文件内容
  • 加载配置文件,并解析配置文件得到相应信息;
  • 根据解析的字符串利用反射机制获取某个类的Class实例动态配置属性。
  1. JDK动态代理,通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口;
  2. jdbc通过Class.forName()加载数据的驱动程序;
  3. Spring解析xml装配Bean。

4、Class 类的作用?如何获取一个 Class 对象?


在程序运行期间,Java 运行时系统为所有对象维护一个运行时类型标识,这个信息会跟踪每个对象所属的类,虚拟机利用运行时类型信息选择要执行的正确方法,保存这些信息的类就是 Class,这是一个泛型类。

获取 Class 对象:

  1. 类名.class
  2. 对象的 getClass方法;
  3. Class.forName(类的全限定名)

JDK1.8新特性

1、JDK1.8新特性有哪些?

JDK1.8有不少新特性,我们经常接触到的新特性如下:

接口默认方法接口可以定义 default 修饰的默认方法,降低了接口升级的复杂性,还可以定义静态方法。

Lambda 表达式允许把函数作为参数传递到方法,简化匿名内部类代码,使代码更加简洁

函数式接口使用 @FunctionalInterface 标识,有且仅有一个抽象方法,可被隐式转换为 lambda 表达式。

Stream API引入函数式编程风格,提供了很多功能,使代码更加简洁。方法包括 forEach 遍历、count 统计个数、filter 按条件过滤、limit 取前 n 个元素、skip 跳过前 n 个元素、map 映射加工、concat 合并 stream 流等。

新日期 API增强了日期和时间 API,新的 java.time 包主要包含了处理日期、时间、日期/时间、时区、时刻和时钟等操作。

Optional 类处理空指针异常,提高代码可读性。


2、Lambda 表达式了解多少?

Lambda 表达式本质上是一段匿名内部类,也可以是一段可以传递的代码。

new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("Thread is running before Java8!");
            }
        }).start();

这是通过内部类的方式来重写run方法,使用Lambda表达式,还可以更加简洁:

new Thread( () -> System.out.println("Thread is running since Java8!") ).start();

当然不是每个接口都可以缩写成 Lambda 表达式。只有那些函数式接口才能缩写成 Lambda 表示式。

所谓函数式接口就是只包含一个抽象方法的声明。针对该接口类型的所有 Lambda 表达式都会与这个抽象方法匹配。

3、Java8有哪些内置函数式接口?


  1. JDK 1.8 API 包含了很多内置的函数式接口。其中就包括我们在老版本中经常见到的 ComparatorRunnable,Java 8 为他们都添加了 @FunctionalInterface 注解,以用来支持 Lambda 表达式。
  2. 除了这两个之外,还有Callable、Predicate、Function、Supplier、Consumer等等。

4、Optional了解吗?

Optional是用于防范NullPointerException。

可以将 Optional 看做是包装对象(可能是 null, 也有可能非 null)的容器。当我们定义了 一个方法,这个方法返回的对象可能是空,也有可能非空的时候,我们就可以考虑用 Optional 来包装它,这也是在 Java 8 被推荐使用的做法。

Optional<String> optional = Optional.of("bam");

optional.isPresent();           // true
optional.get();                 // "bam"
optional.orElse("fallback");    // "bam"

optional.ifPresent((s) -> System.out.println(s.charAt(0)));



相关文章
|
5天前
|
缓存 Java 调度
从0开始回顾Java---系列五
Integer 1、Integer a= 127,Integer b = 127;Integer c= 128,Integer d = 128;相等吗? 答案是a和b相等,c和d不相等。 ● 对于基本数据类型==比较的值 ● 对于引用数据类型==比较的是地址 Integer a= 127这种赋值,是用到了Integer自动装箱的机制。自动装箱的时候会去缓存池里取Integer对象,没有取到才会创建新的对象。 如果整型字面量的值在-128到127之间,那么自动装箱时不会new新的Integer对象,而是直接引用缓存池中的Integer对象,超过范围 a1==b1的结果是false。 publi
|
5天前
|
存储 安全 算法
从0开始回顾Java---系列八
HashMap 1、HashMap 有什么特点? HashMap 基于哈希表的 Map 接口实现,是以 key-value 存储形式存在,主要用来存放键值对。 特点: ● HashMap 的实现不是同步的,这意味着它不是线程安全的 ● key 是唯一不重复的,底层的哈希表结构,依赖 hashCode 方法和 equals 方法保证键的唯一 ● key、value 都可以为null,但是 key 位置只能是一个null ● HashMap 中的映射不是有序的,即存取是无序的 ● key 要存储的是自定义对象,需要重写 hashCode 和 equals 方法,防止出现地址不同内
|
5天前
|
存储 安全 Java
从0开始回顾Java---系列三
面向对象 1、谈一谈你对面向对象的理解 ? 面向过程: 一件事该怎么做,注重实现过程,以过程为中心; 面向对象: 实现对象是谁,只关心怎样使用,不关心具体实现(只关心实现对象是谁,有封装、继承、多态三大特性); 总结: ● 面向对象是一种编程思想,早期的面向过程的思想就是一件事该怎么做,而面向对象就是一件事该由谁来做,它怎么做的我不管,我只需要调用就行。而这些是由面向对象的三大特性来实现的,三大特性就是封装、继承、多态。 2、面向对象的三大特性? 封装:封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法。 多态: 所谓多态就是指程序中定义的引用变量所指
|
5天前
|
存储 缓存 安全
从0开始回顾Java---系列四
String 1、String 是 Java 基本数据类型吗?可以被继承吗?为什么? String是Java基本数据类型吗? 不是。Java 中的基本数据类型只有8个:byte、short、int、long、float、double、char、boolean;除了基本类型(primitive type),剩下的都是引用类型(reference type)。 String是一个比较特殊的引用数据类型。 String 类可以继承吗? 不行。String 类使用 final 修饰,是所谓的不可变类,无法被继承。 String 类为什么要被设计成不可继承? 1. 字符串是一种非常重要且常用的数据类型
|
5天前
|
存储 安全 算法
从0开始回顾Java---系列九
TreeMap 1、TreeMap 有什么特点? 1. TreeMap是基于红黑树的一种提供顺序访问的Map,增删改查的平均和最差时间复杂度均为 O(logn) ,最大特点是 Key 有序。 2. Key 必须实现 Comparable 接口或提供的 Comparator 比较器,所以 Key 不允许为 null。 3. TreeMap是一个线程不安全,有序的键值对集合,因为TreeMap实现了SotredMap接口。 4. TreeMap实现了Cloneable接口,可被克隆,实现了Serializable接口,可序列化; 2、讲讲 TreeMap 怎么实现有序的? TreeMap
|
5天前
|
存储 安全 Java
从0开始回顾Java---系列七
引言 1、常见集合有哪些? Java集合类主要由两个根接口Collection和Map派生出来的,Collection派生出了三个子接口:List、Set、Queue,因此Java集合大致也可分成List、Set、Queue、Map四种接口体系。 ● List代表了有序可重复集合,可直接根据元素的索引来访问; ● Set代表无序不可重复集合,只能根据元素本身来访问; ● Queue是队列集合。 ● Map代表的是存储key-value对的集合,可根据元素的key来访问value。 2、线程安全的集合有哪些?线程不安全的呢? 线程安全的: ● Hashtable:比HashMap多了个线
|
Java 编译器
强哥说Java--Java基础
强哥说Java--Java基础
61 0
|
存储 Java 开发者
[Java --- List]
我们之前实现过的顺序表,只能保存 int 类型的元素,如果现在需要保存 指向 Person 类型对象的引用的顺序表,请问应该如何解决?如果又需要保存指向 Book 对象类型的引用呢?
|
Java
Java报错:Cause: java.io.NotSerializableException: xxx 解决方案
原因是实体类没有开启序列化接口导致的 开启实体类序列化接口即可:
110 0
|
Java 编译器
Java---继承
继承的基本思想是,基于已有的类创造新的类。继承已存在的类就是复用这些类的方法,而且可以增加一些新的方法和字段,使新类能够适应新的情况,继承是Java程序设计中一项核心技术,它主要解决的问题是:共性的抽取,实现代码复用。
Java---继承