Java 面试题整理(语法和集合部分)

通过参考网上诸多大佬的博客,归纳整理的一部分Java 面试资料,仅供大家参考

Java概述

1. JVM、JRE和JDK的关系

  • JVM
    Java Virtual Machine是Java虚拟机,Java程序需要运行在Java虚拟机上,不同开发平台由不同的指令集构成,在各个不同的开发平台上安装有不同的JVM,来达到在不同的平台上运行相同代码的原理。因此Java语言可以实现跨平台特性。
  • JRE
    Java Runtime Environment包括Java虚拟机和Java程序所需的核心类库等。核心类库主要包括java.lang包:包含了运行Java程序必不可少的系统类,如基本数据类型、基本数学函数、字符串处理、线程、异常处理类等。
  • JDK
    Java Development Kit 是用于支持Java程序开发的最小环境,其中包括JRE。JRE是支持Java程序运行的最小环境。

2. Java 语言的特点有哪些

  1. 简单性:语法简单,无需深奥训练即可掌握
  2. 面向对象:封装、继承、多态
  3. 跨平台:由于Java虚拟机的存在,可实现平台无关性
  4. 健壮性:Java语言的强类型机制,异常处理等机制,使得开发人员能够快速定位bug
  5. 支持网络编程
  6. 支持多线程
  7. 安全性

3. Java和C++的区别

  1. Java是解释型语言,所谓的解释型语言,就是源码会先经过一次编译,成为中间码,中间码再被解释器解释成机器码。对于Java而言,中间码就是字节码(.class),而解释器在JVM中内置了。
  2. C++是编译型语言,所谓编译型语言,就是源码一次编译,直接在编译的过程中链接了,形成了机器码。
  3. C++比Java执行速度快,但是Java可以利用JVM跨平台。
  4. Java是纯面向对象的语言,所有代码(包括函数、变量)都必须在类中定义。而C++中还有面向过程的东西,比如是全局变量和全局函数。
  5. C++中有指针,Java中没有,但是有引用。
  6. C++支持多继承,Java中类都是单继承的。但是继承都有传递性,同时Java中的接口是多继承,类对接口的实现也是多实现。
  7. C++中,开发需要自己去管理内存,但是Java中JVM有自己的GC机制,虽然有自己的GC机制,但是也会出现OOM和内存泄漏的问题。C++中有析构函数,Java中Object的finalize方法。
  8. C++运算符可以重载,但是Java中不可以。同时C++中支持强制自动转型,Java中不行,会出现ClassCastException(类型不匹配)。

Java基础语法

1. 九种基本数据类型

在这里插入图片描述

自动装箱拆箱:
一般我们要创建一个类的对象实例的时候,我们会这样:
Class a = new Class(parameter); 而当我们创建一个Integer对象时,却可以这样:int i = 100; (注意:不是 Integer i = new Integer(100); )
实际上,执行上面那句代码的时候,系统为我们执行了:Integer i = Integer.valueOf(100);
此即基本数据类型的自动装箱功能。
而当我们执行 Integer i = 1; int t = i; 时,便把对象中的数据从对象中取出,即实现了自动拆箱。

Integer 的自动拆箱:
//在-128~127 之外的数
 Integer i1 =200;  
 Integer i2 =200;          
 System.out.println("i1==i2: "+(i1==i2));                   
 // 在-128~127 之内的数
 Integer i3 =100;  
 Integer i4 =100;  
 System.out.println("i3==i4: "+(i3==i4));
 输出的结果是:
    i1==i2: false
    i3==i4: true

在Java 5后,在Integer的操作上引入了一个新功能来节省内存和提高性能。整型对象通过使用相同的对象引用实现了缓存和重用。当Integer需要自动装箱时,如果在整数区间-128 ~ 127 之中,会直接引用缓存中的对象,避免了新建对象。如此以来,即可避免装箱或拆箱操作频繁的创建对象。
具体实现源码如下:

    @HotSpotIntrinsicCandidate
    public static Integer valueOf(int i) {
        return i >= -128 && i <= Integer.IntegerCache.high ? Integer.IntegerCache.cache[i + 128] : new Integer(i);
    }

