Java 笔试:常见题目总结

public int test() {

int x = 1;

try {

return x;

} finally {

++x;

System.out.println(“finally:” + x);

}

}

}

执行结果:

finally:2

return:1

那么下面的程序代码输出的结果是多少?

public class smallT

{

public static void main(String args[])

{

smallT t = new smallT();

int b = t.get();

System.out.println(b);

}

public int get()

{

try

{

return 1 ;

}

finally

{

return 2 ;

}

}

}

执行结果是:

2

分析:try中的return语句调用的函数先于finally中调用的函数执行,

也就是说return语句先执行,finally语句后执行,所以,返回的结果是2。

Return并不是让函数马上返回,而是return语句执行后,

将把返回结果放置进函数栈中,此时函数并不是马上返回,

它要执行finally语句后才真正开始返回。

下面用一个程序来帮助分析:

public class Test {

public static void main(String[] args) {

System.out.println(new Test().test());;

}

int test()

{

try {

return func1();

}

finally {

return func2();

}

}

int func1()

{

System.out.println(“func1”);

return 1;

}

int func2()

{

System.out.println(“func2”);

return 2;

}

}

执行结果:

func1

func2

2

结论:finally中的代码比return 和break语句后执行


3. final, finally, finalize的区别

  • final 用于声明属性,方法和类,分别表示属性不可变,方法不可覆盖,类不可继承。内部类要访问局部变量,局部变量必须定义成final类型

  • finally是异常处理语句结构的一部分,表示总是执行。

  • finalize是Object类的一个方法,在垃圾收集器执行的时候会调用被回收对象的此方法,可以覆盖此方法提供垃圾收集时的其他资源回收,例如关闭文件等。JVM不保证此方法总被调用


4. Java中的异常处理机制的简单原理和应用

Java对异常进行了分类,不同类型的异常分别用不同的Java类表示,所有异常的根类为java.lang.Throwable,Throwable下面又派生了两个子类:ErrorException

  • Error 表示应用程序本身无法克服和恢复的一种严重问题,程序只有死的份了,例如,说内存溢出和线程死锁等系统问题。

  • Exception表示程序还能够克服和恢复的问题,其中又分为系统异常和普通异常,系统异常是软件本身缺陷所导致的问题,也就是软件开发人员考虑不周所导致的问题,软件使用者无法克服和恢复这种问题,但在这种问题下还可以让软件系统继续运行或者让软件死掉,例如:

数组越界(ArrayIndexOutOfBoundsException)

空指针异常(NullPointerException)

类转换异常(ClassCastException)

找不到类(ClassNotFoundException)

普通异常是运行环境的变化或异常所导致的问题,是用户能够克服的问题,例如:网络断线硬盘空间不够,发生这样的异常后,程序不应该死掉。

java为系统异常和普通异常提供了不同的解决方案,编译器强制

  • 系统异常可以处理也可以不处理,所以,编译器不强制用try…catch处理或用throws声明,所以系统异常也称为unchecked异常。

  • 普通异常必须try…catch处理或用throws声明继续抛给上层调用方法处理,所以普通异常也称为checked异常。

提示答题者,就按照三个级别去思考:

虚拟机必须宕机的错误

程序可以死掉也可以不死掉的错误

程序不应该死掉的错误


5. sleep() 和 wait() 有什么区别?

  • sleep是线程类(Thread)的方法,导致此线程暂停执行指定时间,给执行机会给其他线程,但是监控状态依然保持,到时后会自动恢复。调用sleep不会释放对象锁。

  • wait是Object类的方法,对此对象调用wait方法导致本线程放弃对象锁,进入等待此对象的等待锁定池,只有针对此对象发出notify方法(或notifyAll)后本线程才进入对象锁定池准备获得对象锁进入运行状态。)

下面用一个例子来说明:

public class Test {

public static void main(String[] args) {

new Thread(new Thread1()).start();

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

new Thread(new Thread2()).start();

}

private static class Thread1 implements Runnable {

@Override

public void run() {

// 由于这里的Thread1和下面的Thread2内部run方法要用同一对象作为监视器,

// 我们这里不能用this,因为在Thread2里面的this和这个Thread1的this不是同一个对象。

// 我们用Test.class这个字节码对象,当前虚拟机里引用这个变量时,指向的都是同一个对象。

synchronized (Test.class) {

System.out.println(“enter thread1…”);

System.out.println(“thread1 is waiting”);

try {

// 释放锁有两种方式:

// 第一种方式是程序自然离开监视器的范围,也就是离开了synchronized关键字管辖的代码范围,

// 另一种方式就是在synchronized关键字管辖的代码内部调用监视器对象的wait方法。

// 这里,使用wait方法释放锁。

Test.class.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“thread1 is going on…”);

System.out.println(“thread1 is being over!”);

}

}

}

private static class Thread2 implements Runnable {

@Override

public void run() {

synchronized (Test.class) {

System.out.println(“enter thread2…”);

System.out.println(“thread2 notify other thread can release wait status…”);

// 由于notify方法并不释放锁,

// 即使thread2调用下面的sleep方法休息了10毫秒,

// 但thread1仍然不会执行,因为thread2没有释放锁,所以Thread1无法得不到锁。

Test.class.notify();

System.out.println(“thread2 is sleeping ten millisecond…”);

try {

Thread.sleep(10);

} catch (InterruptedException e) {

e.printStackTrace();

}

System.out.println(“thread2 is going on…”);

System.out.println(“thread2 is being over!”);

}

}

}

}

