Java普通面试题

本文涵盖了Java基础如JDK/JRE区别、==与equals对比,深入解析final、finally和finalize,以及字符串处理、反射、容器、多线程、Web开发和数据库操作等内容。掌握核心特性和实践技巧,提升Java编程能力。
摘要由CSDN通过智能技术生成

题目目录

一、Java基础

1.JDK和JRE的区别

JDK是包含JRE+编译器。JRE是java的运行环境。
如果只需要运行java程序,安装JRE即可;如果需要编写程序,则安装JDK。

2.==和equals区别

==分情况:对于基本数据类型(8-byte、int、short、long、float、double、char、Boolean),都是值比较,对于引用类型的话,就是比较引用了。
equals默认是引用比较,但多数情况下,很多类重写了equals方法,例如String、Interger等,从而成了值比较。

3.1 final、finally、finalize区别

final 修饰的类不能继承、方法不能重写、修饰的变量是常量,必须初始化。
finally常见于try…catch…语句块中,finally后面语句表示不管对错,都是执行。
finallize是超类Object的一个方法,垃圾回收时候会用到,每次回收前都会调这个方法看是否可回收。

3.2 final在Java中的作用

  • final修饰的类,是不能够被继承的。这也是为什么抽象类用final修饰,会报错的原因。
  • final修饰的方法不能被重写,但是可以重载。
  • final修饰的变量是一个常量,必须被初始化,值不能改变。

4.重写和重载(Overriding、Overloading)

首先,这两者都是java多态性的表现。
方法重写:子类和父类之间多态性的表现。也就是方法名相同,参数类型和个数也相同。
方法重载:一个类多态性的表现。一个类有多个相同的方法名,但是参数类型和个数不同。

5.java操作字符串的类,区别

String、StringBuffer、StringBuilder
String,它使用final修饰的字符数组保存字符串,所以不可变,是一个字符串常量。每次String操作都会创建新的String对象,指针指向新对象,操作慢于其他两者。
StringBuffer,线程安全的,但是性能不好,多线程可用。可变序列,是一个字符串变量
StringBuilder。线程不安全的,但是性能好,单线程可用。可变序列,是一个字符串变量

  • 某种程度上,buffer性能高于bulider。例如toString方法,但并不是瓶颈。

6.String类中常用方法

  • split:分割字符串,返回一个分割后的字符串数组
  • equals:字符串的比较
  • trim:去除字符串两端的空白
  • substring:截取字符串
  • replace:字符串替换

7.如何将字符串反转

这里可以用到StringBuffer或者StringBuilder的reverse方法
直接new一个Buffer或Builder,然后.aapend,括号加字符串,然后reverse方法结果即可!
在这里插入图片描述

8.#{ }和${ }区别

最大区别在于安全。sql注入是程序对用户输入数据过滤不严,别人可在查询语句后添加额外sql语句,从而完成非法操作,盗取信息。
#{ }:可进行预编译,编译好再取值,防止sql注入
${ }:数据库操作时拼接用的,先取值后编译,不能防止sql注入。

9.字符常量和字符串常量区别

字符常量字符串常量
形式上’ ’" "
含义上相当于整形值,可参与表达式运算代表一个地址值
内存上一个字节若干个字节
类型上charstring

10.抽象类必须有抽象方法吗

不是
在这里插入图片描述

11.普通类和抽象类的区别

  • 普通类不能包含抽象方法,可以实例化
  • 抽象类能包含抽象方法,不能被实例化
    为什么不能被实例化?
    逆向思维想一下,实例化是因为我们要调用对象里面的方法,但是抽象类是没有具体的对象,比如可以实例化苹果,但是不能实例化水果。

12.接口和抽象类区别

抽象类是对事物本身的一种描述,而接口是对事物具体行为方式的描述。比如哈士奇抽象类就是狗,接口就是吃饭,看门。
实现方式:接口是用implements实现接口,抽象类子类用extends来继承
构造函数:抽象类可有构造函数,接口不能有
数量:一个类可以有多个接口,但是只能一个抽象类

13.如何获取一个接口/抽象类对象

  • new接口,但是要在构造器中实现接口的所有抽象方法
  • new子类/实现类
  • 工厂模式来建造。典型的sqlSessionFactory这种方式。

