Java语言基础知识点

  1. Switch语句参数: JDK7之前,switch 只能支持 byte、short、char、int 这几个基本数据类型和其对应的封装类型;如果想用String,需要将String包装成枚举类型作为参数;JDK7之后支持String类型直接作为参数参考
  2. for循环和foreach的区别: for循环效率高于foreach; for循环可以间隔遍历,步伐可以自由设置,但是foreach只能用于遍历读取每一个元素,还不能进行修改
  3. Java和C++区别:①Java有接口,有垃圾回收机制②C++有引用,有多重继承,有操作符重载
  4. JNI
  5. Java泛型:泛型是指在定义接口或者类时可以使用类型参数,泛型提供了编译期的类型安全检查,确保你只能把正确类型的对象放入集合中,避免了在运行时出现ClassCastException。Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节代码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉,JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。这个过程就称为类型擦除。比如一个方法如果接收List作为形式参数,那么如果尝试将一个List的对象作为实际参数传进去,却发现无法通过编译;因为这会产生隐含的类型转换问题,编译器直接就禁止这样的行为;Array不支持泛型,所以不能保证编译期的类型安全保证。
  6. BIO、NIO、AIO:三者之间的区别,类似于resin、apache、nginx在IO处理上的区别,从多线程互不干扰的阻塞式执行(resin),到轮询式的同步非阻塞式(apache),再到异步非阻塞式(nginx),现在这三种IO都在JDK中予以了支持

    • BIO是面向流的同步阻塞式IO方式,对于每一个客户端Socket连接,服务端都会新开一个线程处理,在此期间线程一直被占用,直到socket关闭,其中tcp的连接、数据的读取read、数据的返回都是被阻塞的。也就是说这期间会大量的浪费cpu的时间片和线程占用的内存资源。优缺点和适应情景BIO方式具有很高的响应速度,并且控制起来简单,在连接数较少且固定的架构非常有效,但是如果对每一个连接都产生一个线程的无疑是对系统资源的一种浪费,如果连接数较多将会出现资源不足的情况。
    • NIO(new IO从JDK1.4开始)是面向缓冲区的同步非阻塞式IO方式, 对于每一个客户端请求,服务端新开一个线程处理;即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理,当连接没有数据时,是没有工作线程来处理的; 它的非阻塞模式使用一个专用的reactor来处理分发IO事件,数据处理采用双通道模式,client和server各自维护一个选择器用于检测通道上的事件,通过访问选择器来处理感兴趣事件。优缺点和适应情景NIO方式适用于连接数目多且连接比较短(轻操作)的架构,比如聊天服务器,并发局限于应用中,编程比较复杂
    • AIO(Asynchronous IO从JDK1.7开始)是一种异步非阻塞的IO方式;对于每一个客户端的有效请求,服务端新开一个线程处理;即客户端的I/O请求都是由OS先完成了再通知服务器应用去启动线程进行处理,每个线程不必亲自处理IO,而是委派OS来处理,并且也不需要等待IO完成了,如果完成后,OS会通知的;优缺点和适应情景AIO方式使用于连接数目多且连接比较长(重操作)的架构,比如相册服务器,充分调用OS参与并发操作,编程比较复杂
  7. 为什么匿名内部类和局部内部类只能访问final变量?:因为虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或参数的作用域只在这个方法内部有效。因为编译的时候内部类和方法在同一级别上,所以方法中的变量或参数只有为final,内部类才可以引用,因为Java采用了一种copy local variable的方式来实现,也就是说把定义为final的局部变量拷贝过来用,而引用的也可以拿过来用,只是不能重新赋值。

  8. JDK8的新特性:
    • 新增函数接口,引入注解@FunctionalInterface,函数式接口就是只有一个方法的普通接口
    • 接口可以有默认方法和实现以及静态方法
    • 取消方法区/永久代,采用元空间取代
    • 新的Date-Time API
    • 引入Optional类来防止空指针异常,它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查,主要是利用orElseGet(),flatMap()等函数
    • Process类现在增加了两个新的方法用于终止进程;第一个是isAlive()方法,有了它你可以判断进程是否还活着。第二个方法则更加强大,它叫destroyForcibly(),你可以用它来强制的杀掉一个已经超时或者不再需要的进程
    • Java8引入了一个新的读写锁StampedLock。它不仅更快,同时还提供了一系列强大的API来实现乐观锁,这样如果没有写操作在访问临界区域的话,你只需很低的开销就能获取到一个读锁。访问结束后你可以查询锁来判断这期间是否发生了写操作,如果有的话再选择进行重试,升级锁,或者放弃这个操作
    • 新的增强的随机数生成方法SecureRandom.getinstanceStrong(),它能自动选择出当前JVM可用的最佳的随机数生成器。这样减少了获取失败的机率,同时也避免了默认的弱随机数生成器可能会导致密钥或者加密值容易被黑客攻破的问题
  9. Java 8 中的 Stream 是对集合(Collection)对象功能的增强,它专注于对集合对象进行各种非常便利、高效的聚合操作(aggregate operation),或者大批量数据操作 (bulk data operation)。Stream API 借助于同样新出现的 Lambda 表达式,极大的提高编程效率和程序可读性。同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势。通常编写并行代码很难而且容易出错, 但使用 Stream API 无需编写一行多线程的代码,就可以很方便地写出高性能的并发程序;Stream 可以并行化遍历操作,使用并行去遍历时,数据会被分成多个段,其中每一个都在不同的线程中处理,然后将结果一起输出; Stream 的并行操作依赖于 Java7 中引入的 Fork/Join 框架(JSR166y)来拆分任务和加速处理过程

    List<Integer> nums = Lists.newArrayList(1,null,3,4,null,6);
    // 创建stream --> map转换stream --> reduce聚合函数
    // 含义:给定一个Integer类型的List,获取其对应的Stream对象,然后进行过滤掉null,再去重,再每个元素乘以2,再每个元素被消费的时候打印自身,在跳过前两个元素,最后取前四个元素进行加和运算
    nums.stream().filter(num -> num != null).
                   distinct().mapToInt(num -> num * 2).
                   peek(System.out::println).skip(2).limit(4).sum();
    
  10. Java 8 中的 Lambda : 一段带有输入参数的可执行语句块,Lambda表达式取代了匿名类,取消了模板,允许用函数式风格编写代码。这样有时可读性更好,表达更清晰。书写形式:

    (params) -> expression
    (params) -> statement
    (params) -> { statements }                      
    
  11. 自动装箱就是Java自动将原始类型值转换成对应的对象,比如将int的变量转换成Integer对象,这个过程叫做装箱,反之将Integer对象转换成int类型值,这个过程叫做拆箱。自动装箱时编译器调用valueOf将原始类型值转换成对象,同时自动拆箱时,编译器通过调用类似intValue(),doubleValue()这类的方法将对象转换成原始类型值。原始类型byte,short,char,int,long,float,double和boolean对应的封装类为Byte,Short,Character,Integer,Long,Float,Double,Boolean。存在问题: ①自动装箱会隐式地创建对象,如果在一个循环体中,会创建无用的中间对象,这样会增加GC压力,拉低程序的性能 ② 缓存对象,在Java中,会对-128到127的Integer对象进行缓存,当创建新的Integer对象时,如果符合这个这个范围,并且已有存在的相同值的对象,则返回这个对象,否则创建新的Integer对象。
  12. JDK

参考链接

  1. Java8初体验(一)lambda表达式语法
  2. Java8初体验(二)Stream语法详解
  3. Java8 lambda表达式10个示例