2. Object 类的公用方法

    @HotSpotIntrinsicCandidate
    public Object() {
    }

    @HotSpotIntrinsicCandidate
    public final native Class<?> getClass();

    @HotSpotIntrinsicCandidate
    public native int hashCode();

    public boolean equals(Object obj) {
        return this == obj;
    }

    @HotSpotIntrinsicCandidate
    protected native Object clone() throws CloneNotSupportedException;

    public String toString() {
        return this.getClass().getName() + "@" + Integer.toHexString(this.hashCode());
    }

    @HotSpotIntrinsicCandidate
    public final native void notify();

    @HotSpotIntrinsicCandidate
    public final native void notifyAll();

    public final void wait() throws InterruptedException {
        this.wait(0L);
    }

    public final native void wait(long var1) throws InterruptedException;

    public final void wait(long timeoutMillis, int nanos) throws InterruptedException {
        if (timeoutMillis < 0L) {
            throw new IllegalArgumentException("timeoutMillis value is negative");
        } else if (nanos >= 0 && nanos <= 999999) {
            if (nanos > 0) {
                ++timeoutMillis;
            }

            this.wait(timeoutMillis);
        } else {
            throw new IllegalArgumentException("nanosecond timeout value out of range");
        }
    }
  1. clone()方法 :返回一个独立的对象,和原对象地址不同,属性相同。并且只有实现Cloneable接口才能调用clone方法。返回的对象为Object类型,可通过强转转回原对象类型。
  2. equals()方法:判断两个对象是否相等,和“==”作用相同,一般在子类中被重写。
  3. hashCode()方法:该方法时为了配合基于散列的集合可以正常运行(例如,当向集合中插入对象时,如何判别在集合中是否已经存在该对象?(集合中不允许重复的元素存在)),重写了equals方法一般都要重写hashCode方法。这个方法在一些具有哈希功能的Collection中用到。
  4. getClass()方法:final方法,返回此Object的运行时类。
  5. wait() 方法
    使当前线程等待该对象的锁,当前线程必须是该对象的拥有者,也就是具有该对象的锁。
    wait()方法一直等待,直到获得锁或者被中断。wait(long timeout)设定一个超时间隔,如果在规定时间内没有获得锁就返回。
    调用该方法后当前线程进入睡眠状态,直到以下事件发生:
    • 其他线程调用了该对象的notify方法
    • 其他线程调用了该对象的notifyAll方法
    • 其他线程调用了interrupt中断该线程
    • 时间间隔到了
      此时该线程就可以被调度了,如果是被中断的话就抛出一个InterruptedException异常
  6. notify() 方法:唤醒该对象某个处于等待状态的线程。
  7. notifyAll()方法:唤醒在该对象上等待的所有线程
  8. toString()方法:把类转换成字符串,一般子类都会进行重写。

3. final 关键字的用法

  • 项目被final修饰的类不可以被继承
  • 被final修饰的方法不可以被重写
  • 被final修饰的变量不可以被改变.如果修饰引用,那么表示引用不可变,引用指向的内容可变.
  • 被final修饰的方法,JVM会尝试将其内联,以提高运行效率
  • 被final修饰的常量,在编译阶段会存入常量池中.

4. String,StringBuffer和StringBuilder区别

String StringBuffer StringBuilder
String的值是不可变的,这就导致每次对String的操作都会生成新的String对象,不仅效率低下,而且浪费大量优先的内存空间 StringBuffer是可变类,和线程安全的字符串操作类,任何对它指向的字符串的操作都不会产生新的对象。 可变类,速度更快
不可变 可变类 可变类
线程安全 线程不安全
多线程操作字符串 单线程操作字符串

5. 接口和抽象类的区别是什么

  1. 抽象类可以提供成员方法的实现体并且成员方法可以是各种类型的,而接口中只能存在public abstract final static方法;
  2. 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
  3. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
  4. 设计层面不同,抽象类作为很多子类的父类,它是一种模板式设计。而接口是一种行为规范,它是一种辐射式设计。
  5. 抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。

