面试经常问的面试题

1、什么是多态?
多态是面向对象设计思想的三大基本特征之一。
在Java中,任何一个对象都拥有两种类型,一种称之为“编译型类型”,一种称之为“运行时类型”。当一个对象,它的“编译时类型”和“运行时类型”不相同时,就发生了所谓的多态。当多态发生之后,该对象在编译时会表现出父类的特征,但是在运行时,就会表现出子类的特征,这也是我们需要运用多态的重要依据。
例子:比如创建一个对象,A a = new A(); 对于对象a(确切来说,a是一个指向对象A的引用)来说,它的编译时类型是A(由A a决定),运行时类型也是A(由new A()决定)。
多态的情况:A a = new B(); 这种情况下,就发生了所谓的多态。前提:A是B的父类或者父接口。多态发生时,a变量在编译时,a被编译器当前A类型,只能调用A中的方法(在编译时会表现出父类的特征),但是运行时,a调用的方法实际上运行的是B类中重写方法(在运行时,就会表现出子类的特征)。

2、equals和==的区别
==比较基本类型,比较的是值
比较引用类型,比较的就是地址
equals不能比较基本类型(equals是一个方法,基本类型不能调用方法,基本类型的包装类可以)
equals比较引用类型,默认就是根据
比较。具体如何比较,可以根据自己的业务进行重写(String的equals有比较值得特性,也是因为String重写了equals方法)
3、什么是Ajax?Ajax实现原理?列举Ajax的几种运用场景
Ajax是浏览器提供的一种异步和服务器交互,并且可以在不刷新整合网页的情况下,能够进行局部更新的技术。

Ajax主要是基于浏览器提供的XMLHttpRequest对象,浏览器本身不与服务器进行数据交互,而是交给XMLHttpRequest与服务器进行数据交互,在交互的过程中,浏览器不会同步阻塞,仍然可以进行相关操作。XMLHttpRequest获得服务器响应后,可以通过js动态的修改浏览器的局部页面。

Ajax运用场景:
1)注册表达单,验证用户名是否已经注册
2)树形菜单的逐层加载显示
3)N级联动的逐步展示
4)搜索关键字的自动联想
4、Mybatis和Hibernate的区别
Mybatis和Hibernate都是属于非常出名的ORM框架。Hibernate是一种全自动化的ORM框架,通过Hibernate,开发对数据库的所有操作,都可以转换成对象操作。一旦配置完成,操作起来会非常方便(配置的过程比较繁琐)。但是在互联网时代,庞大的数据以及巨量的并发,使得性能成为了项目的首要目标。Hibernate因为完全封装了SQL语句,使得开发者对SQL语句的优化变得繁琐,并且Hibernate也没办法很好的支持存储过程。因此Mybatis反而受到很多的青睐,Mybatis属于半自动的ORM框架,需要开发者手动编写SQL语句,正式因为手动sql的支持,开发者可以很好的对SQL语句进行自定义优化,而且Mybatis也对存储过程提供了良好的支持,更易与开发出高性能的系统。因此,传统的管理项目还是青睐于采用Hibernate,而大型的互联网项目Mybatis成为首选。

5、ArrayList的底层实现原理
ArrayList底层是通过动态数组实现的。在java中一旦初始化一个数组后,长度就固定好,并且不能改变,那么ArrayList是如何实现“动态”的呢?ArrayList会先创建一个空的数组,一旦发现有新的元素添加,则自动再创建一个长度为10的数组,将新的元素放入长度为10的数组中,如果元素添加到10个,则数组长度不够,需要对数组进行扩容,会再次创建一个更长的数据,把旧数组的数据拷贝到新的数组中,完成动态扩展数据的效果。
因为这种特性,当ArrayList频繁的插入、删除集合中间的元素时,会进行大量的元素位移(补位或者让位),所以性能不会很好。但是查询元素时,因为通过下标直接访问数组,所以性能会很好。

一、什么是存储过程?存储过程有什么用?