执行结果:

enter thread1…

thread1 is waiting

enter thread2…

thread2 notify other thread can release wait status…

thread2 is sleeping ten millisecond…

thread2 is going on…

thread2 is being over!

thread1 is going on…

thread1 is being over!

  • sleep就是正在执行的线程主动让出cpu,cpu去执行其他线程,在sleep指定的时间过后,cpu才会回到这个线程上继续往下执行,如果当前线程进入了同步锁,sleep方法并不会释放锁,即使当前线程使用sleep方法让出了cpu,但其他被同步锁挡住了的线程也无法得到执行

  • wait是指在一个已经进入了同步锁的线程内,让自己暂时让出同步锁,以便其他正在等待此锁的线程可以得到同步锁并运行,只有其他线程调用了notify()方法(notify并不释放锁,只是告诉调用过wait方法的线程可以去参与获得锁的竞争了,但不是马上得到锁,因为锁还在别人手里,别人还没释放。如果notify方法后面的代码还有很多,需要这些代码执行完后才会释放锁,可以在notfiy方法后增加一个等待和一些代码,看看效果),调用wait方法的线程就会解除wait状态和程序可以再次得到锁后继续向下运行。wait()必须在synchronized内部调用


6. 当一个线程进入一个对象的一个synchronized方法后,其它线程是否可进入此对象的其它方法?

分几种情况:

  1. 其他方法前是否加了synchronized关键字,如果没加,则能。

  2. 如果这个方法内部调用了wait,则可以进入其他synchronized方法。

  3. 如果其他个方法都加了synchronized关键字,并且内部没有调用wait,则不能。

  4. 如果其他方法是static,它用的同步锁是当前类的字节码,与非静态的方法不能同步,因为非静态的方法用的是this。


7. 简述synchronized和java.util.concurrent.locks.Lock的异同?

  • 主要相同点:Lock能完成synchronized所实现的所有功能

  • 主要不同点:Lock有比synchronized更精确的线程语义和更好的性能。synchronized会自动释放锁,而Lock一定要求程序员手工释放,并且必须在finally从句中释放。Lock还有更强大的功能,例如,它的tryLock方法可以非阻塞方式去拿锁。

例子:

import java.util.concurrent.locks.Lock;

import java.util.concurrent.locks.ReentrantLock;

public class Test {

private int j;

// ReentrantLock 可重入锁,

// 一个线程可以对已被加锁的ReentrantLock锁再次加锁

private Lock lock = new ReentrantLock();

public static void main(String[] args) {

Test tt = new Test();

new Thread(tt.new Adder()).start();

new Thread(tt.new SubTractor()).start();

}

private class SubTractor implements Runnable {

@Override

public void run() {

while (true) {

// synchronized (Test.this) {

// System.out.println(“j–=” + j–);

// //这里抛异常了,锁能释放吗?

// }

lock.lock();

try {

System.out.println("j-- = " + j–);

} finally {

lock.unlock();

}

}

}

}

private class Adder implements Runnable {

@Override

public void run() {

while (true) {

// synchronized (Test.this) {

// System.out.println(“j++=” + j++);

// }

lock.lock();

try {

System.out.println("j++ = " + j++);

} finally {

lock.unlock();

}

}

}

}

}

执行结果:

···

j++ = 42218

j++ = 42219

j++ = 42220

j-- = 42221

j-- = 42220

j-- = 42219

···


8. 设计4个线程,其中两个线程每次对j增加1,另外两个线程对j每次减少1。写出程序

public class Test {

private int j;

public static void main(String args[]) {

Test tt = new Test();

Inc inc = tt.new Inc();

Dec dec = tt.new Dec();

for (int i = 0; i < 2; i++) {

Thread t = new Thread(inc);

t.start();

t = new Thread(dec);

t.start();

}

}

private synchronized void inc() {

j++;

System.out.println(Thread.currentThread().getName() + “-inc:” + j);

}

private synchronized void dec() {

j–;

System.out.println(Thread.currentThread().getName() + “-dec:” + j);

}

class Inc implements Runnable {

public void run() {

for (int i = 0; i < 100; i++) {

inc();

}

}

}

class Dec implements Runnable {

public void run() {

for (int i = 0; i < 100; i++) {

dec();

}

}

}

}

执行结果:

···

Thread-0-inc:5

Thread-0-inc:6

Thread-2-inc:7

Thread-2-inc:8

···

Thread-2-inc:105

Thread-2-inc:106

Thread-3-dec:105

Thread-3-dec:104

···