14.Java三大特性

封装:封装对象的属性,也就是隐藏起来,访问只有通过对外公开的接口才能访问,有限避免一些错误操作使用对象的私有部分;
继承:一个类型的对象获得另一个类的对象的属性和方法。比如子类继承父类,然后获取它的实例域和方法,从而拥有相同的行为;
多态:同一个行为多种不同的表现形式。最经典的就是方法重载和重写。

15.Java中的IO流分为几种

按功能:输入流、输出流
按类型:字节流、字符流(区别:8位传输以字节为单位,16位传输以字符为单位)

16.Java中的文件上传实现

思维图:
在这里插入图片描述
客户端代码

public class FileTcpSocketClient_缓冲流 {
    public static void main(String[] args) throws IOException {
        //文件上传客户端
        //1.初始化socket,连接到哪个服务器(打电话)
        InetAddress localHost = InetAddress.getLocalHost();
//        System.out.println(localHost);
        Socket socket = new Socket("localHost",8088);
        //2.创建输入/输出流(缓冲流)
        //读取本地文件
        BufferedInputStream bufferedInputStream = new BufferedInputStream(new FileInputStream("客户端文件.jpg"));
        //输出网络流
        BufferedOutputStream bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
        //3.写数据(边读边写)
        int len;
        byte[] buffer = new byte[1024];
        while((len=bufferedInputStream.read(buffer))!=-1){
            //读到的内容写到网络流中,写一段刷新一段数据
            bufferedOutputStream.write(buffer,0,len);
            //刷新缓冲数据
            bufferedOutputStream.flush();

        }
        //4.关闭,释放资源
            bufferedOutputStream.close();
            bufferedInputStream.close();
            socket.close();
        System.out.println("文件发送完毕!");
    }
}

服务端代码:

public class FileTcpServerSocket_缓冲流 {
    public static void main(String[] args) throws IOException {
        System.out.println("服务器开始启动!");
        //1.创建服务端ServerSocket,绑定端口(创建10086,申请10086号码)
        ServerSocket serverSocket = new ServerSocket(80881);
        //2.授权连接accept,返回socket对象(socket指客服小姐姐)
        Socket socket = serverSocket.accept();
        //3.创建流对象
        //3.1通过socket得到输入流(获取输入流,读文件数据)
        BufferedInputStream a = new BufferedInputStream(socket.getInputStream());
        //3.2获得输出流,保存到本地
        BufferedOutputStream b = new BufferedOutputStream(new FileOutputStream("服务器文件.jpg"));
        //4.创建一个字节数组,读取数据到字节数组中,读取数据到字节数组中
        int len;
        byte[] buffer = new byte[1024];
        while ((len=a.read(buffer))!=-1){
                b.write(buffer,0,len);
        }
        //7.关闭,释放资源
        b.close();
        a.close();
        socket.close();
        System.out.println("文件上传已保存");
    }
}

17.Files常用方法

Files.exists:检测文件路径是否存在
Files.create:创建文件
Files.copy:复制文件
Files.move:移动文件
Files.write:写入文件
Files.read:读取文件

18.for和foreach区别

两者都是用来遍历元素

  • for循环可以使用break跳出循环,foreach不行;
  • for循坏可以控制循环起点,而foreach必须从索引0开始;
  • for循环过程中可以修改,而foreach不行(底层控制index自增,我们无法左右)

19.深拷贝和浅拷贝区别

两者最根本区别就是:是否真正获取一个对象复制实体;
浅拷贝只是增加了一个指针指向已存在的内存地址,只是复制对象所有的值;
深拷贝是增加一个指针并指向了一个新的内存,对象的值和引用全部复制过来了;

20.Java中常用的工具类

  • StringUtils 字符串的工具类。
    isEmpty——字符串是否为空
    equals——字符串是否相同 trim、replace、substring、split
  • ArrayUtils 数组的工具类
    contains——是否包含某个字符串
    addAll——添加整个数组
    indexOf——查找元素下标
  • FileUtils——文件的工具类
    copy、write、read
  • CollectionUtils 集合接口工具类
    isEmpty、select——筛选集合元素
    isEqualCollection——判断集合是否一致

