云计算百科
云计算领域专业知识百科平台

java面试题

JAVA 复习题

简单题

1. 计算机网络传输层有哪些协议?分别适用于什么场景?

传输层核心协议:TCP、UDP

  • TCP:面向连接、可靠传输。适用:文件传输、网页访问、数据库连接(需要数据不丢失、顺序正确)。
  • UDP:无连接、不可靠,开销小。适用:直播、视频通话、DNS查询、游戏(允许少量丢包,优先速度)。

2. 多线程的使用场景有哪些?线程开启多少个合适?判断标准有哪些?

场景:IO密集型(文件读写、网络请求)、后台异步任务、并行计算。

线程数量:

  • CPU密集型:核心数+1;
  • IO密集型:2*CPU核心数。 判断标准:看CPU利用率、IO等待时间,减少线程上下文切换,避免过多线程抢占资源。

3. 线程池的提交方式有哪几种?

  • execute(Runnable):无返回值,抛出异常直接向外抛出
  • submit(Runnable):返回Future对象,可以捕获异常
  • submit(Runnable, T result)
  • submit(Callable):带返回结果,通过Future获取返回值
  • 4. 锁的实现原理介绍一下?

    以synchronized为例:对象头包含Mark Word,存放锁标记。 无锁→偏向锁→轻量级锁(CAS自旋)→重量级锁(OS互斥锁)。 底层:CAS + 对象头MarkWord + 操作系统互斥原语。通过竞争锁,保证同一时间只有一个线程执行临界区代码,保证原子性。

    5. TCP协议中拥塞控制的主要作用是什么?

    防止发送方发送数据太快,造成网络拥堵、报文大量丢失。动态调整拥塞窗口大小,控制发送速率,避免网络过载。四个阶段:慢启动、拥塞避免、快重传、快恢复。

    6. String类的常用函数有哪些?列举十种。

    length()、charAt()、substring()、indexOf()、lastIndexOf()、equals()、equalsIgnoreCase()、trim()、split()、replace()、toUpperCase()、toLowerCase()

    7. String和StringBuffer,StringBuilder的区别有哪些?所有类名包含Buffer的类的内部实现原理是什么?有什么优势?

     

  • 第一点: 可变和适用范围。String对象是不可变的,而StringBuffer和StringBuilder是可变字符序列。每次对String的操作相当于生成一个新的String对象,而对StringBuffer和StringBuilder的操作是对对象本身的操作,而不会生成新的对象,所以对于频繁改变内容的字符串避免使用String,因为频繁的生成对象将会对系统性能产生影响。
  • 第二点: 线程安全。String由于有final修饰,是immutable的,安全性是简单而纯粹的。StringBuilder和StringBuffer的区别在于StringBuilder不保证同步,也就是说如果需要线程安全需要使用StringBuffer,不需要同步的StringBuilder效率更高。
  • 总结:
    • 操作少量的数据 = String
    • 单线程操作字符串缓冲区下操作大量数据 = StringBuilder
    • 多线程操作字符串缓冲区下操作大量数据 = StringBuffer
    • Buffer类底层:可变字符数组,预分配容量,扩容时新建数组复制内容。优势:字符串拼接不会频繁创建新对象,减少GC压力。

    8. String字符串的不可变是指哪里不可变?

    底层存储字符的value数组被final修饰,数组引用不能指向新数组;数组内元素一旦初始化,不能修改。String引用变量可以重新赋值,不是变量不可变。

    9. HTTP协议有哪些字段,列举3个就可以。

    请求头:Host、User-Agent、Content-Type、Cookie、Accept。

    10. Java异常类有哪些?分别管理什么异常?

    Throwable分两大分支:

  • Error:系统级严重错误,OutOfMemoryError、StackOverflowError,程序无法处理。
  • Exception:程序可处理异常
    • 受检异常(编译期):IOException、SQLException
    • 非受检异常(运行时RuntimeException):NullPointerException、ArrayIndexOutOfBounds
  • 11. Java反射获取类信息的方式有哪几种?分别是什么?

  • 类名.class 如User.class
  • 对象.getClass() 如userObj.getClass()
  • Class.forName("全类名") 最常用,可动态加载类
  • 12. Java代理的主要方法有哪几种?列举代理的使用场景2个。

    静态代理、JDK动态代理、CGLIB动态代理。

    场景:AOP切面、事务控制、日志记录。

    13. equals()方法的作用是什么?重写equals需要注意哪些事项?为什么?

  • ==(补充)
    • 基本数据类型:比较数值(值)
    • 引用数据类型:永远比较对象内存地址
  • equals()
    • Object 原生未重写:底层就是return this == obj,比较内存地址。
    • String、Integer 等包装类:重写 equals 方法,比较对象内容(值)。

    重写要求:

  • 自反性、对称性、传递性、一致性;
  • 重写equals必须重写hashCode。 原因:如果两个对象equals相等,hashCode必须相等,否则HashMap等集合会出错。
  • 14. Java是按值传递还是按引用传递?什么是引用传递,什么是值传递,哪些语言支持引用传递?

    Java只有值传递。 值传递:传递的是副本,方法内修改副本不影响原变量。

    引用传递:传递变量本身的地址,方法内修改会直接修改原始变量。

    C++、C#支持引用传递。

    Java传递引用类型时,传递的是引用地址副本,仍然属于值传递。

    15. 描述java的类初始化顺序?如果存在继承,初始化顺序会如何

    无继承:静态变量/静态代码块 → 成员变量/构造代码块 → 构造方法。

    有继承:父类静态 → 子类静态 → 父类成员、构造块 → 父类构造 → 子类成员、构造块 → 子类构造。

    静态只加载一次。

    16. 本地方法栈有什么作用?

    为native本地方法(C/C++写的方法)服务,存放native方法的局部变量、返回地址。JVM调用操作系统底层方法时使用。

    17. 描述Java的双亲委派机制,为什么要用到双亲委派机制

    Java双亲委派机制是指在类加载过程中,类加载器会按照一定的顺序委派给父类加载器来尝试加载类。这个机制可以确保类的加载安全和防止类的重复加载。下面是一个简要解答核心知识的表格:

    通过Java双亲委派机制,可以实现类加载的安全性和避免重复加载,同时也允许开发者自定义ClassLoader来实现特定需求的类加载行为。

    18. 重写和重载的区别是什么?

  • 重载就是同一个类中,有多个方法名相同,但参数列表不同(包括参数个数和参数类型),与返回值无关,与权限修饰符也无关。调用重载的方法时通过传递给它们不同的参数个数和参数类型来决定具体使用哪个方法,这叫多态。
  • 重写就是子类重写基类的方法,方法名,参数列表和返回值都必须相同,否则就不是重写而是重载。权限修饰符不能小于被重写方法的修饰符。重写方法不能抛出新的异常或者是比被重写方法声明更加宽泛的检查型异常。
  • 19. 子类构造方法调用父类构造方法的注意事项有哪些?

  • super()必须放在子类构造方法第一行;
  • 如果父类无无参构造,子类必须显式调用父类有参super;
  • super和this不能同时出现在同一个构造器。
  • 20. 子类实例初始化是否触发发父类实例初始化?

    会。 创建子类对象,一定会先初始化父类实例。

    21. instanceof关键字的作用是什么?

    判断对象是不是某个类(或子类)的实例。obj instanceof User,返回布尔值。

    22. 基本类型的强制类型转换是否会丢失精度?引用类型的强制类型转换需要注意什么?

    基本类型:大范围转小范围,会丢失精度(double→int,long→short)。

    引用类型强制转换:只能向上转型(自动);向下强转必须保证对象实际类型是目标类/子类,否则抛出ClassCastException。建议配合instanceof判断。

    23. 重入锁有哪些?为什么要有重入锁?

    synchronized、ReentrantLock。

    作用:同一个线程拿到锁之后,再次进入同步代码块,可以再次获取锁,不会自己死锁。

    24. 指令重排序的优点是什么?由什么原因导致的?

    优点:CPU优化,调整指令执行顺序,充分利用CPU流水线,提升执行性能。

    原因:JVM编译器、CPU处理器为了性能做的优化。 volatile可以禁止指令重排。

    25. Arrays.sort()的内部原理介绍一下?

    JDK8:

    • 基本类型:双轴快速排序(DualPivotQuicksort)
    • 引用类型:TimSort(归并+插入排序),稳定排序。

    26. 堆排序的时间复杂度是多少,空间复杂度是多少?

    时间复杂度:O(nlogn),最好最坏平均都是O(nlogn) 空间复杂度:O(1),原地排序。

    27. 字符串“asdasjkfkasgfgshaahsfaf”经过哈夫曼编码之后存储比特数是多少?

    字符统计:a:6,s:5,f:4,k:2,g:2,h:2,d:1,j:1

    哈夫曼树构建: 总比特= 61 + 52 +42 +23 +23 +23 +14 +14 = 46 bit。

    28. CPU高速缓存的优点和缺点有哪些?

    优点:速度极快,减少访问内存耗时,提升CPU吞吐。

    缺点:容量小;存在缓存一致性问题;多核心下缓存同步开销。

    29. 线程安全的类有哪些?列举2个以上就可以

    Vector、HashTable、StringBuffer、ConcurrentHashMap

    30. 什么是LRU算法?

    最近最少使用。缓存满时,淘汰最长时间没有被访问的数据。

    核心思想:保留热点数据,淘汰冷数据。

    31. TCP协议有哪些协议字段?如何保障可靠传输的?滑动窗口解决了什么问题?

    字段:序号、确认号、标志位、窗口大小。

    可靠传输:序列号+ACK确认、超时重传、校验和。

    滑动窗口:流量控制,接收方告诉发送方最多能接收多少数据,防止发送方发太快淹没接收缓冲区。

    32. 什么是三次握手,什么是四次挥手。

    三次握手:建立TCP连接。

  • 客户端SYN;2. 服务端SYN+ACK;3.客户端ACK。
  • 四次挥手:断开TCP连接。

    1.客户端FIN;2.服务端ACK;3.服务端FIN;4.客户端ACK。

    33. 什么是深拷贝?什么是浅拷贝?

    浅拷贝:拷贝对象,引用成员变量只复制地址,新旧对象共用子对象。

    深拷贝:拷贝整个对象,所有嵌套对象全部新建独立副本,修改互不影响。

    34. 访问器如何保障线程安全?举例说明。

    get/set访问方法加synchronized锁,保证同一时刻只有一个线程读写变量。

    private int num;

    public synchronized void setNum(int v){num=v;}

    public synchronized int getNum(){return num;}

    35. 抽象类和接口的不同点和相同点有哪些?

  • 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
  • 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final 类型的;
    • 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法;
  • 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
  • 36. final关键字能否防止指令重排序?能否代替volatile?

    final可以禁止构造对象内的指令重排,保证对象安全发布;但是不能代替volatile。volatile保证可见性+禁止读写重排,final不保证变量可见性。

    37. static修饰的模块什么时候开始初始化?

    类加载的初始化阶段。第一次主动使用类的时候触发(new、静态方法/静态变量访问、反射等)。

    38. 什么是对象锁,什么是类锁?

    对象锁:锁绑定实例对象,synchronized修饰普通方法、锁对象。多个实例互不干扰。

    类锁:锁绑定Class对象,synchronized静态方法、锁类.class。全局一把锁。

    39. 进程和线程的区别是什么?进程间的通信方式有哪些?线程间的通信方式有哪些?

    进程:资源分配最小单位,独立内存空间;

    线程:CPU调度最小单位,共享进程内存。

    进程通信:管道、socket、消息队列、共享内存、信号量。 线程通信:wait/notify、共享变量、Lock、CountDownLatch。

    40. 类锁和对象锁是否是互斥的?

    不互斥。类锁锁的是Class对象;对象锁锁实例对象。两个锁对象不一样,可以同时执行。

    41. 什么是注解,注解可以作用类的哪些部分?

    注解是元数据,给程序附加说明信息,不直接执行。

    可作用:类、接口、方法、成员变量、参数、局部变量。

    42. 内部类有哪几种?分别适用于那些场景?

    4种:成员内部类、静态内部类、局部内部类、匿名内部类。

    • 成员内部类:访问外部类成员;
    • 静态内部类:不需要外部实例,工具类;
    • 局部内部类:方法内临时使用;
    • 匿名内部类:快速实现接口/抽象类(回调、线程)。

    43. finally的作用,一般用于什么场景?

    finally代码块一定执行(除JVM退出),用于资源释放:关闭流、数据库连接。

    44. 什么是栈溢出?什么是堆溢出?什么是堆外内存?

    栈溢出StackOverflowError:方法调用深度过大,栈帧超过栈容量(递归太深)。

    堆溢出OOM:堆内存不足以创建新对象。

    堆外内存:不在JVM堆内,操作系统直接分配的内存,NIO的DirectBuffer。

    45. Java的集合类有哪些?

    Collection:List(ArrayList、LinkedList、Vector);Set(HashSet、TreeSet) Map:HashMap、TreeMap、HashTable、ConcurrentHashMap

    46. 什么是泛型,请写一个泛型队列或者泛型栈。

    泛型:参数化类型,编译期类型检查,避免类型强转。 泛型栈示例:

    class Stack<T>{

        private Object[] arr = new Object[10];

        private int index = 0;

        public void push(T t){arr[index++]=t;}

        public T pop(){return (T)arr[–index];}

    }

    47. 反射能否获取私有信息,如果能,需要注意什么?

    可以。setAccessible(true)开启访问权限。

    注意:会破坏封装;有安全管理器限制;性能略低。

    48. 线程的状态有哪些?

    NEW新建、RUNNABLE可运行、BLOCKED阻塞、WAITING等待、TIMED_WAITING计时等待、TERMINATED终止。

    49. 线程.start()是进入什么状态?

    调用start(),线程进入RUNNABLE(可运行),等待CPU调度,不是直接运行。

    50. 等待队列和阻塞队列的区别是什么?

    等待队列:synchronized的监视器等待集合,wait进入,notify唤醒。 阻塞队列(BlockingQueue):并发容器,take()/put()自带阻塞,生产者消费者模型,底层封装锁+等待队列。

    51. sleep()和wait()的区别是什么?

  • sleep是Thread静态方法;wait是Object方法。
  • sleep不释放锁;wait释放锁。
  • sleep时间到自动恢复;wait需要notify唤醒。
  • sleep不一定要在同步块;wait必须在synchronized内。
  • 52. sleep(1)什么作用,都用于哪些场景?

    作用:让出CPU,进入TIMED_WAITING,至少暂停1ms。 场景:简单限流、让出CPU给其他线程、简单轮询降频。

    53. 什么是中断机制?举一个中断响应的例子。

    中断是线程的标记,不是直接终止线程。interrupt()设置中断标记,线程检测标记自行停止。

    while(!Thread.currentThread().isInterrupted()){

        //业务

    }

    54. 守护线程是什么?什么是协程?

    守护线程:后台服务线程,用户线程全部结束,守护线程自动退出(GC线程)。

    协程:用户态轻量级线程,由程序调度,占用资源远小于线程。

    55. 形成死锁的条件是什么?如何避免死锁?

    4条件:互斥、持有并等待、不可剥夺、循环等待。

    避免:统一锁获取顺序、设置超时、破坏持有等待。

    56. 基本类型的数据存在jvm的哪个区域?

    局部变量里的基本类型:虚拟机栈;作为对象成员变量的基本类型,在堆。

    57. 多线程的使用场景有哪些?

    IO密集型任务:网络请求、文件读写;后台异步任务;并行计算;消息消费。

    58. Throw和Throws的区别?

    throws写在方法声明,声明本方法可能抛出异常;

    throw写在方法体内,手动抛出一个异常实例。

    59. Object类的方法有哪些?分别有什么作用?

  • equals():对象相等比较
  • hashCode():返回哈希码
  • getClass():获取运行时Class
  • wait():监视器等待
  • notify()/notifyAll():唤醒等待线程
  • clone():对象拷贝
  • finalize():垃圾回收前执行(废弃)
  • toString():对象字符串描述
  • 60. 总线锁的优缺点是什么?

    总线锁:CPU锁住总线,同一时刻只有一个CPU访问内存。

    优点:简单,保证原子性;

    缺点:锁整个总线,多核CPU并发性能差。后来优化为缓存锁(MESI)。


    代码题(每题10分)

    1. 写三个线程t1、t2、t3,t1输出A,t2输出B,t3输出C,循环输出 ABABC

    思路:用锁+状态标记,控制线程轮流执行,循环顺序 A → B → A → B → C

    public class ABCThread {

        static Object lock = new Object();

        //state:0输出A,1输出B,2输出A,3输出B,4输出C,循环

        static int state = 0;

        public static void main(String[] args) {

            Thread t1 = new Thread(()->{

                while(true){

                    synchronized (lock){

                        while(state !=0 && state !=2){

                            try {lock.wait();} catch (InterruptedException e) {}

                        }

                        System.out.print("A");

                        state++;

                        lock.notifyAll();

                    }

                }

            },"t1");

            Thread t2 = new Thread(()->{

                while(true){

                    synchronized (lock){

                        while(state !=1 && state !=3){

                            try {lock.wait();} catch (InterruptedException e) {}

                        }

                        System.out.print("B");

                        state++;

                        if(state==5) state=0;

                        lock.notifyAll();

                    }

                }

            },"t2");

            Thread t3 = new Thread(()->{

                while(true){

                    synchronized (lock){

                        while(state !=4){

                            try {lock.wait();} catch (InterruptedException e) {}

                        }

                        System.out.print("C");

                        state++;

                        if(state==5) state=0;

                        lock.notifyAll();

                    }

                }

            },"t3");

            t1.start();

            t2.start();

            t3.start();

        }

    }

    逻辑:state 0(A)→1(B)→2(A)→3(B)→4(C),state重置为0,循环ABABC。

    2. 默写懒汉式单例模式,以及代码解释

    public class Singleton {

        //私有静态变量,不初始化

        private static Singleton instance;

        //私有构造,禁止外部new

        private Singleton(){}

        //获取实例,第一次调用才创建

        public static Singleton getInstance(){

            if(instance == null){

                instance = new Singleton();

            }

            return instance;

        }

    }

    解释:懒汉式,延迟加载,调用getInstance才创建对象。缺点:多线程环境线程不安全,多线程同时进入if会创建多个实例。 【可选:线程安全版本】加synchronized:

    public static synchronized Singleton getInstance(){

        if(instance == null){

            instance = new Singleton();

        }

        return instance;

    }

    推理题(10分,不少于500字)

    1.Tomcat如何访问到Controller的,内部实现原理是什么?

    浏览器输入地址发起HTTP请求,请求经过网络到达Tomcat,整体流程分为:端口接收、解析请求、匹配Servlet、转发到SpringMVC的Controller。

    Tomcat底层是Socket通信,启动时在8080端口开启ServerSocket,持续监听客户端连接。浏览器发送HTTP请求报文,操作系统内核把TCP数据包交给Tomcat。Tomcat的Connector组件负责接收Socket连接,读取HTTP报文,解析请求行、请求头,封装成HttpServletRequest对象;同时准备HttpServletResponse对象,用来回写响应数据。

    Connector解析完成后,把请求交给Container容器。Container包含Engine、Host、Context、Wrapper四层容器。Engine代表整个引擎,Host对应虚拟主机,Context对应一个web项目,Wrapper封装Servlet。Tomcat根据请求url,匹配对应的Context项目。

    SpringMVC项目中,web.xml自动注册DispatcherServlet,它是前端控制器,本质是一个Servlet。当请求进入Context后,匹配到DispatcherServlet,进入它的service方法。DispatcherServlet是整个MVC的入口。DispatcherServlet内部调用doDispatch核心方法。

    doDispatch内部流程:首先通过HandlerMapping,根据请求URL查找对应的Controller处理器。HandlerMapping保存URL和Controller方法的映射关系,扫描项目所有@Controller注解,把@RequestMapping地址和方法绑定。找到Handler之后,获取对应的HandlerAdapter,HandlerAdapter负责调用Controller方法。

    HandlerAdapter通过反射执行Controller里的目标方法,传入请求参数。Controller执行业务逻辑,返回ModelAndView或者直接返回JSON。 如果返回视图,DispatcherServlet调用ViewResolver视图解析器,找到页面,渲染数据;如果是@ResponseBody,直接把返回对象转为JSON,写入Response。

    处理完成后,DispatcherServlet把结果写入HttpServletResponse。Tomcat的Connector拿到response,组装HTTP响应报文,通过Socket写回浏览器。请求链路结束,关闭连接(HTTP1.1长连接则复用连接)。

    总结:Tomcat负责底层网络通信、HTTP报文解析,把请求交给Servlet;SpringMVC的DispatcherServlet作为核心Servlet,完成URL路由,调用Controller,处理返回结果。Tomcat提供Web运行环境,SpringMVC在Servlet之上做路由和业务分发,二者配合完成从浏览器访问到Controller执行的完整流程。


    赞(0)
    未经允许不得转载:网硕互联帮助中心 » java面试题
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!