java面试题

目录

一 Java 基础
    1.Java 基础 知识
        1.1 面向对象的特征(了解)
        1.2 Java 的基本数据类型有哪些(了解)
        1.3JDK JRE JVM 的区别 (必会)
        1.4 重载和重写的区别(必会)
        1.5 Java 中==和 equals 的区别(必会)
        1.6 String、StringBuffer、StringBuilder 三者之间的区别(必会)
        1.7 接口和抽象类的区别是什么?(必会)
        1.8 string 常用的方法有哪些?(了解)
        1.9 什么是单例模式?有几种?(必会)
        1.10 反射(了解)
        1.11 jdk1.8 的新特性(高薪常问)
        1.12 Java 的异常(必会)
        1.13 BIO、NIO、AIO 有什么区别?(高薪常问)
        1.14 Threadloal 的原理(高薪常问)
        1.15 同步锁、死锁、乐观锁、悲观锁 (高薪常问)
        1.16 说一下 synchronized 底层实现原理?(高薪常问)
        1.17 synchronized 和 volatile 的区别是什么?(高薪常问)
        1.18synchronized 和 Lock 有什么区别? (高薪常问)
        1.19 手写冒泡排序?(必会)
    2.集合(必会)
        2.1 常见的数据结构(了解)
        2.2 集合和数组的区别(了解)
        2.3List 和 Map、Set 的区别(必会)
        2.4 List 和 Map、Set 的实现类(必会)
        2.5Hashmap 的底层原理(高薪常问)
        2.6 Hashmap 和 hashtable ConcurrentHashMap 区别(高薪常问)
     3.多线程(必会)
        3.1 什么是线程?线程和进程的区别?(了解)
        3.2 创建线程有几种方式(必会)
        3.3Runnable 和 Callable 的区别?(必会)
        3.4 如何启动一个新线程、调用 start 和 run 方法的区别?(必会)
        3.5 线程有哪几种状态以及各种状态之间的转换?(必会)
        3.6 线程相关的基本方法?(必会)
        3.7 wait()和 sleep()的区别?(必会)
    4. 线程池
        4.1 为什么需要线程池(了解)
        4.2 线程池的分类(高薪常问)
        4.3 核心参数(高薪常问)
        4.4 线程池的原理(高薪常问)
        4.5 拒绝策略(了解)
        4.6 线程池的关闭(了解)
    5. Jvm
        5.1 JDK1.8 JVM 运行时内存(高薪)
        5.2 JDK1.8 堆内存结构(高薪常问)
        5.3 Gc 垃圾回收(高薪常问)
        5.4 JVM 调优参数(了解)
二、 Web
    1.网络通讯部分
    2.cookie 和 session 的区别?(必会)
    3.Jsp 和 Servlet(了解)
    4.Ajax 的介绍(必会)
三、 数据库
    1.连接查询(必会)
    2.聚合函数(必会)
    3.SQL 关键字(必会)
    4. SQL Select 语句完整的执行顺序: (必会)
    5. 数据库三范式(必会)
    6. 存储引擎 (高薪常问)
        6.1.MyISAM 存储引擎
        6.22.InnoDB 存储引擎
    7.数据库事务(必会)
    8.索引
    9.数据库锁(高薪常问)
        9.1.行锁和表锁
        9.2.悲观锁和乐观锁
    10.MySql 优化(高薪常问)
        1) 定位执行效率慢的 sql 语句.(了解)
        2) 优化索引(高薪)
        3) Sql 语句调优(高薪)
        4) 合理的数据库设计(了解)
四. 框架
    1. Mybatis 框架
    2. Spring 框架
    3.SpringMVC 框架
    3. Dubbo
    4. Zookeeper
    6.SpringBoot
    7. SpringCloud
五.技术点
    1. Redis
    2. RocketMQ
    3. MongoDb
    4. Nginx
    5. FastDFS
    6. JWT
    7. Kafka


一、Java基础


