java面试题

本文主要探讨了Java面试中常见的问题,包括交换数字的方法、double的近似存储、++操作的解析、==与equals的区别、包装类的工作原理、String类的特性、异常处理、多线程的细节(如CAS算法、线程池参数)、I/O框架和网络编程的基础知识,以及MySQL事务的特性与隔离级别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

java面试题

1.如何来交换两个数字?

第一种方法:使用第三个变量

public class Swap{
    public static void main(String[] args) {
        int n1 = 10;
        int n2 = 20;
        System.out.println("交换之前n1:" + n1 + "交换之前n2:" + n2 );
        int temp = n1;
        n1 = n2;
        n2 = temp;
        System.out.println("交换之后n1:" + n1 + "交换之后n2:" + n2 );
    }
}

第二种方法:不使用第三个变量(使用异或运算符)

运算规则:0^0=0; 0^1=1; 1^0=1; 1^1=0;

public class swap{
    public static void main(String[] args) {
        int n1 = 10;
        int n2 = 20;
        System.out.println("交换之前n1:" + n1 + "交换之前n2:" + n2 );
        n1 = n1 ^ n2;
        n2 = n1 ^ n2;
        n1 = n1 ^ n2;
        System.out.println("交换之后n1:" + n1 + "交换之后n2:" + n2 );
    }
}

2.关于double近似存储

      double r = (1.4-0.5)/0.9;
      System.out.println(r);

这里输出0.9999999999,这是因为java中所有的小数都是采取近似存储的方式。

3.++代码题

		int count=10;
		for(int i=0;i<10;i++){//执行10次
			count=++count;
		}
		System.out.println(count);

结果输出10。

4.==和equals的区别?

①如果是基本数据类型比较的数据,如果是引用数据类型,比较的是地址
②默认情况下
和equals是一样的如果equals重写了则比较内容

5.包装类

在这里插入图片描述
我们可以知道输出的是true false true false
原因:第一个:包装类自动拆箱
:第四个:我们可以先用反编译工具xjad把class类反编译成java类找到所对应的代码里面的valueof 按Ctrl点进去我们可以发现valueof里面有一个整数包装类对象数组缓存区 如果存放的数据在-128 – 127之间,直接从这个数组里面找出来,如果不是则需要重新new一个

6.String类

在这里插入图片描述第一个答案:fasle true 第二个答案:true true
使用intern方法如果常量池中没有,则把对象复制一份(或对象引用)放入常量池中,返回常量池中的对象,如果常量池中存在,则直接返回常量地址。
jdk1.7之前是复制一份放入常量池中,jdk1.8(包括1.8)之后则把对象引用放入常量池中
具体的内存解析见下图:
在这里插入图片描述
在这里插入图片描述

7.异常

try{}、catch{}、finally{]中可以包含return语句吗?如果try{}里面有一个return语句,那么紧跟在这个try后的finally{}中的代码会不会执行?
(1)try{}、catch{}、finally{]中可以包含return语句,finally中不推荐使用return,返回不正确的结果
(2)finally无论是否发生异常都会执行,先执行finally再执行return
在这里插入图片描述

8.多线程

1.利用lock和Condition让三个线程交替输入ABC

public class Alternative {
    private int num = 1;
    //创建锁
    Lock lock = new ReentrantLock();

    //创建队列
    Condition conditionA = lock.newCondition();
    Condition conditionB = lock.newCondition();
    Condition conditionC = lock.newCondition();

    //打印A
    public void printA(){
        lock.lock();
        try {
            if (num != 1){
                conditionA.await();
            }
            System.out.println("A");
            conditionB.signal();
            num = 2;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    //打印B
    public void printB(){
        lock.lock();
        try {
            if (num != 2){
                conditionB.await();
            }
            System.out.println("B");
            conditionC.signal();
            num = 3;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    //打印C
    public void printC(){
        lock.lock();
        try {
            if (num != 3){
                conditionC.await();
            }
            System.out.println("C");
            conditionA.signal();
            num = 1;
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}



//测试类
public class TestAlternative {
    public static void main(String[] args) {
        Alternative alternative = new Alternative();
        ExecutorService es = Executors.newFixedThreadPool(3);
        es.submit(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    alternative.printA();
                }
            }
        });
        es.submit(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    alternative.printB();
                }
            }
        });
        es.submit(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    alternative.printC();
                    System.out.println("-----------------");
                }
            }
        });
        es.shutdown();
    }
}

2.CAS算法Compare And Swap(比较交换算法)

其实现方式是基于硬件平台的汇编指令(compxchg),是靠硬件来实现的,效率高,并且比较和交换的过程是同步的,是一种乐观锁
CAS比较交换算法,修改的方法包含三个核心参数
V:要更新的变量,E预期值,N:新值
只有当V==E时,V=N,否则表示已被更新过,则取消当前的操作,继续尝试执行直到成功
关于CAS算法的内存
这里插入图片描述
下面有关于代码模拟的CAS算法

public class CAS {
    private int v;
    private int version;

    public int  getV(){
        return this.v;
    }
    public int getVersion(){
        return this.version;
    }
    public boolean cAndSwap(int e, int n, int version){
        if (this.v == e && this.version == version){
            v = n;
            version++;
            return true;
        }
        return false;
    }
}