21.装箱和拆箱

装箱:基本类型转成包装类型的过程,通过.vauleOf方法
拆箱:包装类转为基本类型的过程,调用包装类的xxxValue方法,xxx代表我们对应的基本数据类型
比如int装箱就调用Interger的就是valueOf(int),
Interger拆箱就是调用的Integer的intValue方法

二、Java反射

1.什么是Java反射机制

Java反射是在运行状态中,
对于一个类而言,能够获取它的属性和方法
对于一个对象而言,能够调用它的属性和方法
这种动态获取信息或者调用对象方法的操作就是java的反射。

2.什么是Java序列化?什么情况下序列化?

Java序列化:保存对象在内存中的状态,并且能从内存中读取对象状态,就是对象转为字节流的过程。
情况:

  • 讲对象存到文件或数据库中
  • 远程调用传输对象

3.Java获取反射的三种方法

  • 类名.getClass
  • new对象
  • 通过路径实现

4.动态代理是什么?应用?

动态代理是运行时动态生成代理类,这个代理类不实现服务,而是调用被代理类的方法,起到一个预处理的作用。
(艺人和经纪人的关系)
应用:AOP,rpc、java注解对象获取

5.动态代理的实现原理

JDK原生动态代理、cglib动态代理
jdk动态代理是由java内部的反射机制实现的,反射在生成类的过程中高效。但是jdk动态代理前提是目标类必须统一接口,有局限性。
cglib动态代理是通过asm实现的,对生成类后的相关操作高效,也就是继承当前类的子类实现的。这种通过第三方实现的代理效率更高点。

三、Java容器

1.Java容器有哪些

Java容器分为两大类,Collection和Map。

  • Collection【 list(ArrayList、LinkedList、Vector、Stack)、set(HashSet、LinkedHashSet、TreeSet) 】
  • Map【 HashMap(LinkedHashMap)、TreeMap、ConcurrenctHashMap、HashTable 】

2.Collection和Collections区别

Collection是一个集合接口,提供了集合对象进行操作的基本方法,所有集合都是它子类,比如list、set等
Collections是一个包装类,包含了静态方法,就像一个工具类,例如提供排序的方法sort等等。

3.List、Set、Map区别

主要两方面:元素是否有序、元素是否可重复
在这里插入图片描述

4.HashMap和HashTable区别

存储:HashMap是允许key、value为null,HashTable不允许为null。
线程安全:HashMap是非线程安全的,HashTable是线程安全的。
单线程情况下,可以用HashMap。多线程情况下,用的concurrenct,而不是HashTable,因为它的put/get方法都有synchronized修饰,说明方法是级别堵塞的,效率就非常低,可以看做是一个保留类。

5.如何用HashMap和TreeMap?

对于在Map中,如果插入、删除操作比较多,就用HashMap;
但如果对于一个key集合进行有序遍历,有用TreeMap;

6.HashMap的实现原理

HashMap是以键值对(key,value)进行数据存储的,基于hash算法来实现的,通过put/get进行存值,取值操作。
首先,jdk8中,HashMap底层是数组+链表+红黑树来实现的。
当传入一个key时,HashMap通过hashcode()算出hash值,然后取模存入到对应的bucket当中。当计算出hash值相同时,就是hash冲突,此时将会以链表的形式存储到同一个bucket上。jdk8之前是头插法,8之后采用尾插法,当链表长度到达8时,就会采用红黑树的方式存储,因为查询方便;长度到6时,又转为链表方式。

7.HashMap的扩容过程

当容器元素数量达到阈值,就扩容。
阈值:当前数组长度*加载因子0.75
扩容就是:从一个数组拷贝到另一个数组。
扩容是2的n次方,当元素个数大于2的某个次方时,就会扩容到2的某个次方+1。

8.ArrayList和LinedkList区别