1.Java基础知识

            
1.1面向对象的特征(了解)
        面向对象的特征:封装、继承、多态、抽象
        封装:就是把对象的属性和行为结合为一个独立的整体,并尽可能的隐藏对象的内部实现细节,就是把不想告诉别人或者不该告诉别人的进行隐藏,把可以告诉别人的进行公开,别人只能用我提供的功能实现需求,而不知道是如何实现的,主要是增加了安全性。
        继承:子类继承父类的数据属性和方法,并且能根据自身需求扩展出新的行为,继承主要是提高了代码的复用性。
        多态:指允许不同的对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用的多种不同的行为方式(发送消息就是函数调用)。封装和继承几乎都是为多态而准备的,在执行期间判断引用对象引用对象的引用类型,根据其实际的类型调用其相应的方法。
        抽象:表示对问题领域进行分析、设计中得出的抽象的概念,是对一系列看上去不同,但是本质上相同的具体概念的抽象,在Java中抽象用avstract关键字来修饰,用abstract修饰类时,此类就不能被实例化,从这里可以看出,抽象类(接口)就是为了继承而存在的。
1.2Java的基本数据类型有哪些(了解)
整数型 bayte short int long  float double boolear char
字节数     1        2     4    8        4      8          1         2
java面试题_第1张图片

1.3.JDK  JRE JVM  的区别(必会)
java面试题_第2张图片
        JDK(Java Development kit)是整个java的核心,是java开发工具包,包括了java运行环境 JRE,Java工具和 Java基础类库
        JRE (Java Runtime Environment)是运行Java程序所必须的环境的集合,包含Java虚拟机和java程序的一些核心类库。
        JVM 是Java VirtualMachine(Java虚拟机)的缩写,是整个java实现跨平台最核心的部分,能够运行以Java语言写作的软件程序
1.4重载和重写的区别(必会)
        重载:发生在同一个类中,方法名必须相同。参数类型不同,个数不同,顺序不同,访问修饰符和方法返回值可以不同,发生在编译时。
        重写:发生在父子类中,方法名,参数列表必须相同,返回值范围小于父类,输出异常范围小于父类,访问修饰符大于等于父类,访问修饰符范围大于父类;需要注意的是:如果父类方法访问修饰符为private,则子类就不能重写该方法
1.5java中==和equals的区别(必会)
        ==的作用                                     
基本类型:比较的是值是否相同
引用类型:比较的就是地址值是否相同
        equals的作用
只能比较引用数据类型,默认是比较的地址值,
重写后,比较的就是内容而不是地址!
           
    面试题:请解释字符串比较之中 “==” 和 equals()的区别?
 答:== 比较的是两个字符串的堆内存地址值是否相等,属于数值比较;
        equals():比较的是两个字符串的内容,属于内容比较
   注:因为String是引用类型所以==比较的是地址值
           因为String重写过并且继承自Object中的equals(),所以比较的是字符串中的内容。
1.6 String、StringBuffer、StringBuilder三者之间的区别(必会)
        String                  字符串常量
        StringBuffer        字符串变量(线程安全)
        StringBuilder      字符串变量(非线程安全)
        
        String 中的String 类中使用 final 关键字修饰字符数组来保存字符串,
        private final char value[] , String 对象是不可变的,也就可以理解为常量,线程安全
        AbstractStringBuilder  是  StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串操作,如 expandCapacity、append、insert、indexOf 等公共方法.
        StringBuffer         对方法加了同步锁或者对调用的方法加了同步锁,所以是线程安全的
        StringBuilder       并没有对方法进行加同步锁,所以是非线程安全的.但是运行效率会高很多
1.7 抽象类和接口类的区别是什么?(必会)
        实现: 抽象类的子类使用 extends 来继承;接口必须使用 implements 来实现接口
        构造函数: 抽象类可以有构造方法;接口不能有构造方法
        main方法:抽象类可以有 main 方法,并且我们能够运行它;接口中是不能有 main 方法.
        实现数量: 类可以实现很多接口;但是只能继承一个抽象类.
        访问修饰符: 接口中的方法默认使用 public 修饰;抽象类中的方法可以是任意访问修饰符
        补充:
        a.抽象类继承于Object接口;接口不继承
        b.抽象类中可以有普通成员变量和常量;接口中只能有常量,而且只能是public static final 不写也是默认的
        c. 抽象类中可以有抽象方法也可以有普通方法;接口中只能有抽象方法而且修饰符只能是public abstract 不写也是默认的
        d. 抽象类中是可以有final方法的;接口中不能有final的方法
        e. 抽象类只能是单继承多实现;接口是可以多继承其他接口,但是不能实现接口,和不能继承其他类
        f: 抽象类中可以有静态的方法,接口中不能有