Thread-3-dec:7

Thread-3-dec:6

Thread-1-dec:5

Thread-1-dec:4

···

Thread-1-dec:-20

Thread-1-dec:-21

Thread-0-inc:-20

Thread-0-inc:-19

···


9. 子线程循环10次,接着主线程循环5次,接着又回到子线程循环10次,接着再回到主线程又循环5次数。如此循环50次,请写出程序

public class Test {

public static void main(String[] args) {

new Test().init();

}

public void init() {

final Business business = new Business();

new Thread(new Runnable() {

public void run() {

for (int i = 0; i < 50; i++) {

business.SubThread(i); // 子线程

}

}

}).start();

for (int i = 0; i < 50; i++) {

business.MainThread(i); // 主线程

}

}

private class Business {

//这里相当于定义了控制该谁执行的一个信号灯

boolean isShouldSub = true;

public synchronized void MainThread(int i) {

if (isShouldSub)

try {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

for (int j = 0; j < 5; j++) {

System.out.println(Thread.currentThread().getName() + “:i=” + i + “,j=” + j);

}

isShouldSub = true;

this.notify();

}

public synchronized void SubThread(int i) {

if (!isShouldSub) {

try {

最后的内容

在开头跟大家分享的时候我就说,面试我是没有做好准备的,全靠平时的积累,确实有点临时抱佛脚了,以至于我自己还是挺懊恼的。(准备好了或许可以拿个40k,没做准备只有30k+,你们懂那种感觉吗)

如何准备面试?

1、前期铺垫(技术沉积)

程序员面试其实是对于技术的一次摸底考试,你的技术牛逼,那你就是大爷。大厂对于技术的要求主要体现在:基础,原理,深入研究源码,广度,实战五个方面,也只有将原理理论结合实战才能把技术点吃透。

下面是我会看的一些资料笔记,希望能帮助大家由浅入深,由点到面的学习Java,应对大厂面试官的灵魂追问

这部分内容过多,小编只贴出部分内容展示给大家了,见谅见谅!

  • Java程序员必看《Java开发核心笔记(华山版)》

  • Redis学习笔记

  • Java并发编程学习笔记

四部分,详细拆分并发编程——并发编程+模式篇+应用篇+原理篇

  • Java程序员必看书籍《深入理解 ava虚拟机第3版》(pdf版)

![](https://upload-images.jianshu.io/upload_images/22932333-a154662a3f2c7c87?imageMogr2/auto-

必看视频!获取2024年最新Java开发全套学习资料 备注Java

orient/strip%7CimageView2/2/w/1240)

  • 大厂面试必问——数据结构与算法汇集笔记

其他像Spring,SpringBoot,SpringCloud,SpringCloudAlibaba,Dubbo,Zookeeper,Kafka,RocketMQ,RabbitMQ,Netty,MySQL,Docker,K8s等等我都整理好,这里就不一一展示了。

2、狂刷面试题

技术主要是体现在平时的积累实用,面试前准备两个月的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。

①大厂高频45道笔试题(智商题)

②BAT大厂面试总结(部分内容截图)

③面试总结

3、结合实际,修改简历

程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。
ringBoot,SpringCloud,SpringCloudAlibaba,Dubbo,Zookeeper,Kafka,RocketMQ,RabbitMQ,Netty,MySQL,Docker,K8s等等我都整理好,这里就不一一展示了。

[外链图片转存中…(img-9RwBw8s5-1716448063844)]

2、狂刷面试题

技术主要是体现在平时的积累实用,面试前准备两个月的时间再好好复习一遍,紧接着就可以刷面试题了,下面这些面试题都是小编精心整理的,贴给大家看看。

①大厂高频45道笔试题(智商题)

[外链图片转存中…(img-5HfXYWQ4-1716448063845)]

②BAT大厂面试总结(部分内容截图)

[外链图片转存中…(img-CURqypJm-1716448063845)]

[外链图片转存中…(img-VX1Btn2H-1716448063845)]

③面试总结

[外链图片转存中…(img-PNIiDpfN-1716448063846)]

[外链图片转存中…(img-4nuqzAlQ-1716448063846)]

3、结合实际,修改简历

程序员的简历一定要多下一些功夫,尤其是对一些字眼要再三斟酌,如“精通、熟悉、了解”这三者的区别一定要区分清楚,否则就是在给自己挖坑了。当然不会包装,我可以将我的简历给你参考参考,如果还不够,那下面这些简历模板任你挑选:

[外链图片转存中…(img-1txJWf2M-1716448063846)]

以上分享,希望大家可以在金三银四跳槽季找到一份好工作,但千万也记住,技术一定是平时工作种累计或者自学(或报班跟着老师学)通过实战累计的,千万不要临时抱佛脚。

另外,面试中遇到不会的问题不妨尝试讲讲自己的思路,因为有些问题不是考察我们的编程能力,而是逻辑思维表达能力;最后平时要进行自我分析与评价,做好职业规划,不断摸索,提高自己的编程能力和抽象思维能力。

  • 9
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值