存储过程是数据库系统中的一个执行单元,可以理解成为一个执行在数据库端的方法。在一个存储过程中,可以执行一系列的sql语句以及流程控制,实现一个复杂的业务逻辑。
存储过程的作用:
对于一个复杂的业务,势必会和数据进行频繁的交互(比如一个下单操作,必须查询库存,判断库存,扣减库存,添加订单,修改积分等等一系列的操作),大量的数据库操作无疑会导致请求响应时间拉长,不利于高并发的处理。这个时候,可以考虑将这个复杂的业务写到数据库的存储过程中,存储过程是执行在数据库端的,这样程序只需要调用数据库的存储过程,以及获得存储过程的结果就行了,极大的减少了和数据库交互的次数,提高了响应速度,并且存储过程只会在数据库端编译一次,后面再次调用,就不需要再次编译了,进一步提高了系统的吞吐量。

二、什么是反射?反射有什么运用场景?

反射是一种可以在运行时动态解析类的技术。
通常反射运用在架构设计中,因为在进行架构设计、工具类抽取时,可能会面临参数对象不明确的情况(比如要设计一个方法,可以将任何对象都转成JSON字符串,在设计这个方法时候根本不知道运行时会传入什么类型的参数),这个时候,方法的参数就有可能会设计成一个父类型甚至直接是Object类型。这个时候,在写方法实现时是不知道这个object类型对象有什么方法,这个时候就需要使用反射动态的获得对象的属性、方法等,进行操作。
比如spring的IOC底层就是通过反射进行Bean的创建和注入的;

三、SpringMVC的请求流程

在这里插入图片描述
在这里插入图片描述

四、手写一个线程安全的单例模式

饿汉式 - 线程安全:
public class SingleClass{
//1、私有化构造方法
private SingleClass(){}

//2、提供一个静态对象(比较‘饿’,加载类的时候直接创建SingleClass对象)
private static SingleClass singleClass = new SingleClass();
//3、提供一个获得静态对象的公有方法 - 供外界访问
public static SingleClass getInstance(){
return singleClass;
}
}

懒汉式:
public class SingleClass{
//1、私有化构造方法
private SingleClass(){}

//2、提供一个静态对象的引用
private static SingleClass singleClass;
//3、提供一个获得静态对象的公有方法 - 供外界访问
public static SingleClass getInstance(){
//比较‘懒’,当需要用到这个对象的时候才创建
if(singleClass == null){
singleClass = new SingleClass();
}
return singleClass;
}
}

五、static关键字的含义

static可以修饰类中的属性、方法、代码块以及内部类,被static修饰的成员会由实例成员变成类成员。类成员直接属于类,不管创建多少个对象,类成员在内存中永远只有一份。而且类成员都是随着类加载时执行(或者初始化)的。类成员可以由类名直接调用,对象也可以直接调用类成员,但是不管对象调用还是类名直接调用,都是调用的同一个类成员。
一、Java中终止线程的方式
有三种方法可以使终止线程。

  1. 使线程正常退出,也就是当run方法完成后线程终止。
  2. 使用stop方法强行终止线程(这个方法不推荐使用,因为stop和suspend、resume一样,也可能发生不可预料的结果,有可能会发生死锁,已经被标记为过时的方法)。
  3. 使用interrupt方法中断线程。
    使用interrupt方法来终端线程可分为两种情况:
    (1)线程处于阻塞状态,如使用了sleep方法。
    (2)使用while(!isInterrupted()){……}来判断线程是否被中断。
    在第一种情况下使用interrupt方法,sleep方法将抛出一个InterruptedException例外,而在第二种情况下线程将直接退出。

二、JDK和JRE的区别
JRE:是java运行时环境,包含了java虚拟机,java基础类库。
JDK:顾名思义是java开发工具包,是程序员使用java语言编写java程序所需的开发工具包,是提供给程序员使用的。JDK包含了JRE,同时还包含了编译java源码的编译器javac,还包含了很多java程序调试和分析的工具