6. 反射机制:框架设计的灵魂

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

反射的应用:

在日常业务开发中很少会用到反射机制。但实际上有很多设计、开发都与反射机制有关,例如模块化的开发,通过反射去调用对应的字节码;动态代理设计模式也采用了反射机制,还有我们日常使用的 Spring/mybatis 等框架也大量使用到了反射机制。

  1. 我们在使用JDBC连接数据库时使用Class.forName()通过反射加载数据库的驱动程序;
  2. Spring框架也用到很多反射机制,最经典的就是xml的配置模式。Spring 通过 XML 配置模式装载 Bean 的过程:
1) 将程序内所有 XML 或 Properties 配置文件加载入内存中; 
2)Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息; 
3)使用反射机制,根据这个字符串获得某个类的Class实例; 4)动态配置实例的属性

7.集合知识点总结:

7.1 体系框架

在这里插入图片描述

Collection

  1. List
    • Arraylist:Object数组
    • Vector:Object数组
    • LinkedList:双向链表
  2. Set
    • HashSet(无序,唯一): 基于 HashMap 实现的,底层采用 HashMap 来保存元素
    • LinkedHashSet: LinkedHashSet 继承于 HashSet,并且其内部是通过 LinkedHashMap 来实现的。有点类似于我们之前说的LinkedHashMap 其内部是基于 HashMap 实现一样,不过还是有一点点区别的
    • TreeSet(有序,唯一): 红黑树(自平衡的排序二叉树)
Map
  1. HashMap:JDK1.8之前HashMap由数组+链表组成的,数组是HashMap的主体,链表则是主要为了解决哈希冲突而存在的(“拉链法”解决冲突)。JDK1.8以后在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间
  2. LinkedHashMap :继承自 HashMap,所以它的底层仍然是基于拉链式散列结构即由数组和链表或红黑树组成。另外,LinkedHashMap 在上面结构的基础上,增加了一条双向链表,使得上面的结构可以保持键值对的插入顺序。同时通过对链表进行相应的操作,实现了访问顺序相关逻辑。
  3. Hashtable: 数组+链表组成的,数组是 HashMap 的主体,链表则是主要为了解决哈希冲突而存在的
  4. TreeMap:红黑树(自平衡的排序二叉树)

7.2 ArrayList、LinkedList、Vector的区别和实现原理

ArrayList ArrayList Vector
存储结构 基于数组实现的 基于双向链表实现 基于数组实现的
线程安全性 不具有有线程安全性,多线程环境下需使用synchronizedList 不具有有线程安全性,多线程环境下需使用synchronizedList Vector实现线程安全的,即它大部分的方法都包含关键字synchronized,但是Vector的效率没2有ArraykList和LinkedList高。:
扩容机制 Object的数组形式来存储的,元素不够时,扩容至原来的1.5倍 Object的数组形式来存储的,元素不够时,扩容至原来的2倍

7.3 HashMap与Hashtable的区别

  1. HaspMap是非线程安全的,HashTable是线程安全的;HashTable内部的方法基本都经过synchronized修饰。
  2. 因为线程安全问题,HashMap要比HashTable效率高一点,HashTable基本被淘汰。
  3. HashMap允许有空值存在,而在HashTable中put进的健值只要有一个为空,直接抛出NullPointerException。
    所以在单线程开发中,因为速度问题,一般推荐用HashMap,而需要完全线程安全时,使用HashTable。不过Java5以上的话,推荐用ConcurrentHashMap,HashTable已经是马上要淘汰的遗留类。

7.4 HashMap的源码解析

Hash函数源码解析:源码解析
HashMap源码解读:源码解析
LinkedHashMap 源码解读:源码解析

发布了16 篇原创文章 · 获赞 22 · 访问量 3783

猜你喜欢

转载自blog.csdn.net/qq_36008321/article/details/104552313