1.8 String 常用的方法有哪些?(了解)
        indexOf():返回指定字符的索引
        charAt(): 返回指定索引处的字符
        replace(): 字符串替换
        trim(): 去除字符串两端空白.
        split(): 分割字符串,返回一个分割后的字符串数组.
        getBytes(): 返回字符串的 byte 类型数组
        lenth(): 返回字符串长度.
        toLowerCase(): 将字符串转成小写字母.
        toUpperCase(): 将字符串转成大写字母
        substring(): 截取字符串
        equals(): 字符串比较  
1.9 什么是单例模式?有几种?(必会)
        单例模式:某个类的实例在多线程环境下只会被创建一次出来.
        单例模式有饿汉式单例模式、懒汉式单例模式和双检锁单例模式
        饿汉式:线程安全,一开始就初始化
        
package com.jt;

public class Singleton1 {
    public static void main(String[] args) {
        //5.在main()方法中,不通过对象,直接调用类名,调用静态方法
        MySingle single1 = MySingle.getSingle();
        MySingle single2 = MySingle.getSingle();
        //6.用==检验是否是同一个对象
        System.out.println(single1);
        System.out.println(single2);
        System.out.println(single1 == single2);

    }
}
//1.创建自己的单例程序
class MySingle{
    //2.提供构造方法,并将构造方法私有化
    /*2.1构造方法私有化的目的:为了防止外界随意创建本类对象*/
    private MySingle(){}

    //3.创建本类对象,并将对象也私有化
    //3.2由于静态资源只能调用静态资源,所以single对象也需要设置成为静态
    private static  MySingle single = new MySingle();

    //4.提供公共的访问方式,访问创建好的对象
    //4.1为了不通过对象,直接调用本方法,需要将本方法设置为静态
    public  static  MySingle getSingle(){
        return  single;
    }

}

懒汉式:非线程安全,延迟初始化(可以使用synchronized添加同步锁)

package com.jt;
/*
本类用于实现单例设计模式优化实现方案2:懒汉式
关于单例设计模式的两种实现方式:
1.饿汉式:不管你用不用这个类的对象,都会直接先创建一个
2.懒汉式:先不给创建这个类的对象,等你需要的时候再创建--延迟加载的思想
延迟加载的思想:是指不会在第一设计就把对象创建好占用内存
             而是什么时候用到,什么时候再去创建对象
3.线程安全问题:由于我们存在唯一的对象Single2,并且多条语句都操作了这个变量
    如果将程序放在多线程的环境下,就容易出现数据安全的问题,所以解决方案:
    1)将3条语句都使用同步代码块包裹,保证同步排队的效果(利用代码从上往下执行的特性)
    2)由于getSingle2()只要这3条语句,所以也可以将本方法设置为同步方法
 */

public class Singleton2 {
    public static void main(String[] args) {
        //6.调用方法进行查看
        MySingle2 single1 = MySingle2.getMySingle2();
        MySingle2 single2 = MySingle2.getMySingle2();
        System.out.println(single1);
        System.out.println(single2);
        System.out.println(single1 == single2);
    }

}
//1.创建单例程序
class MySingle2{
    //6.2创建一个静态的唯一的锁对象
    static Object o = new Object();
    //2.私有化本类的构造方法
    private MySingle2(){}
    //3.创建的是本类对象的引用类型变量,用来保存对象的地址值,默认为null
    private static MySingle2 Single2;
    //4.提供公共的get方法
    public static MySingle2 getMySingle2() {
        //5.进行if判断,判断之前是否创建过对象,之前创建过就直接进行return返回
        //如果之前没有创建过,才走if,创建对象并将对象进行返回
        //6.有数据共享+多条语句操作数据,所以尽量提前处理,避免多线程数据安全隐患
        //6.1解决方案1:加同步代码块
        //6.2解决方案2:将本方法getSingle2()设置为同步方法
        //因为这个方法里的所有语句都需要同步
        synchronized (o) {
            if (Single2 == null) {//Single2 还是默认值null,说明之前没有创建过对象
                Single2 = new MySingle2();//没创建过才创建,并赋值给Single2
            }
            return Single2;
        }
    }

}

 双检锁模式:线程安全,延迟初始化(可以使用synchronized添加同步锁)