三、数据库连接池的特点
1.资源重用
由于数据库连接得到重用,避免了频繁创建、释放连接引起的大量性能开销。在减少系统消耗的基础上,另一方面也增进了系统运行环境的平稳性(减少内存碎片以及数据库临时进程/线程的数量)。
2.更快的系统响应速度
数据库连接池在初始化过程中,往往已经创建了若干数据库连接置于池中备用。此时连接的初始化工作均已完成。对于业务请求处理而言,直接利用现有可用连接,避免了数据库连接初始化和释放过程的时间开销,从而缩减了系统整体响应时间。
3.新的资源分配手段
对于多应用共享同一数据库的系统而言,可在应用层通过数据库连接的配置,实现数据库连接池技术,几年钱也许还是个新鲜话题,对于目前的业务系统而言,如果设计中还没有考虑到连接池的应用,那么…….快在设计文档中加上这部分的内容吧。某一应用最大可用数据库连接数的限制,避免某一应用独占所有数据库资源。
4.统一的连接管理,避免数据库连接泄漏
在较为完备的数据库连接池实现中,可根据预先的连接占用超时设定,强制收回被占用连接。从而避免了常规数据库连接操作中可能出现的资源泄漏。

四、类加载过程
当JVM加载一个类时,需要经过3个阶段:装载 -> 连接 -> 初始化
装载:通过类的全路径限定名称找到对应类的class文件,加载到jvm内存的方法区中,并且生成一个唯一的Class对象。
连接:又分为3步(验证、准备、解析)。主要是校验class文件的格式,以及赋予类中静态成员默认值。
初始化:主要是初始化类中的静态属性,如果有赋值行为,则初始化的值就会覆盖默认值。

五、手写冒泡排序法
int[] arrays = {7, 10, 2, 5, 19, 66, 45, 100, 164, 26};

//外层循环比较轮数 比较的轮数 n - 1
for(int i = 0; i < arrays.length - 1; i++){
//内存循环控制每轮中比较的次数
for(int j = 0; j < arrays.length - 1 - i; j++){
//比较 arrays[j] arrays[j+1]
if(arrays[j] > arrays[j+1]){
//交换
int temp = arrays[j];
arrays[j] = arrays[j+1];
arrays[j+1] = temp;
}
}
}

冒泡排序注意点:
1、外层循环 i < arrays.length - 1 (n个元素,只要比较n-1轮,所以要这样写)
2、内层循环j < arrays.length - 1 - i (每多比一轮,就要少比一个元素,所以要- i)
3、比较的元素 arrays[j] 和 arraysj + 1
六、写出15个Linux的常用命令
ll:查看文件列表
cd:路径定位
clear:清屏
rm -rf:强制删除
cp:拷贝
mv:剪切
vim:创建并编辑文件
ps -aux:查看进程
server xxx start:操作服务
ssh:远程连接
su:切换用户
chmod:授权
useradd:创建用户
pwd:查看当前路径
tar -zxf:解压

七、编写一个程序,将a文件夹下的所有文本文件(.txt结尾的文件)拷贝到c文件夹中,如下:

在这里插入图片描述

public static void main(String[] args) throws Exception {
String pathA = “C:\worker\a”;
String pathB = “C:\worker\b”;

File file = new File(pathA);
findTxt(file, pathB);

}

/**

  • 递归查找

  • @param file
    */
    private static void findTxt(File file, String outpath) throws Exception {

    if(file.isFile() && file.getName().endsWith(".txt")){
    //如果是一个文件,并且是.txt结尾
    //进行拷贝
    fileCopy(file, outpath + “\” + file.getName());
    } else {
    //如果是一个路径,继续往下递归
    File[] files = file.listFiles();
    for (File file1 : files) {
    findTxt(file1, outpath);
    }
    }
    }

/**

  • 文件拷贝

  • @param file

  • @param outPath
    */
    private static void fileCopy(File file, String outPath) throws Exception {

    FileInputStream in = new FileInputStream(file);
    FileOutputStream out = new FileOutputStream(outPath);

    int len = 0;
    byte[] buffer = new byte[1024];
    while((len = in.read(buffer)) != -1){
    out.write(buffer, 0, len);
    }

    in.close();
    out.close();
    }

八、什么是SpringBoot?
SpringBoot是一种用于快速搭建开发Spring轻应用的框架。拥有开箱即用的特点,默认的提供了很多繁琐的配置,开发者也可以根据自已的要求自定义配置,可以更快捷方便进行Spring应用的开发。另外SpringBoot也整合了很多常用的第三方服务和框架,也有很多第三方框架反向整合了SpringBoot,让这些框架使用起来变得更简单。另外SpringBoot也内置了很多非功能性的特性,比如Tomcat、健康监测等等。