ArrayList是基于动态数组实现的,LinkedList基于双向链表实现的。
所以访问效率,ArrayList是远高于LinkedList,因为LinkedList是线性存储方式,每次指针都要往后移;并且LinkedList更占内存,每个节点有两个引用,一个指向前一个(to prev),一个指向后一个(to next)。
但是增加、删除操作,LinkedList效率远高于ArrayList,因为ArrayList每次增加、删除操作后,会影响数组内其他数据的下标。
另外,LinkedList还实现了Deque接口,它是Queue接口的子接口,它代表一个双向队列,因此LinkedList可以作双向队列。
总体来说,数据读取频繁用ArrayList,插入、删除操作用LinkedList。

9.ArrayList和Vector区别

Vector使用了synchronized实现线程同步,是线程安全的,ArrayList是非线程安全的,但是性能高于Vector。
另外,两者都是动态调整容量,Vector扩容每次增加1倍,而ArrayList每次扩容1/2。

10.Array和ArrayList区别

  • Array可存储基本数据类型和对象,ArrayList只能存储对象
  • Array是固定大小的,ArrayList是自动扩容的
  • ArratList内置方法更多,比如addAll,removeAll,iteration

11.迭代器Iterator是什么

Iterator接口提供遍历任何Collection的接口,为各种容器提供了公共的操作接口。

12.fail-fast和fail-safe

两者是多线程并发操作集合时的一种失败处理机制
fail-fast表示快速失败,在集合遍历过程中,一但发现容器中的数据被修改过了,就会立刻抛出一个ConcurrentModificationException异常,从而导致整个遍历过程是失败的;比如我定义一个Map集合,使用Iterator迭代器进行数据遍历,在遍历过程中,对集合的数据做了一个变更,就会抛出这个异常;而java.utli包下的集合类都是属于快速失败机制的,常见的使用这样一个机制的集合有ArrayList、HashMap等等;
fail-safe表示的是一个失败安全,也就是在这个机制下,出现集合元素的修改,不会抛出上述异常;
原因是采用安全失败机制的集合容器在遍历时候,不是直接在集合内容上进行访问,而是先复制集合的内容,在拷贝的集合上进行遍历;由于迭代器是对原始集合的拷贝进行遍历的,所以在遍历过程中对原始集合的修改并不能被迭代器检测到;
比如我定义一个CopyOnWriteArrayList,在对这个集合遍历过程中对集合元素进行修改后,它不会抛出异常,同时也不会打印出修改后所修改的内容,在java.util.concurrent包下的一个容器,都是属于安全失败的,可以在多线程并发使用的时候,提供并修改的这样一个机制的,常见的使用这个机制的容器有ConcurrentHashMap和CopyOnWriteArrayList等;

13.HashTable不允许null

因为HashTable使用失败安全机制,这种机制下读取的数据不一定是最新的数据。
如果使用null的话,就无法判断对应的key是不存在还是为空,因为无法再调用contain来对key是否存在进行判断,ConcurrentHashMap也是同理;
TIP:失败安全,java.utli.concurrent包下的容器都是失败安全,可在多线程并发使用。

四、Java多线程

1.并行和并发区别

  • 并行:多个处理器或多核处理器同时处理多个任务
  • 并发:多个任务在同一个CPU核上,通过时间片轮流执行

2.线程和进程区别

一个程序至少有一个进程,一个进程下至少一个线程,也可以多个线程提高执行速度。(进程>线程)

3.守护线程是什么

守护线程是运行在后台的一种特殊进程。独立于控制终端并周期性执行某种任务。
比如Java中的垃圾回收线程就是守护线程。

4.创建线程的方式,哪种更常用

  • 实现Runnable接口
  • 实现Callable接口
  • 继承thread重写run方法
  • 应用程序可以使用Executor框架来创建线程池
    实现Runnable接口这种方式更受欢迎,因为这不需要继承Thread类。在应用设计中已经继承了别的对象的情况下,这需要多继承(而Java不支持多继承),只能实现接口。同时,线程池也是非常高效的,很容易实现和使用。

5.Runnable和Callnable区别

  • runnable没有返回值,不能throw抛出异常;
  • callable有返回值,能throw抛异常;
    对于callable,通过future task去获得返回值,future是接口,future task是它的实现类。
    一般future作用:终端执行的任务,判断任务是否还在执行,得到执行后的结果。

6.throw和throws区别

在这里插入图片描述