public class TestCas {
    public static void main(String[] args) {
        CAS cas = new CAS();
        ExecutorService es = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 100; i++) {
            es.submit(new Runnable() {
                @Override
                public void run() {
                    while (true){
                        int e = cas.getV();
                        int version = cas.getVersion();
                        boolean b = cas.cAndSwap(e, new Random().nextInt(100), version);
                        System.out.println(Thread.currentThread().getName() + "执行了" + b + "版本号:" + version) ;
                        if (b){
                            break;
                        }
                    }
                }
            });
        }
        es.shutdown();
    }
}

关于CAS算法中的ABA问题以及解决办法?
ABA问题就是:当进程A准备修改V的值时,进程B抢先修改了V的值,此时进程C又修改V的值为原来的值。
解决办法:如上面代码,在方法中加一个版本号判断此时V值是不是原来的值。

3.i++是不是原子操作?

答案:不是
i++的执行步骤:
①读取i②执行i+1③赋值i
通过代码分析:

public class TestAtomic {
    public static void main(String[] args) {
        Num num = new Num();
        ExecutorService es = Executors.newFixedThreadPool(10);
        for (int i = 0; i < 10; i++) {
            es.submit(new Runnable() {//匿名内部类
                @Override
                public void run() {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(num.getNum());
                }
            });
        }
        es.shutdown();
    }
    static class Num{//创建一个num类
        static int num= 0;//同时修改一个元素,所以设置成静态的
        static int getNum(){
           return num++;
        }
    }
}

在这里插入图片描述
上图我们可以看到不是原子操作,因为结果中出现了两个0,就证明他在执行的时候被打断了。那我我们要怎么解决这个问题呢?javaAPI中有专门的原子操作Atomic,代码修改了之后如下面

static class Num{
        private static AtomicInteger num = new AtomicInteger();
        static int getNum(){
           return num.getAndIncrement();
        }
    }

decrementAndGet() 相当于: - - i
getAndDecrement() 相当于:i - -
getAndIncrement() 相当于:i + +
incrementAndGet() 相当于:+ +

4.多线程的三大特性及其解析:

①原子性:一个或多个操作不能被分割,要么全部执行,要么都不执行
②可见性:多个线程访问同一个变量,一个线程修改了这个变量,别的线程能立即看到修改的值 Volatile 关键字可以保证内存可见性
③有序性:程序执行的顺序按照代码的先后顺序执行,但是处理器为了提高程序运行效率,可能会对输入代码进行优化,他不保证程序中各个语句的执行顺序与编写顺序一致,但是最终结果是一致的
下面解释一下可见性和有序性
可见性:
我们用代码测试一下

public class myThread extends Thread {
    public boolean flag = false;

    @Override
    public void run() {
        System.out.println("子线程开始执行了。。。");
        while (true){
            if (flag){
                break;
            }
        }
        System.out.println("子线程结束了。。。");
    }
}
public class TestMyThread {
    public static void main(String[] args) throws IOException {
        myThread thread = new myThread();
        thread.start();
        System.out.println("输入任意字符结束子线程");
        System.in.read();
        thread.flag = true;
        System.out.println("主线程结束了:" + thread.flag);
    }
}

在这里插入图片描述
由图我们可以看出子线程并没有执行子线程结束了这句代码,可知子线程中的falg还是false,理由如下
在这里插入图片描述
线程在获取堆中的对象时,并不是直接访问的,而是第一次先从堆中访问读取到cpu的缓存区中,然后以后每次就都使用缓存中的数据,如果不使用volatile则子线程看不见flag已经变为true。所以我们应该把flag设为volatile
这样的执行结果如下:
在这里插入图片描述
有序性:
在这里插入图片描述

5.线程池的七个参数

ThreadPoolExcutor类的参数
corePoolSize:核心线程数
maximumPoolSize:最大线程数
KeepValueTime:非核心线程的存活时间
unit:时间单位
workQueue:工作队列
threadFactory:线程工厂
handler:拒绝策略
AbortPolicy:中断,抛出异常(
核心业务,使用最多)
DiscardPolicy:直接抛弃,不抛出异常(非核心业务)
DiscardOldestPolicy:把旧的抛弃,加入新的(喜新厌旧)
CallerRunsPolicy:线程池创建者执行

9.I/O框架

记事本的编码问题?
(1)记事本编码识别错误问题
在这里插入图片描述
联通的GBK编码正好符合UTF-8的编码格式,GBK前面没有特殊的标记

网络编程

1.OSI七层参考模型

在这里插入图片描述

mysql

1.事务的特性

原子性(Atomicity):表示一个事务内的所有操作是一个整体,要么全部成功,要么全部失败。
一致性(Consistency):表示一个事务内有一个操作失败时,所有的更改过的数必须回到回滚前的指定状态
隔离性(lsolation):事务查看数据操作所处的状态,要么是另一并发事务修改他之前的状态 要么是另一事物修改他之后的状态,事务不会查看中间状态的数据
持久性(Durability):持久性事务完成之后,他对于系统的影响是永久性的

2.事务的隔离级别

在这里插入图片描述
在这里插入图片描述
①Read committed(获取未提交的内容):Oracle默认级别
②repeatable read:mysql默认级别 mysql已经解决了幻读问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值