package com.jt;
//双重锁模式:安全且在多线程情况下能保持高性能。
public class Singleton3 {
    public static void main(String[] args) {
        //6.调用方法进行查看
        MySingle2 single1 = MySingle2.getMySingle2();
        MySingle2 single2 = MySingle2.getMySingle2();
        System.out.println(single1);
        System.out.println(single2);
        System.out.println(single1 == single2);
    }

}

//1.创建单例程序
class MySingle3{
    //6.2创建一个静态的唯一的锁对象
    static Object o = new Object();
    //2.私有化本类的构造方法
    private MySingle3(){}
    //3.创建的是本类对象的引用类型变量,用来保存对象的地址值,默认为null
    //实例变量需要加volatile 关键字保证易变可见性
    private volatile static MySingle3 Single3;
    //4.提供公共的get方法
    public static MySingle3 getMySingle2() {
        //5.进行if判断,判断之前是否创建过对象,之前创建过就直接进行return返回
        //如果之前没有创建过,才走if,创建对象并将对象进行返回
        //6.有数据共享+多条语句操作数据,所以尽量提前处理,避免多线程数据安全隐患
        //6.1解决方案1:加同步代码块
        //6.2解决方案2:将本方法getSingle2()设置为同步方法
        //因为这个方法里的所有语句都需要同步
        synchronized (o) {
            if (Single3 == null) {//Single2 还是默认值null,说明之前没有创建过对象
                Single3 = new MySingle3();//没创建过才创建,并赋值给Single2
            }
            return Single3;
        }
    }

}

补充知识点:

volatile关键字特点
1.修饰属性
2.禁止指令重排序(JVM底层执行指令时,可能考虑到一定优化,会对指令进行重排序)
3.保证线程可见性(一个线程修改了这个值,其他线程立即可见)
4.不能保证其原子性(不保证线程安全)

1.10反射(了解)

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

        获取 Class 对象的3种方法:

        ①调用某个对象的geClass()方法

        Person p = new Person();

        ClassClazz = p.getClass();

        ②调用某个类的 class 属性来获取该类对应的 Class 对象

        Class clazz = Person.class;

        ③使用 Class 类中的 forName()静态方法(最安全/性能最好)

        Class clazz = Class.forName("类的全路径");(最常用)

1.11 jdk1.8 的新特性 (高薪常问)

 Lambda 表达式
        Lambda 允许把函数作为一个方法的参数。
        
new Thread(()->System.out.println("abc")).start();

 ② 方法引用

        方法引用允许直接引用已有 Java 类或对象的方法或构造方法。
        
ArrayList list = new ArrayList<>();
    list.add("a");
    list.add("b");
    list.add("c");
    list.forEach(System.out::println);
    

        上例中我们将 System.out::println 方法作为静态方法来引用。
 ③  函数式接口
        有且仅有一个抽象方法的接口叫做函数式接口,函数式接口可以被隐式转换为Lambda 表达式。通常函数式接口上会添加@FunctionalInterface 注解。
 ④  接口允许定义默认方法和静态方法
        从 JDK8 开始,允许接口中存在一个或多个默认非抽象方法和静态方法。
 ⑤  Stream API
        新添加的 Stream API(java.util.stream)把真正的函数式编程风格引入到 Java 中。这种风格将要处理的元素集合看作一种流,流在管道中传输,并且可以在管道的节点上进行处理,比如筛选, 排序,聚合等。
package com.jt;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Demo {
    public static void main(String[] args) {
        List list = Arrays.asList("abc","","abc","bc","efg","abcd","def","jkl");
        list.stream()//获取集合的流对象
                .filter(string -> !string.isEmpty())//对数据进行过滤,过滤掉空字符串
                .distinct()//去重
                .forEach(a -> System.out.println(a));
    }
}

 ⑥ 日期/时间类改进

        之前的 JDK 自带的日期处理类非常不方便,我们处理的时候经常是使用的第三方