7.解释下线程的几种可用状态

  • 新建( new ):新创建了一个线程对象。
  • 可运行( runnable ):线程对象创建后,其他线程(比如 main 线程)调用了该对象的start ()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取cpu的使用权。
  • 运行( running ):可运行状态( runnable )的线程获得了cpu时间片( timeslice ),执行程序代码。
  • 阻塞( block ):阻塞状态是指线程因为某种原因放弃了cpu使用权,也即让出了cpu timeslice ,暂时停止运行。直到线程进入可运行( runnable )状态,才有机会再次获得 cpu timeslice 转到运行( running )状态。阻塞的情况分三种:

(一). 等待阻塞:运行( running )的线程执行 o.wait ()方法,JVM会把该线程放入等待队列( waitting queue )中。

(二). 同步阻塞:运行( running )的线程在获取对象的同步锁时,若该同步锁被别的线程占用,则 JVM 会把该线程放入锁池( lock pool )中。

(三). 其他阻塞: 运行( running )的线程执行Thread.sleep ( long ms )或 t.join ()方法,或者发出了 I/O 请求时,JVM会把该线程置为阻塞状态。当 sleep ()状态超时、join()等待线程终止或者超时、或者I/O 处理完毕时,线程重新转入可运行( runnable )状态。

  • 死亡( dead ):线程run()、 main() 方法执行结束,或者因异常退出了run()方法,则该线程结束生命周期。死亡的线程不可再次复生。
    在这里插入图片描述

8.sleep()和wait()区别

sleep( )来自于Thread,它是不会释放锁的,方法时间一到就会自动恢复;
wait( )是Object类的一个方法,会释放锁,需要由notify()或者notifyAll()方法唤醒;

9.notify()和notifyAll()区别

8.9的四个方法就是线程同步线程调度相关的方法

  • notify()是随机唤醒一个线程;
  • notifyAll()是唤醒全部的线程;调用notifyAll()后,会将全部线程由等待池转到锁池,然后参与锁的竞争,成功则继续执行;不成功则留在锁池继续参与锁的竞争。

10.线程的run()和start()区别

start()用于启动线程,只能调用一次
run()用于执行线程运行时代码,可重复调用

11.线程池作用

在程序启动的时候就创建若干线程来响应处理,它们被称为线程池,里面的线程叫工作线程
第一:降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
第二:提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
第三:提高线程的可管理性。

12.synchronized底层实现原理

synchronized是java中实现同步锁的关键字
实现原理分两种情况:
synchronized同步语句块
使用了monitorenter和monitorexit指令,前者指向同步代码块开始的地方,后者指向同步代码块结束的地方。
当执行monitorenter指令时,线程会获取锁,也就是获取monitor的持有权。当计数器为0的时候成功获取,之后将计数器变为1。
当执行monitorexit指令时,计数器设为0,表明锁被释放。如果获取对象锁失败,就会阻塞等待,直到锁被另外一个线程释放为止。
注意:为什么有两个monitorexit?
因为防止异常退出从而没有释放锁,造成死锁;第二个就是保证即使异常,我也能将锁释放出去。
synchronized修饰方法
没有两个指令,而是acc_synchronized标识,表明是一个同步方法。JVM访问标识来辨别一个方法是否为同步方法。

13.什么是死锁?怎么防止死锁?

线程A持有独占锁a,尝试获取独占锁b;
线程B持有独占锁b,尝试获取独占锁a;两者都需要对方的锁而发生的阻塞现象,就是死锁。
防止

  • 可以使用tryLock的方法,来设置超时时间,超时可退出防止死锁;
  • 使用Java.utils.concurrent 并发类代替手写锁;
  • 降低锁的使用度,不要几个功能同一把锁
  • 减少使用同步的代码块

14.synchronized和Lock区别

  • synchronized 可以给类、方法、代码块加锁;而 lock 只能给代码块加锁
  • synchronized 不需要手动获取锁和释放锁,使用简单,发生异常会自动释放锁,不会造成死锁;
    而 lock 需要自己加锁和释放锁,如果使用不当没有 unLock()去释放锁就会造成死锁。
  • Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到

15.synchronized用在静态方法和非静态方法的区别

