Java 笔试:常见题目总结

{

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 {

this.wait();

} catch (InterruptedException e) {

e.printStackTrace();

}

}

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

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

}

isShouldSub = false;

this.notify();

}

}

}

执行结果:

···

Thread-0:i=48,j=7

Thread-0:i=48,j=8

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
println(Thread.currentThread().getName() + “:i=” + i + “,j=” + j);

}

isShouldSub = false;

this.notify();

}

}

}

执行结果:

···

Thread-0:i=48,j=7

Thread-0:i=48,j=8

最后

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。

因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

[外链图片转存中…(img-Na3xZh0L-1715707162484)]

[外链图片转存中…(img-0iJCBnuh-1715707162484)]

[外链图片转存中…(img-qCFkww1J-1715707162485)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!

如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值