工具包,比如 commons-lang 包等。不过 JDK8 出现之后这个改观了很多,比如日期时间的创建、比较、调整、 格式化、时间间隔等。
        这些类都在 java.time 包下,LocalDate/LocalTime/LocalDateTime。
 ⑦ Optional 类
        Optional 类是一个可以为 null 的容器对象。如果值存在则 isPresent()方法会返 回 true,调用 get()方法会返回该对象。
package com.jt;

import java.sql.SQLOutput;
import java.util.Optional;

public class Demo2 {
    public static void main(String[] args) {


    String string = "abc";
    Optional optional = Optional.of(string);
    boolean present = optional.isPresent();
    String value = optional.get();
        System.out.println(present+"/"+value);
    }
}

⑧ Java8 Base64 实现

        Java 8 内置了 Base64 编码的编码器和解码器
1.12 Java的异常(必会)
java面试题_第3张图片
        Throwable 是所有Java程序中错误处理的父类,有两种子类:Error和Exception.

         Error:表示由 JVM 所侦测的无法预期的错误,由于这是属于JVM层次的严重错误,导致JVM无法继续执行,因此,这是不可捕捉到的,无法采取任何恢复的操作,顶多只能显示错误信息.

        Exception:表示可恢复的错误,这是可以捕捉到的..

        1.运行时异常:都是RuntimeException 类及其子类异常,如 NullPointerException(空指针异常)、InderxOutOfBoundsException(下标越界异常)等,这些异常都是不检查异常,程序中可以选择捕获处理,也可以不处理,这些异常一般是由程序逻辑错误引起的,程序一个从逻辑角度尽可能避免这类异常的发生.运行时异常的特点是Java编译器不会检查它,也就是说,当程序中可能出现这类异常,即使技术没有用try-catch 语句捕获,也没有用 throws 子句声明抛出它,也会编译通过.

        2.非异常时运行(编译异常): 是 RuntimeException 以外的异常,类型上都属于 Exception 类及其子类.从程序语法角度讲是必须进行处理的异常,如果不处理,程序就不能编译通过.如 IOException、SQLException 等以及用户自定义的 Exception 异常,一般情况下不自定义检查异常.

        常见的 RunTime 异常几种如下:

        NullPointerException - 空指针引用异常

        ClassCastException - 类型强制转换异常

        IllegalArgumentException - 传递非法参数异常

        ArithmeticException - 算术运算异常

        ArrayStoreException - 向数组中存放与声明类型不兼容对象异常

        IndexOutOfBoundsException - 下标越界异常

        NegativeArraySizeException - 创建一个大小为负数的数组错误异常

        NumberFormatException - 数字格式异常

        SecurityException - 安全异常

        UnsupportedOperationException - 不支持的操作异常

1.13 BIO、 NIO、 AIO 有什么区别?(高薪常问)

        BIO: Block IO 同步阻塞式 IO ,就是我们平常使用的传统 IO ,他的特点是模式简单使用方便,并发处理能力低.

        NIO:New IO 同步非阻塞 IO ,是传统 IO 的升级,客户端和服务端通过 Channel(通道) 通讯,实现了多路复用.

        AIO: Asynchronous IO 是 NIO 的升级,也叫 NIO2,实现了异步非堵塞 IO , 异步 IO 的操作基于事件和回调机制.

1.14 Threadloal的原理(高薪常问)

        ThreadLocal:为共享变量在每个线程中创建一个副本,每个线程都可以访问自己内部的副本变量.通过threadlocal保证线程的安全性.
        其实在ThreadLocal类中有一个静态内部类ThreadLocalMap(其类似于Map),用键值对的形式存储每一个线程的变量副本,ThreadLocalMap中元素的key为当前ThreadLocal对象,而value则是对应线程的变量副本.也就是说(ThreadLocal对象,对应线程的变量副本)
        ThreadLocal本身并不存储值,它只是作为一个key保存到ThreadLocalMap中,但是这里要注意的是它作为一个Key用的是弱引用,因为没有强引用链,弱引用在垃圾回收机制GC的时候可能会被回收,这样就会在ThreadLocalMap中存在一些Key为null的键值对(Entry),因为key变成null了,我们是没法访问这些键值对(Entry)的,但是这些Entry本身是不会被清除的.如果没有手动删除对应key就会到账这块内存既不会回收也无法访问,也就是发生了内存泄漏.
        使用完ThreadLocal之后,记得调用remove方法,在不使用线程池的前提下,即使不调用remove方法,线程的"变量副本"也会被gc回收,即不会造成内存泄漏的情况.