修饰静态方法其实就是类锁,因为static的方法属于类方法,
修饰非静态方法就是对象锁
两者之间不会产生互斥。但是让一个类下面所有静态方法和非静态方法共用一把锁时,就要用到Lock

16.异常分类及处理机制

异常分类主要两大类:error和exception --<错误和异常>
错误一般代表了jvm本身的错误,这个人为通过代码搞不定。
异常一般代表运行时各种不期望的事件,可以被java异常处理机制搞定。
异常又分为两大类,编译异常(检查异常)和运行异常(不检查异常)。
编译异常通常都是外部资源或者环境错误造成的,java强制捕获或者处理这些异常,保持程序健壮性。
运行异常通常是代码逻辑错误,数学异常,空指针异常等,由人为处理,避免去捕获。
所以,java处理运行时错误有三种方式:
1.程序不能处理的错误-oom
2.程序必须捕获的错误–代码逻辑错误,空指针数学异常
3.程序能尽量避免而不去捕获的错误–配置环境有问题

17.NoClassDefFoundError和ClassNotFoundException区别

NoClassDefFoundError是一个错误,ClassNotFoundException是一个异常;
在Java中,对于错误和异常处理是不同的,可以从异常中恢复程序,但不能从错误中恢复;
NoClassDefFoundError产生的原因是:jvm尝试加载的时候找不到类的定义,也就是这个类在运行的时候存在,加载的时候找不到它,这个常见错误就是我们导包的时候不完整导致的;
ClassNotFoundException产生的原因是:在java中,我们用class.forName方法动态加载一个类,任意一个类名被作为参数传递给这个方法,都可以使方法得到加载,如果这个类的路径没找到,就会抛出这个异常;

五、JavaWeb

1.JSP和Servlet区别

jsp本质上就是一个servlet,而servlet本质上是一个java程序,所以jsp是servlet的一个扩展。
区别:servlet应用逻辑在java文件上,完全从html分离开,注重于逻辑;而jsp是java和html组合的一个扩展名为jsp的文件,注重于视图(el表达式+jstl==展示数据)。

2.JSP内置对象

JSP 有 9 大内置对象:
• request:封装客户端的请求,其中包含来自 get 或 post 请求的参数;
• response:封装服务器对客户端的响应;
• pageContext:通过该对象可以获取其他对象;
• session:封装用户会话的对象;
• application:封装服务器运行环境的对象;
• out:输出服务器响应的输出流对象;
• config:Web 应用的配置对象;
• page:JSP 页面本身(相当于 Java 程序中的 this);
• exception:封装页面抛出异常的对象。

3.JSP的作用域

• page:代表与一个页面相关的对象和属性。
• request:代表与客户端发出的一个请求相关的对象和属性。一个请求可能跨越多个
页面,涉及多个 Web 组件;需要在页面显示的临时数据可以置于此作用域。
• session:代表与某个用户与服务器建立的一次会话相关的对象和属性。跟某个用户
相关的数据应该放在用户自己的 session 中。
• application:代表与整个 Web 应用程序相关的对象和属性,它实质上是跨越整个
Web 应用程序,包括多个页面、请求和会话的一个全局作用域。

4.cookie和session区别

• 存储位置:session 存储在服务器端;cookie 存储在浏览器端。
• 安全性:cookie 安全性一般,在浏览器存储,可以被伪造和修改。
• 容量和个数限制:cookie 有容量限制,每个站点下的 cookie 也有个数限制。
• 存储多样性:session 可以存储在 Redis 中、数据库中、应用程序中;而 cookie
只能存储在浏览器中

六、网络

1.BIO、NIO、AIO区别

BIO:同步阻塞式,有多少个用户向浏览器发送请求,就会创建多少个线程。不管用户有没有响应,线程都必须等待,资源浪费严重。一个用户一个线程。
NIO:同步非阻塞,用户和浏览器之间多了一个选择器,用户请求发送到选择器上,当有IO读写时,就会给它创建线程。一个请求一个线程。
AIO:异步非阻塞,用户发送的请求先给操作系统处理,处理后再通知线程。一个有效请求一个线程。

2.forword和redirect区别

url显示:forword地址栏不会变,redirect会改变
数据共享:forword可以共享request数据
forword效率高于redirect

