Java面试之语言基础

版权声明:本文为博主原创文章,转载请附上博文链接! https://blog.csdn.net/qq_24095055/article/details/88531257

Java八种基本数据类型

类型 字节/位数 封装类
byte 1/8 Byte
short 2/16 Short
int 4/32 Integer
long 8/64 Long
float 4/32 Integer
double 8/64 Double
char 2/16 Character
boolean 1/8 Boolean

Java三大基础特性

  1. 封装:将客观事物包装成类,隐藏具体实现,提供操作接口。在java中,对于对象的内部属性一般用private来实现隐藏,并通过set和get方法对外提供访问接口。
  2. 继承:子类获得父类的属性和行为(extends),并能根据自己的需求扩展出新的属性和行为,提高了代码的可复用性。

    overide(重写):
    当子父类中出现相同方法时,会先运行子类中的方法。
    重写的特点:方法名一样,访问修饰符权限不小于父类,返回类型一致,参数列表一致。

  3. 多态:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果,这就是多态性。简单的说:就是用基类的引用指向子类的对象。

面向对象和面向过程的区别

面向过程

  • 优点:性能比面向对象高,因为类调用时需要实例化,开销比较大,比较消耗资源;如单片机、嵌入式开发、Linux/Unix等一般采用面向过程开发,性能是最重要的因素。
  • 缺点:没有面向对象易维护、易复用、易扩展

面向对象

  • 优点:易维护、易复用、易扩展,由于面向对象有封装、继承、多态的特性,可以设计出低耦合的系统,使系统更加灵活、更加易于维护
  • 缺点:性能比面向过程低

Java与C++对比

比较点 Java C++
面向对象思想 完全对象化 可采用非面向对象(兼容C)
内存管理机制 Java自身管理 程序员管理
异常机制 完善 欠缺
第三方库 丰富(Log、JUnit等等) 较少(STL)
执行效率
操控底层 麻烦 方便

Java8 新特性

  • 默认方法:在接口里面有了一个实现的方法
  • Lambda 表达式:Lambda允许把函数作为一个方法的参数
  • Stream API:把真正的函数式编程风格引入到Java中
  • Date Time API:加强对日期与时间的处理
  • Optional 类:Optional 类已成为 Java 8类库的一部分,用来解决空指针异常
  • 方法引用:可以直接引用已有Java类或对象的方法或构造器
  • 新编译工具:Nashorn引擎(一个新的JavaScript引擎)、 类依赖分析器

Java反射机制

在运行状态中,对于任意一个类,都能够知道其所有属性和方法;对于任意一个对象,都能够调用其任意方法和属性。这种动态获取信息及动态调用对象方法的功能称为Java语言的反射机制。Java反射API如下:

  • Class:反射的核心类。
  • Field:类的成员变量。
  • Method:类的成员方法。
  • Constructor:类的构造方法。
/**获取Class对象的三种方式**/

// 1. 调用某个对象的getClass()方法
Class clazz = person.getClass();

// 2. 调用某个类的class属性
Class clazz = Person.class;

// 3. 使用Class类的forName()静态方法
Class clazz = Class.forName("Person");

反射机制主要提供了以下功能:

  1. 在运行时判断任意一个对象所属的类。
  2. 在运行时构造任意一个类的对象。
  3. 在运行时判断任意一个类所具有的成员变量和方法。
  4. 在运行时调用任意一个对象的方法。
  5. 生成动态代理。

Java异常机制

下面是Java异常类的组织结构,红色区域的异常类表示是程序需要显示捕捉或者抛出的。
在这里插入图片描述

Throwable

Throwable是Java异常的顶级类,所有的异常都继承于这个类。

Error,Exception是异常类的两个大分类。

Error

Error是非程序异常,即程序不能捕获的异常,一般是编译或者系统性的错误,如OutOfMemorry内存溢出异常等。

Exception

Exception是程序异常类,由程序内部产生。Exception又分为运行时异常、非运行时异常。

运行时异常

运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使没有用try-catch语句捕获它,也没有用throws子句声明抛出它,也会编译通过,运行时异常可处理或者不处理。运行时异常一般常出来定义系统的自定义异常,业务根据自定义异常做出不同的处理。