1.15 同步锁、死锁、乐观锁、悲观锁(高薪常问)

        同步锁
        当多个线程同时访问同一个数据时,很容易出现问题,为了避免这种情况出现,我们要保证线程同步互斥,就是指并发执行的多个线程,在同一数据只允许一个线程访问共享数据,Java中可以使用synchronized关键字来取得一个对象的同步锁
        死锁
        何为死锁,就是多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放.在开发过程中,尽量避免死锁的产生.
        乐观锁
        总是假设最好的情况,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候回判断一下在此期间别人有没有去更新这个数据,可以使用版本号机制和CAS算法实现.乐观锁使用与多度的应用类型,这样可以提高吞吐量,想数据库提供的类似于write_conditio机制,其实都是提供的乐观锁.在Java中Java.util.concurrent.atomic包下面的原子变量类就是使用了乐观锁的一直实现方式CAS实现的
        悲观锁
        总是假装在最坏的情况,每次去拿数据的时候都认为别人会修改,所以,每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线程使用,其他线程阻塞,用完后再把资源转让给其他线程).传统的关系型数据库里面就用到了很多这种锁机制,比如:行锁、表锁等,读锁、写锁等都是在做操作之前先上锁.Java中synchronized和ReentrantLock等独占锁就是悲观锁思想的实现.

1.16说一下synchronized底层实现原理(高薪常问)

        synchronized可以保证方法或者代码块在运行时,同一时刻只有一个方法可以进入到临界区,同时它还可以保证共享变量的内存可见性.
        Java中每一个对象都可以作为锁,这是synchronized实现同步的基础:
        普通同步方法,锁是当前实例对象
        静态同步方法,锁是当前类的class对象
        同步方法块,锁是括号里面的对象

1.17synchronized和volatile的区别是什么?(高薪常问)

        volatile本质是告诉 jvm 当前变量在寄存器(工作内存)中的值是不确定的,需要从主存中读取;synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住
        volatile仅能使用在变量级别;synchronized则可以使用在变量、方法和类级别的.
        volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性.
        volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞.
        volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化