九、final关键字的作用
final关键字可以修饰类、变量、方法。拥有最终的含义。
final修饰类时,表示了当前类不能被继承。
final修饰变量时,标识当前变量只能被初始化一次。注意,被final修饰的成员变量时,JVM不会再对该变量赋予默认值。
final修饰方法是,表示当前方法不能被子类重写。

十、LinkedList和ArrayList的区别
ArrayList底层采用动态数组的结构存放数据。动态数组需要进行扩容还有元素移位,所以从前面插入和删除元素性能不太好。但是通过下标定位的方式查找元素,因此性能较好。
LinkedList底层采用双向链表的结构存放数据。根据链表的特点,插入元素和删除元素只需要修改节点的指向,所以性能会比ArrayList要高(操作越高前和后的元素,性能越好,越靠中间的元素,性能越差)。查询速度,需要从前或者后面遍历,所以性能比ArrayList要差。

一、线程的创建方式,各有什么特点
线程创建有3种方式:
1)继承Thread类
当前类本身就是一个线程,直接调用start方法就可以启动。这种方式编码简洁,而且在线程中直接使用this就能获得当前线程对象,但是不能再继承其他的父类了。

2)实现Runnable接口
当前类并不是一个线程,还需要封装到一个Thread类中,才能实现线程的运行。当前类不能通过this获得当前线程对象,但是该类仍然保留了继承其他类的可能性。

3)实现Callable接口
通过这种方式实现的线程,有返回值。主线程在开启Callable线程后会阻塞等待,直到Callable线程返回结果为止。
二、HashMap底层原理
HashMap底层是采用哈希表的数据结构实现的。哈希表是一种用于快速定位查询的数据结构。当保存key-value数据时,key会经过一个哈希函数,计算得到一个int类型的下标。然后将当前的key-value直接放到该下标对应的数组内,要通过key获取value时,也只需要将key通过哈希函数进行计算,得到下标,去指定的下标中获取即可。哈希表在精准查询时的时间复杂度为O(1)。
HashMap底层是采用链表的方式解决哈希冲突的。为了提高效率,JDK1.8之后,引入了红黑树的结构,进一步提高哈希冲突发生时的查询性能。
三、说出几种常用的设计模式
工厂模式、代理模式、单例模式、装饰者模式、门面模式、模板模式、命令模式、策略模式、观察者模式、适配器模式等

23种设计模式如下:

在这里插入图片描述

四、Mybatis中#和KaTeX parse error: Expected 'EOF', got '#' at position 14: 的区别 在Mybatis中#̲{}的变量会被解析成占位符,可…{}会直接进行字符串拼接。有SQL注入的风险。
比如:
xxx where id = #{id} 会解析成为 xxx where id = ?
xxx where id = ${id} 会解析成为 xxx where id = 10

五、谈谈Dubbo的理解
Dubbo是阿里开源的一款高性能的分布式服务治理框架,也是一款优秀的RPC远程调用框架。
Dubbo通常采用Zookeeper作为注册中心(可以没有注册中心),进行服务的注册与管理,实现了服务层与调用者之间的解耦,并且提供一套高效的RPC远程调用技术,实现服务的调用以及服务间的互调。 Dubbo也内置了服务的负载均衡策略、熔断机制以及丰富的协议,而且和Spring以及SpringBoot无缝整合。
使用Dubbo可以轻松的搭建出高性能的面向服务的系统架构。