常见的运行时异常如NullPointException、ArrayIndexOutOfBoundsException等。

非运行时异常

非运行时异常是程序必须进行处理的异常,捕获或者抛出,如果不处理程序就不能编译通过。如常见的IOException、ClassNotFoundException等。

各种比较

Override和Overload的区别

比较点 Override Overload
中文 重写 重载
方法名 相同 相同
形参 相同 不同
返回类型 相同 可同可不同

Override 典型例子:接口方法的重写
Overload 典型例子:构造方法的重载

Interface与abstract类的区别

比较点 Interface abstract类
中文 接口 抽象类
能否实例化 不能 不能
方法能否实现 Java 8 可以 可以
一个类可以 implements多个 extends一个

equals()与==的区别

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)

equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

  • 情况1:类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
  • 情况2:类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来两个对象的内容相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。

举个例子:

public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 为一个引用
        String b = new String("ab"); // b为另一个引用,对象的内容一样
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 从常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一对象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}

说明:

  • String 中的 equals 方法是被重写过的,因为 object 的 equals 方法是比较的对象的内存地址,而 String 的 equals 方法比较的是对象的值。
  • 当创建 String 类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个 String 对象。

String、StringBuffer、StringBuilder

比较点 String StringBuffer StringBuilder
底层实现 final char value[] char[] value char[] value
可变性(参考底层) 不可变 可变 可变
修改时 不会改变自身 会改变自身 会改变自身
安全性 线程安全 线程安全 非线程安全
使用场景 少量数据 多线程大量数据 单线程大量数据
String str = "abc"; // str只是一个String对象的引用
str = "xyz"; // 创建了新对象"xyz",而引用str重新指向新对象

强弱软虚四种引用

比较点 强引用 软引用 弱引用 虚引用
特性 不会被回收 内存足则不回收,内存不足则回收 一旦发现变回收 必须和引用队列联合使用
使用场景 平时工作接触的最多(new) 可用来实现内存敏感的高速缓存 常用语Map数据结构中,引用占用内存空间较大的对象 跟踪对象被回收的活动

comparable接口和comparator接口

  • Comparable:在集合内部实现排序的接口,位于java.lang包。
  • Comparator:在集合外部实现排序的比较器接口,位于java.util包。
  1. comparable和comparator相同的地方

    他们都是java的一个接口, 并且是用来对自定义的class比较大小的,

    什么是自定义class: 如 public class Person{ String name; int age }.

    当我们有这么一个personList,里面包含了person1, person2, persion3…, 我们用Collections.sort( personList ),
    是得不到预期的结果的. 这时肯定有人要问, 那为什么可以排序一个字符串list呢:

    如 StringList{“hello1” , “hello3” , “hello2”}, Collections.sort( stringList ) 能够得到正确的排序, 那是因为
    String 这个对象已经帮我们实现了 Comparable接口 , 所以我们的 Person 如果想排序, 也要实现一个比较器。

  2. Comparator 和 Comparable 的区别

    • comparable
      Comparable 定义在 Person类的内部:
      public class Persion implements Comparable {..比较Person的大小..},
      因为已经实现了比较器,那么我们的Person现在是一个可以比较大小的对象了,它的比较功能和String完全一样,可以随时随地的拿来比较大小,因为Person现在自身就是有大小之分的。Collections.sort(personList)可以得到正确的结果。
    • Comparator
      Comparator 是定义在Person的外部的, 此时我们的Person类的结构不需要有任何变化,如
      public class Person{ String name; int age },
      然后我们另外定义一个比较器:
      public PersonComparator implements Comparator() {..比较Person的大小..},
      在PersonComparator里面实现了怎么比较两个Person的大小. 所以,用这种方法,当我们要对一个 personList进行排序的时候, 我们除了了要传递personList过去, 还需要把PersonComparator传递过去,因为怎么比较Person的大小是在PersonComparator
      里面实现的, 如:
      Collections.sort( personList , new PersonComparator() ).
  3. Comparator 和 Comparable 的实例
    Comparable
    Comparable:

    实现Comparable接口要覆盖compareTo方法, 在compareTo方法里面实现比较:

    public class Person implements Comparable {
         String name;
         int age
         public int compareTo(Person another) {
              int i = 0;
              i = name.compareTo(another.name); // 使用字符串的比较
              if(i == 0) { // 如果名字一样,比较年龄, 返回比较年龄结果
                   return age - another.age;
              } else {
                   return i; // 名字不一样, 返回比较名字的结果.
              }
         }
    }
    

    这时我们可以直接用 Collections.sort( personList ) 对其排序了.

    Comparator
    实现Comparator需要覆盖 compare 方法:

    public class Person{
         String name;
         int age
    }
    
    class PersonComparator implements Comparator { 
         public int compare(Person one, Person another) {
              int i = 0;
              i = one.name.compareTo(another.name); // 使用字符串的比较
              if(i == 0) { // 如果名字一样,比较年龄,返回比较年龄结果
                   return one.age - another.age;
              } else {
                   return i; // 名字不一样, 返回比较名字的结果.
              }
         }
    }
    

    Collections.sort( personList , new PersonComparator()) 可以对其排序

  4. 总结
    两种方法各有优劣, 用Comparable 简单, 只要实现Comparable 接口的对象直接就成为一个可以比较的对象,但是需要修改源代码, 用Comparator 的好处是不需要修改源代码, 而是另外实现一个比较器, 当某个自定义的对象需要作比较的时候,把比较器和对象一起传递过去就可以比大小了, 并且在Comparator 里面用户可以自己实现复杂的可以通用的逻辑,使其可以匹配一些比较简单的对象,那样就可以节省很多重复劳动了。