3.get和post区别

• get 请求会被浏览器主动缓存,而 post 不会。
• get 传递参数有大小限制,而 post 没有。
• post 参数传输更安全,get 的参数会明文限制在 url 上,post 不会。

4.如何实现跨域

• 服务器端运行跨域 设置 CORS 等于 *; (前端跨域)
• 在单个接口使用注解 @CrossOrigin 运行跨域;(后端跨域)

七、Mysql数据库

1.MySQL的内连接、左连接、右连接区别

inner join 、left join、right join
内连接是把匹配的关联数据显示出来;
左连接是左边的表全部显示出来,右边的表显示符合条件的数据;
右连接是右边的表全部显示出来,左边的表显示符合条件的数据;

2.ACID是什么

原子性:指的是数据库事务是不可分割的工作单位;整个操作要么全部成功,要么全部失败;
一致性:指的是数据库事务不会伙牌数据完整性。比如我有1000,然后账户转200,不管成功与否,总金额还是1000;
隔离性:指的是并发环境中,每个事务都有自己完整数据空间;
持久性:指的是事务成功结束,对数据库更新是永久保存的;
(原子性:事务要么都成功,要么都失败。
一致性:事务结束后,数据都是一样的。
隔离性:事务执行期间,都看不到对方的中间状态。
持久性:数据操作后,是永久性的。)

3.数据库三范式

第一范式:强调的是列的原子性,即数据库表的每一列都是不可分割的原子数据项;
第二范式:实体的属性完全依赖主关键字,也就是不能只依赖主关键字一部分属性;
第三范式:非主属性之间不互相依赖;

4.一张自增表里共有5条数据,删除最后2条,重启MySQL数据库,又插入一条,此时id多少?

表类型是MyIsm的话,id就是6;
表类型是InnoDB的话,id就是4;
InnoDB会把自增主键的id存到内存中,所以重启后id丢失,所以为4;

5.数据库的事务隔离

MySQL的事务隔离是在.ini配置文件中添加的;
四种隔离:
read-uncommitted:未提交读;最低隔离级别、事务没提交前,就能被其他事务读取(脏读、幻读、不可重复读)
read-committed:提交读;一个事务提交后才能被其他事务读取(脏读、不可重复读)
repeatable-read:可重复读,默认级别;保证多次读取同一个数据,它的值和事务开始时候是一致(幻读)
serializable:序列化,最高隔离级别;

6.脏读、不可重复读、幻读

脏读:表示一个事务能够读取另一个事务中还未提交的数据。比如,一个事务插入A,还没提交;另一个事务读取到了A;
不可重复读:指在一个事务内,多次读同一数据;比如事务A读取了一条数据,此时事务B对数据进行了修改,当A再次读取时候,发现数据不匹配,这就是不可重复读;
幻读:指同一个事务多次查询返回的结果不一样。比如,一个事务A第一次查询有x条记录,第二次查询有x+1条记录;其实原因就是:另一个事务对第一个事务的数据进行了操作(新增、删除、修改)

7.乐观锁和悲观锁

悲观锁:认为表中的数据每次操作都会修改,所以每次都会上锁,只有拿到锁才能操作;比如synchronized就是悲观锁思想的一种体现;
乐观锁:认为表中数据不会被修改,不会上锁;但是在更新的时候它会判断有没有更改数据,通过版本号CAS算法实现;
数据库添加version字段,当修改一次,版本号+1,如果if判断和自己不一致,就驳回请求。

七、JVM

1.JVM怎么给线程分配内存

主要是通过堆空间整齐度

  • 指针碰撞;(要求可使用内存和已用内存是连续的,有一条边界区分----一般是新生代里面的复制算法)
  • 空闲列表;(内存碎片化严重,哪里空去哪里----一般是老年代里的CMS,用的标记-清除算法)

2.Java中的强、软、弱、虚引用

强引用:只要引用存在,垃圾回收器永远不会回收;内容不够时,会抛出OOM错误,也不会回收它;
软引用:内存足够前提下,永远不会回收,内存溢出之前进行回收;
弱引用:第二次垃圾回收时回收;
虚引用:垃圾回收时回收,无法通过引用取到对象值;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

11_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值