一、能否直接调用Thread类的run方法启动线程?和调用Start启动线程有什么区别?
不能直接调用run方法启动线程。
直接调用run方法,JVM会直接在当前线程中,像执行一个普通方法一样,执行run方法中的方法体,并不会新创建一个线程去执行,所以还是单线程结构,并不会多线程。
Thread类必须调用start方法,JVM才会创建一个新的线程来执行run方法中的方法体,从而达到多线程调度的模式。
二、ThreadLocal类的作用
ThreadLocal类通常在多线程模型下使用。主要作用就是ThreadLocal对象,可以将线程的数据进行隔离使用。比如线程A给ThreadLocal对象中写入一个数据a,这个数据a只能在线程A中才能拿出来,线程B访问ThreadLocal只能拿到null。
三、什么是触发器
触发器是数据库维护数据一致性的一种手段。触发器运行在数据库端,可以监视某个行为(比如insert、update、delete),一旦这个行为执行,就会触发这个触发器,触发器内部可以编写复杂的业务逻辑,从而保证这个行为所带来的数据一致性变化。触发器不能手工调用,必须被动触发。我们可以理解成为触发器是一个被动触发的存储过程。
四、Dubbo的容错机制
Dubbo的容错机制是指,在消费者调用提供者失败时,Dubbo的应对手段。
Dubbo提供了多种容错手段:
Failover:失败自动重试,可以设置重试次数(默认行为)
Failfast:快速失败,一旦失败就会报错
Failsafe :失败安全,一旦失败直接忽略
Failback :失败自动恢复,后台记录失败请求,定时重发。
Forking :并行调用多个服务器,只要一台服务器成功即可。
Broadcast :广播所有提供者,逐个调用,任意一台报错则报错
五、谈谈Spring的IOC
IOC是控制反转的意思,简单来说就是讲对象创建的权利反转给第三方(在spring中就是spring容器),程序本省不创建对象,依赖的对象都是从spring容器中注入进来的。这种方式可以有效降低程序类与类之间的耦合性。
降低耦合的好处在于,某个对象的创建模式发生变化后,不会牵扯到其他引用到这个类的类也需要改变。

一、什么是线程间的通讯协作? 列举几种线程间的通讯协作的方式
在多线程的环境下,因为现在线程调度的不确定性,线程和线程之间的调用顺序是无规则的,但是有些场景下需要线程有一定的调用顺序,或者线程之间需要互相传递数据,(比如A线程主要是给变量temp设置值,而线程B主要是取temp的值进行自己的业务操作,所以线程B必须要在线程A设置值之后才能执行)这时候就涉及到线程之间的通讯协作。
线程间的通讯方式主要有两种:
1)notify和wait机制
2)BlockQueue(阻塞队列)

二、TreeMap底层实现原理
TreeMap底层是基于红-黑树的数据结构。红-黑树是二叉树的一种,二叉树是一种便于搜索的数据结构,但是二叉树如果节点失衡会严重影响搜索的效率,为了解决数失衡所带来的性能问题,红-黑树结构就诞生了。红-黑树是一颗平衡的二叉树,通过内部的红黑规则来维护树的平衡,所以TreeMap采用红黑树作为自己的底层数据结构。因为要维护树的平衡,所谓红-黑树插入、删除的效率会低于HashMap(底层是哈希表),查询的效率也会低于HashMap,但是红-黑树本身是有序的数据结构,所以TreeMap的元素是有顺序(字典顺序)的。

三、什么是动静态分离?
Tomcat处理静态资源(js/css/png/gif/jpg…)的速度比较慢,所以在实际开发过程中,通常不会用Tomcat处理静态请求,而是将静态资源提取到单独的服务上,交给更快的静态资源服务器处理(比如Nginx)。这种将动态请求和静态请求分开处理的方式就是所谓的动静态分离。

四、谈谈Spring的AOP机制
AOP(面向切面编程)是一种编程思想,在传统的业务开发中,业务代码可能会可一些非业务相关的代码耦合在一起(比如 开启事务 -> 核心业务 -> 提交事务)。面向切面就是针对这种编程模式做出的升级改进,将非核心代码封装抽取,开发者只需要关心核心业务层的代码,然后再通过织入的方式最后形成完成的业务逻辑代码。
AOP底层是基于动态代理实现的,Spring的AOP底层采用了JDK的动态代理和Cglib动态代理来实现AOP机制。

五、请写出如下空缺的代码
public static void main(String[] args) throws Exception {
Integer a = 10;
Integer b = 20;
System.out.println(a + " " + b);
swap(a, b);
System.out.println(a + " " + b);
}

public static void swap(Integer a, Integer b) throws Exception {
//请实现该方法
}

运行结果:
10 20
20 10

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值