IO,BIO,NIO,AIO

Java中IO是以流为基础进行输入输出的,在网络编程中,接触到最多的就是利用Socket进行网络通信开发,主要有BIO、NIO、AIO三种实现方式。

比较点 BIO NIO AIO
中文 阻塞IO 非阻塞IO 异步IO
版本 - JDK1.4提出 JDK1.7提出
描述 服务端每次都需要创建一个线程来建立连接并处理消息。若建立连接、读写数据时发生阻碍,线程会阻塞。并发情况下,N个连接需要N个线程来处理。 使用一个线程来管理所有的Socket 通道,也就是基于Selector机制,查询到事件时(连接、读写),转发给不同的处理线程(Handler)。 在进行读写操作时,只需要调用相应的read/write方法,并传入CompletionHandler(动作完成处理器),在动作完成后会调用CompletionHandler。

序列化与反序列化

序列化即把对象转换为字节序列;反序列化即把字节序列恢复为对象。其使用场景大致有如下几种:

  • 把内存中的对象状态保存到文件或者数据库中。
  • 用套接字在网络上传送对象。
  • 通过RMI传输对象。

JVM会把字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化。

哪些情况会导致OOM或SOF,怎么解决

OutOfMemory(OOM)

  • Java堆溢出:一般由于内存泄露或者堆的大小设置不当引起。可以通过虚拟机参数-Xms、-Xmx等设置堆大小。
  • 方法区溢出:包括运行时常量池溢出,一般由于大量动态生成的Class导致。可以通过-XX:PermSize-XX:MaxPermSize限制方法区的大小。

使用JConsole生成Heap Dump文件,然后使用MAT分析排查

StackOverflow(SOF)

  • Java虚拟机栈和本地方法栈内存溢出:一般是由于程序中存在死循环或者深度递归调用造成的,栈设置太小也会出现此种溢出。可以通过虚拟机参数-Xss来设置栈大小。

JNI的使用

JNI (Java Native Interface)允许Java代码和其他语言代码(主要是C和C++)进行交互。

  1. 定义本地native方法
  2. 用javah命令生成.h头文件,拷贝至jni目录
  3. 在jni目录中编写.c文件
  4. 在jni目录中创建Android.mk文件,声明所引用的.c文件和生成的函数库名
  5. 创建Application.mk文件,声明支持的平台(armeabi、armeabi-v7a、x86)
  6. 使用ndk工具编译生成.so成动态链接库文件

参考博客:https://chung567115.blog.csdn.net/article/details/79772903

猜你喜欢

转载自blog.csdn.net/qq_24095055/article/details/88531257