1.18synchronized和lock有什么区别?(高薪常问)

        首先synchronized是java内置关键字,在jvm层面,lock是一个java类
        synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁
        synchronized会自动释放锁(a线程执行完同步代码会释放锁;b线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁
        用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2等待,如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了
        synchronized的锁可重入、不可中断、非公平、而Lock锁可重入、可判断、可公平(两者皆可)
        Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题

1.19手写冒泡排序?(必会)

package com.jt;


import java.util.Scanner;

public class Demo3 {
    public static void main(String[] args) {
        sort();
    }
    public static void sort(){
        //使用scanner获取控制台输入的字符
        Scanner input = new Scanner(System.in);
        //创建一个长度为10的数组sort
        long sort[] = new long[10];
        //创建一个int类型的temp变量
        long temp;
        System.out.println("请输入10个排序的数据");
        for (int i =0;i< sort.length;i++){
            sort[i]=input.nextLong();
        }
        for (int i = 0;i

2.集合(必会)

2.1 常用的数据结构(了解)

        常用的数据结构有:数组,栈,队列,链表,树,散列,对,图等
        java面试题_第4张图片
        数组是最常用的数据结构,数组的特点是长度固定的,数组的大小固定后就无法扩容了,数组只能存储一种类型的数据,添加,删除的操作慢,因为要移动其他的元素.
        是一种基于先进后出(FILO)的数据结构,是一种只能在一端进行插入和删除操作的特殊线性表,它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来).
        队列是一种基于先进先出(FIFO)的数据结构,是一种智能在一段进行插入,在另一端进行删除操作的特殊线性表,它按照先进先出的原则存储数据,先进入的数据,在读取数据时先被读取出来.
        链表是一种物理存储单元上非连续、非顺序的存储结构,其物理结构不能只表示数据的逻辑顺序,数据元素的逻辑顺手是通过链表的指针链接次序实现的.链表由一系列的结节(链表中的每一个元素称为节点)组成,节点可以在运行时动态生成.根据指针的指向,链表能形成不同的结果,例如:单链表,双向链表,循环链表等.
       是我们计算机中非常重要的一种数据结构,同时使用树这种数据结构,可以描述现实生活中的很多事物,例如家谱、单位的组织架构等等.有二叉树、平衡树、红黑树、B数、B+数.
        散列表,也叫哈希表,是根据关键码和值(key和value)直接进行访问的数据结构,通过key和value来映射到集合中的一个位置,这样就可以很快找到集合中的对应元素.
        堆是计算机学科中一类特殊的数据结构的统称,堆通常可以被看做是一颗完全二叉树的数组对象.
        图的定义:图是由一组顶点和一组能够将两个顶点相连的边组成的

2.2集合和数组的区别(了解)

        区别:数组长度固定   集合长度可变
        数组中存储的是同一种数据类型的元素,可以存储基本数据类型,也可也存储引用数据类型;集合存储的都是对象,而且对象的数据类型可以不一致.在开发当中一般当对象较多的时候,使用集合来存储对象.

2.3List和Map、Set的区别(必会)

        List和set是存储单列数据的集合,map是存储键值对这样的双列数据的集合;
        List中存储的数据是有顺序的,并且值是允许重复的;
        Map中存储的数据是无序的,它的键是不允许重复的,但是值是允许重复的;
        Set中存储的数据是无顺序的,并且不允许重复,但元素在集合中的位置是由元素的hashcode决定的,即位置是固定的(Set集合是根据hashcode来进行数据存储的,所以位置是固定的,但是这个位置不是用户可以控制的,所以对于用户来说set中的元素还是无序的).

2.4List和Map、Set的实现类(必会)
        java面试题_第5张图片

        Connection接口:
List 有序,可重复
        ArrayList
        优点:底层数据结构是数组,查询快,增删慢,(因为增删会改变数据结构,所以对比起来会慢一些)
        缺点:线程不安全,效率高
        Vector
        优点:底层数据结构是数组,查询快,增删慢.
        缺点:线程安全,效率低,已给舍弃
        LinkedList
        优点:底层数据结构是链表,查询慢,增删快
        缺点:线程不安全,效率高
Set 无序,唯一
        Hashset
        底层数据结构是哈希表.(无序,唯一)
        如何来保证元素唯一性?
        依赖两个方法:hashCode()和equals()
        LinkedHashSet
        底层数据结构是链表和哈希表.(FIFO插入有序,唯一)
        1.由链表保证数据有序
        2.由哈希表保证元素唯一
        TreeSet
        底层数据结构是红黑树.(唯一,有序)
        1.如何保证元素排序的呢?
        自然排序
        比较器排序
        2.如何保证元素唯一性的呢?
        根据比较的返回值是否是0来决定
Map接口有四个实现类:
        HashMap
        基于hash表的Map接口实现,非线程安全,搞笑,支持null值和null键,线程不安全
        HashTable
        线程安全,低效,不支持null值和null键;
        LinkedHashMap
        线程不安全,是HashMap的一个子类,保存了记录的插入顺序;
        TreeMap
        能够把它保存的记录根据键排序,默认是键值的升序排序,线程不安全

2.5Hashmap的底层原来(高薪常问)

        HashMap在jdk1.8之前实现方式是数组+链表.
        但是在jdk1.8后对HashMap进行了底层的优化,改为了由数组+链表或者数值+红黑树实现,主要目的是提高查询效率
        
        java面试题_第6张图片

         1.jdk8数组+链表或者数组+红黑树实现,当链表中的元素超过8个以后,会将链表转换为红黑树,当红黑树节点小树6时又会退化为链表.
        2.当 new HashMap():底层没有创建数组,首次调用put()方法时.底层创建为16的数组,jdk8底层的数组是:Node[],而非Entry[],用数组

你可能感兴趣的:(面试,面试,java)