牛客java选择题每日打卡Day12
Posted 京与旧铺
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客java选择题每日打卡Day12相关的知识,希望对你有一定的参考价值。
牛客java选择题每日打卡Day12
👩💻博客主页:京与旧铺的博客主页
✨欢迎关注🖱点赞🎀收藏⭐留言✒
🔮本文由京与旧铺原创,csdn首发!
😘系列专栏:java学习
👕参考网站:牛客网
💻首发时间:🎞2022年6月13日🎠
🎨你做三四月的事,八九月就会有答案,一起加油吧
🀄如果觉得博主的文章还不错的话,请三连支持一下博主哦
🎧最后的话,作者是一个新人,在很多方面还做的不好,欢迎大佬指正,一起学习哦,冲冲冲
💬推荐一款模拟面试、刷题神器👉点击进入网站
🛒导航小助手🎪
文章目录
😥选择题1
以下各类中哪几个是线程安全的?( )
正确答案: B C D 你的答案: B C D (正确)
ArrayList
Vector
Hashtable
Stack
在集合框架中,有些类是线程安全的,这些都是jdk1.1中的出现的。在jdk1.2之后,就出现许许多多非线程安全的类。 下面是这些线程安全的同步的类:
vector:就比arraylist多了个同步化机制(线程安全),因为效率较低,现在已经不太建议使用。在web应用中,特别是前台页面,往往效率(页面响应速度)是优先考虑的。
statck:堆栈类,先进后出
hashtable:就比hashmap多了个线程安全
enumeration:枚举,相当于迭代器
除了这些之外,其他的都是非线程安全的类和接口。
😫选择题2
下面的对象创建方法中哪些会调用构造方法 ()?
正确答案: A C 你的答案: A C D (错误)
new语句创建对象
调用Java.io.ObjectInputStream的readObject方法
java反射机制使用java.lang.Class或java.lang.reflect.Constructor的newInstance()方法
调用对象的clone()方法
构造函数的作用是完成对象的初始化。当程序执行到new操作符时, 首先去看new操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化。而选项B、D中,对象的初始化并不是通过构造函数完成的,而是读取别的内存区域中的对象的各个域来完成。
😣选择题3
下面有关maven和ant的描述,描述错误的是?
正确答案: C 你的答案: C (正确)
Ant 没有正式的约定如一个一般项目的目录结构,你必须明确的告诉 Ant 哪里去找源代码
Maven 拥有约定,因为你遵循了约定,它已经知道你的源代码在哪里
maven和ant都有“生命周期”的概念,当你输入一个命令后,maven或者ant会执行一系列的有序的步骤,直到到达你指定的生命周期
Ant构建文件默认命名为build.xml,Maven默认构建文件为pom.xml
Ant和Maven都是基于Java的构建(build)工具。理论上来说,有些类似于(Unix)C中的make ,但没有make的缺陷。Ant是软件构建工具,Maven的定位是软件项目管理和理解工具。
Ant特点 ›
没有一个约定的目录结构 ›必须明确让ant做什么,什么时候做,然后编译,打包 ›没有生命周期,必须定义目标及其实现的任务序列 ›没有集成依赖管理
Maven特点
›拥有约定,知道你的代码在哪里,放到哪里去 ›拥有一个生命周期,例如执行 mvn install 就可以自动执行编译,测试,打包等构建过程 ›只需要定义一个pom.xml,然后把源码放到默认的目录,Maven帮你处理其他事情 ›拥有依赖管理,仓库管理
😋选择题4
下面叙述错误的是 ( )
正确答案: C 你的答案: B (错误)
一个类可以有多个构造方法
最终类不能派生子类,最终方法不能被覆盖
如果一个类中没有定义构造方法,则Java在生成这个类的实例时不会调用构造方法。
数组一旦创建之后,就不能再改变其长度
A.一个类可以有多个构造方法,实际上就是方法的重载,正确
B.用final修饰的类不能被继承,方法不能被覆盖,正确
C.如果没有构造方法,编译器会自动添加一个空参构造方法,错误
D.由源码可知,数组内部采用字符数组存储,该字符数组用final修饰,长度一旦确定不可再变,正确
😀选择题5
try括号里有return语句, finally执行顺序
正确答案: B 你的答案: C (错误)
不执行finally代码
return前执行
return后执行
选项B;我相信仔细看的话,每一本Java书都有讲过。“假设利用 return 语句从 try 语句块中退出。在方法返回前,finally子句的内容将被执行。如果 finally 子句中也有一个 return 语句,这个返回值将会覆盖原始的返回值。”
public static void main(String[] args)
int k = f_test();
System.out.println(k);
public static int f_test()
int a = 0;
try
a = 1;
return a;
finally
System.out.println("It is in final chunk.");
a = 2;
return a;
输出:
It is in final chunk.
2
🥱选择题6
有变量int i = 0; int a = i++; int b = ++a; int c = a+b; int d = (a == 1)?b:c; 请问a和d的值分别是多少?( )。
正确答案: D 你的答案: B (错误)
2,4
1, 4
1, 2
1,1
int i = 0; //i=0
int a = i++; //a=i,a=0,i++,i=1
int b = ++a; //a++,a=1,b=a,b=1
int c = a+b;//c=2
int d = (a == 1)?b:c;//a==1,d=b,d=1
🤔选择题7
以下哪种方式实现的单例是线程安全的
正确答案: A B C D 你的答案: A B D (错误)
枚举
静态内部类
双检锁模式
饿汉式
一、单例模式的定义
定义: 确保一个类只有一个实例,并提供该实例的全局访问点。
这样做的好处是:有些实例,全局只需要一个就够了,使用单例模式就可以避免一个全局使用的类,频繁的创建与销毁,耗费系统资源。
二、单例模式的设计要素
- 一个私有构造函数 (确保只能单例类自己创建实例)
- 一个私有静态变量 (确保只有一个实例)
- 一个公有静态函数 (给使用者提供调用方法)
简单来说就是,单例类的构造方法不让其他人修改和使用;并且单例类自己只创建一个实例,这个实例,其他人也无法修改和直接使用;然后单例类提供一个调用方法,想用这个实例,只能调用。这样就确保了全局只创建了一次实例。
三、单例模式的6种实现及各实现的优缺点
(一)懒汉式(线程不安全)
实现:
public class Singleton
private static Singleton uniqueInstance;
private Singleton()
public static Singleton getUniqueInstance()
if (uniqueInstance == null)
uniqueInstance = new Singleton();
return uniqueInstance;
说明: 先不创建实例,当第一次被调用时,再创建实例,所以被称为懒汉式。
优点: 延迟了实例化,如果不需要使用该类,就不会被实例化,节约了系统资源。
缺点: 线程不安全,多线程环境下,如果多个线程同时进入了 if (uniqueInstance == null) ,若此时还未实例化,也就是uniqueInstance == null,那么就会有多个线程执行 uniqueInstance = new Singleton(); ,就会实例化多个实例;
(二)饿汉式(线程安全)
实现:
public class Singleton
private static Singleton uniqueInstance = new Singleton();
private Singleton()
public static Singleton getUniqueInstance()
return uniqueInstance;
说明: 先不管需不需要使用这个实例,直接先实例化好实例 (饿死鬼一样,所以称为饿汉式),然后当需要使用的时候,直接调方法就可以使用了。
优点: 提前实例化好了一个实例,避免了线程不安全问题的出现。
缺点: 直接实例化好了实例,不再延迟实例化;若系统没有使用这个实例,或者系统运行很久之后才需要使用这个实例,都会操作系统的资源浪费。
(三)懒汉式(线程安全)
实现:
public class Singleton
private static Singleton uniqueInstance;
private static singleton()
private static synchronized Singleton getUinqueInstance()
if (uniqueInstance == null)
uniqueInstance = new Singleton();
return uniqueInstance;
说明: 实现和 线程不安全的懒汉式 几乎一样,唯一不同的点是,在get方法上 加了一把 锁。如此一来,多个线程访问,每次只有拿到锁的的线程能够进入该方法,避免了多线程不安全问题的出现。
优点: 延迟实例化,节约了资源,并且是线程安全的。
缺点: 虽然解决了线程安全问题,但是性能降低了。因为,即使实例已经实例化了,既后续不会再出现线程安全问题了,但是锁还在,每次还是只能拿到锁的线程进入该方***使线程阻塞,等待时间过长。
(四)双重检查锁实现(线程安全)
实现:
public class Singleton
private volatile static Singleton uniqueInstance;
private Singleton()
public static Singleton getUniqueInstance()
if (uniqueInstance == null)
synchronized (Singleton.class)
if (uniqueInstance == null)
uniqueInstance = new Singleton();
return uniqueInstance;
说明: 双重检查数相当于是改进了 线程安全的懒汉式。线程安全的懒汉式 的缺点是性能降低了,造成的原因是因为即使实例已经实例化,依然每次都会有锁。而现在,我们将锁的位置变了,并且多加了一个检查。 也就是,先判断实例是否已经存在,若已经存在了,则不会执行判断方法内的有锁方法了。 而如果,还没有实例化的时候,多个线程进去了,也没有事,因为里面的方法有锁,只会让一个线程进入最内层方法并实例化实例。如此一来,最多最多,也就是第一次实例化的时候,会有线程阻塞的情况,后续便不会再有线程阻塞的问题。
为什么使用 volatile 关键字修饰了 uniqueInstance 实例变量 ?
uniqueInstance = new Singleton(); 这段代码执行时分为三步:
- 为 uniqueInstance 分配内存空间
- 初始化 uniqueInstance
- 将 uniqueInstance 指向分配的内存地址
正常的执行顺序当然是 1>2>3 ,但是由于 JVM 具有指令重排的特性,执行顺序有可能变成 1>3>2。
单线程环境时,指令重排并没有什么问题;多线程环境时,会导致有些线程可能会获取到还没初始化的实例。
例如:线程A 只执行了 1 和 3 ,此时线程B来调用 getUniqueInstance(),发现 uniqueInstance 不为空,便获取 uniqueInstance 实例,但是其实此时的 uniqueInstance 还没有初始化。
解决办法就是加一个 volatile 关键字修饰 uniqueInstance ,volatile 会禁止 JVM 的指令重排,就可以保证多线程环境下的安全运行。
优点: 延迟实例化,节约了资源;线程安全;并且相对于 线程安全的懒汉式,性能提高了。
缺点: volatile 关键字,对性能也有一些影响。
(五)静态内部类实现(线程安全)
实现:
public class Singleton
private Singleton()
private static class SingletonHolder
private static final Singleton INSTANCE = new Singleton();
public static Singleton getUniqueInstance()
return SingletonHolder.INSTANCE;
说明: 首先,当外部类 Singleton 被加载时,静态内部类 SingletonHolder 并没有被加载进内存。当调用 getUniqueInstance() 方法时,会运行 return SingletonHolder.INSTANCE; ,触发了 SingletonHolder.INSTANCE ,此时静态内部类 SingletonHolder 才会被加载进内存,并且初始化 INSTANCE 实例,而且 JVM 会确保 INSTANCE 只被实例化一次。
优点: 延迟实例化,节约了资源;且线程安全;性能也提高了。
(六)枚举类实现(线程安全)
实现:
public enum Singleton
INSTANCE;
//添加自己需要的操作
public void doSomeThing()
说明: 默认枚举实例的创建就是线程安全的,且在任何情况下都是单例。
优点: 写法简单,线程安全,天然防止反射和反序列化调用。
- 防止反序列化
**序列化:**把java对象转换为字节序列的过程;
反序列化: 通过这些字节序列在内存中新建java对象的过程;
说明: 反序列化 将一个单例实例对象写到磁盘再读回来,从而获得了一个新的实例。
我们要防止反序列化,避免得到多个实例。
枚举类天然防止反序列化。
其他单例模式 可以通过 重写 readResolve() 方法,从而防止反序列化,使实例唯一重写 readResolve() :
private Object readResolve() throws ObjectStreamException
return singleton;
四、单例模式的应用场景
应用场景举例:
- 网站计数器。
- 应用程序的日志应用。
- Web项目中的配置对象的读取。
- 数据库连接池。
- 多线程池。
- …
使用场景总结:
- 频繁实例化然后又销毁的对象,使用单例模式可以提高性能。
- 经常使用的对象,但实例化时耗费时间或者资源多,如数据库连接池,使用单例模式,可以提高性能,降低资源损坏。
类天然防止反序列化。**
其他单例模式 可以通过 重写 readResolve() 方法,从而防止反序列化,使实例唯一重写 readResolve() :
private Object readResolve() throws ObjectStreamException
return singleton;
四、单例模式的应用场景
应用场景举例:
- 网站计数器。
- 应用程序的日志应用。
- Web项目中的配置对象的读取。
- 数据库连接池。
- 多线程池。
- …
使用场景总结:
- 频繁实例化然后又销毁的对象,使用单例模式可以提高性能。
- 经常使用的对象,但实例化时耗费时间或者资源多,如数据库连接池,使用单例模式,可以提高性能,降低资源损坏。
- 使用线程池之类的控制资源时,使用单例模式,可以方便资源之间的通信。
结束语🏆🏆🏆
🔥推荐一款模拟面试、刷题神器网站
点击跳转进入网站点击进入
1、算法篇(398题):面试必刷100题、算法入门、面试高频榜单
2、SQL篇(82题):快速入门、SQL必知必会、SQL进阶挑战、面试真题
3、大厂笔试真题:字节跳动、美团、百度、腾讯…
秋招冲刺-每日打卡应届生JAVA岗-每日5道高频面试题Day5- 异常类篇
文章大纲
一: 前言 |
- 大家好,这里是IT学习日记,一个非双一流大学毕业的深漂族,年少曾憧憬大厂,面试过许多家公司,也曾踩过无数坑,深知面试技巧和知识广度与深度对一个应届生乃至工作多年的开发者的重要性。
- 故特意收集了各个公司、大厂的面试高频题,通过每天打卡的方式,和大家一起记录和学习,希望能够帮助到应届生和开发者们少走弯路,一起冲向大厂!!!
二: 面试题目 |
一: Error和Exception有什么区别?
(一): 为什么JAVA存在这种异常机制
异常机制是指当程序出现错误时,该如何处理,它给程序提供了一个安全的退出通道,就跟我们大楼的安全通道类似,当出现火灾或者不可控的情况时,人们可以通过安全通道逃生。
(二): 程序错误的分类
主要分为三种既编译时错误、运行时错误、逻辑错误。
1、编译时错误: 它指的是程序的编写不符合对应程序的语言语法,编译器会提示异常信息,且这些异常必须处理,否则程序无法被运行。
2、运行时错误: 它指的是程序运行时,运行环境发现程序不合理而抛出的错误,它主要是开发考虑不够细致导致,这种错误只能依靠异常机制来进行处理,而且能否预防程序在运行时出现错误也是一个开发者是否考虑周全,经验是否丰富的考察标准。
3、逻辑错误: 它指的是程序的运行流程和结果跟开发者预测的不一样,出现这种问题可能是开发没有考虑周全导致。
(三): 异常家族的结构
1、Throwable: 可抛出的,它是JAVA中所有异常的一个父类,用来定义所有可以作为异常被抛出来的类,Exception(异常)和Error(错误)是它的子类,Exception(异常)和Error(错误)的最大区别是异常可以通过异常处理机制在程序中处理,而错误则是没法通过程序处理。
Throwable常用方法:
2、Exception(异常): Throwable的子类之一,表示程序可以处理的异常,它又分为两类即编译时异常(CheckedException)和运行时异常(RuntimeException),这类异常应该尽可能在程序去处理它们。
- 编译时异常: Exception中除了RuntimeException以外的异常,这种异常是必须处理的,否则编译程序不过,程序无法被执行,常见的如:IOException、SQLException等等。
- 运行时异常: 这类异常编译器是无法检测的,一般是有程序的逻辑错误引起的,在程序中可以通过异常捕获机制来进行处理,处理这类异常主要看开发者是否考虑全面,开发经验是否丰富可以提前预测代码可能出现异常,常见的有:空指针异常,数组下标越界等。
3、Error(错误): Throwable的子类之一,表示无法通过程序处理的的错误,通常出现的原因和开发者无关,一般是由虚拟机JVM引起的,常见的如:VirtulMachineError、AWTError等等。
(四): 常见的异常有哪些
一: 常见的编译时异常
1、IOException: IO操作输入流或者输出流可能出现的异常
2、FileNotFoundException: 文件未找到异常
3、EOFException: 文件已结束异常
二: 常见的运行时时异常
1、NullPointerException: 空指针异常,当对象为null对,调用对象的某个方法时会抛出
2、ArrayIndexOutOfBoundsException: 数组下标越界异常,当访问的数组下标是负数或者大于数组的大小时会抛出该异常
3、ArithmeticException: 算术条件异常,如分母为0时的除法运算
4、SecurityException: 安全性异常
5、IllegalArgumentException: 非法参数异常
二: Java语言如何处理异常,关键字:try、catch、finally、throws、throw分别有什么作用?
JAVA中是通过面向对象的方式来处理异常,将不同的异常分为不同的类,在JAVA中,每一个异常都是一个对象,它们都属性Throwable的子类或者其子类的实例,如果某个地方出现了异常,则在该处抛出一个异常对象,这个异常对象中包含了异常信息,开发者可以通过异常处理机制对异常进行处理。
,在JAVA中异常处理机制主要是通过try、catch、finally、throws、throw这五个关键字来进行处理的。
如果某个方法过程中可能会throw出一个异常,那么这个代码范围可以使用try…catch包围起来,当出现异常的时候,则会进入到catch的逻辑中,用户可以根据自己的需要去进行相应的错误日志记录等,如果这个代码有资源在执行完成后需要释放,可以使用finally关键字来存放释放资源的逻辑。
1、try关键字:
主要用于包围可能存在异常情况的代码段,并不是范围越大越好,如果可能,尽量将包围的范围缩小,因为不出异常情况下效率是没有多大影响,但是如果出现异常,那么范围越大则效率越低,因为被try包围的代码快,会阻止对JAVA的优化如指令重排序。
2、catch关键字:
catch子句紧跟在try块后面,用来指定你想要捕获的异常的类型,进行异常日志的记录等逻辑处理。
3、finally关键字:
finally为确保一段代码不管发生什么异常状况都要被执行,除非虚拟机退出如:exit(0),常用于资源的释放。
4、throw关键字:
throw语句用来明确地抛出一个异常,如某个代码段已经会出现某个问题,但是你并不像在这里进行处理,此时可以通过throw关键字进行异常抛出,让调用者去处理。
5、throws关键字:
throws用来声明一个方法可能抛出的各种异常,用于方法声明处,表示这个方法中可能抛出的异常,需要调用者进行处理或者晚上抛出这些异常。
三: 在程序中遇到异常在所难免,你有什么好的处理异常经验?
1、异常不要用来做流程控制、条件控制,因为异常设计的初衷是解决程序运行中的各种意外情况,且异常的处理效率比条件判断方式要低很多(阿里巴巴开发规范手册)
2、代码划分为可能出现异常代码块和不可能出现异常代码块,可能出现异常的代码块使用try…catch异常捕获机制进行处理,而不应该对一大段代码进行try…catch,这不仅是不负责任的表现,同时出现异常时也很难定位到问题。
3、捕获异常是为了处理它,不要捕获了却什么都不处理而抛弃之,如果不想处理它,请
将该异常抛给它的调用者。最外层的业务使用者,必须处理异常,将其转化为用户可以理解的
内容。
4、每个方法的异常最好有相应的文档描述,便于日后代码维护。
5、在事务的场景下,抛出异常被 catch 后,如果需要回滚,一定要注意手动回滚事务。
6、finally 块必须对资源对象、流对象进行关闭,有异常也要做 try-catch。如果 JDK7 及以上,可以使用 try-with-resources 方式.
PS:上面的经验参考自《阿里巴巴开发规范手册-泰山版》,有需要的可以私信我。
四: final、finally、finalize的区别?
- final:修饰符(关键字)可以用于修饰类、方法、变量。分别表达的含义是类不可以被继承、方法不能被重写、被修饰的变量是常量,需要在声明的时候给定初始值。
- finally:通常放在try…catch…的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。
- finalize:Object类中定义的方法,Java中允许使用finalize()方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize()方法可以整理系统资源或者执行其他清理工作。
追问1、try-catch-finally需要同时都存在?那个可以省略?
不需要同时存在,try-catch-finally可以划分为try-catch、try-finally、try-catch-finally三种结构。
try-catch结构主要是为了捕获可能出现的异常并进行相应的异常处理。
try-finally结构主要是为了捕获异常时正确释放资源或者关闭流
try-catch-finally结构主要是为了处理既要捕获异常处理异常,也要在出现异常时关闭流和释放对应资源的场景
五: NoClassDefFoundError和 ClassNotFoundException区别是什么?
NoClassDefFoundError是这一种Error类型错误,它是由JVM异常而引起的,无法通过程序去处理的,所以这个错误我们不应该通过异常处理机制去处理。
ClassNotFoundException是Exception的一种子类,它是一种运行时异常,可以通过异常处理机制进行处理,常见的引起原因如下:
1、使用 Class.forName, ClassLoader.loadClass 或 ClassLoader.findSystemClass 动态加载类到内存的时候,根据类路径没有找到对应的类,则抛出该异常。
2、某个类已经由一个类加载器加载至内存中,另一个加载器又尝试去加载它,因为类只能被一个累加载器加载一次,对类加载流程感兴趣的可以看之前的一篇文字: 《诚意满满,准备跳槽和应届生必备JAVA面试知识点!》。
追问1、try-finally结构中,如果在try和finally中分别有return,则具体的返回情况会是什么?
情况1: 如果返回的类型是值类型(常见的JAVA八大类型),那么当try和finally都有return语句时,返回的是try中return的值。
因为基本数据类型是存储在栈中的,是值存于底,在try执行return时,会先将return的值存储到局部变量表中,执行完finally中语句时就返回局部变量表中的值,而不是finally中修改后的值
情况2: 如果返回的类型是引用类型,那么返回的值则是最后finally中设置的值,因为它们指向的是同一个引用地址,所以最后修改的值就是引用地址中最新的值。
追问2、try-catch-finally结构中,如果在catch中return了,finally中的代码是否还会被执行?
会的,finally中的代码会在catch结构return之前被执行,但是不推荐在catch中做return操作。
每日小结
不积跬步,无以至千里;不积小流,无以成江海。今天播种努力的种子,总会有一天发芽!
欢迎大家关注,如果觉得文章对你有帮助,不要忘记一键三连哦,你的支持是我创作更加优质文章的动力,希望大家都能够早日拿到心仪的Offer,有任何面试问题可以私信我,欢迎大家投稿面试题目哦!
以上是关于牛客java选择题每日打卡Day12的主要内容,如果未能解决你的问题,请参考以下文章
秋招冲刺-每日打卡应届生JAVA岗-每日5道高频面试题Day3-基础篇