共计 7418 个字符,预计需要花费 19 分钟才能阅读完成。
看看我在 Object 通用办法埋了什么坑
equals 办法用过吧?看看这道题,说说看 equals 办法在前和在后有什么区别?
没什么区别。
错,初学者或者代码打得少的人都会犯这个错。
test1 会间接报空指针异样,你想想看,null.equals 看不起来不就怪怪的吗?空指针怎么可能有办法呢是吧,
拓展: 咱们个别在企业开发中都会将已知的字面量放在 equals,未知的参数放在 equals 前面,这样能够防止空指针,编程老手容易犯这个异样,我 review 过的代码这么实现的,说实话,挺屡次的,不止编程新人,两三年工作教训的都会这么做,切实不应该,
说说看 equlas 跟 == 的区别
equals 办法比拟的是字符串的内容是否相等,而 == 比拟的则是对象地址。
这么答复也是对的,然而,咱们更心愿听到更业余的答复,比方:
首先 Java 中的数据类型能够分为两种,一种是根本数据类型,也称原始数据类型,如 byte,short,char,int,long,float,double,boolean 他们之间的比拟,利用双等号(==), 比拟的是他们的值。
另一种是复合数据类型,包含类,当他们用(==)进行比拟的时候,比拟的是他们在内存中的寄存地址,所以,除非 是同一个 new 进去的对象,他们的比拟后的后果为 true,否则比拟后后果为 false。
而 JAVA 当中所有的类都是继承于 Object 这个基类的,在 Object 中的基类中定义了一个 equals 的办法,这个办法的初始行为是比拟对象的内存地址,但在一些类库当中这个办法被笼罩掉了,如 String,Integer,Date 在这些类当中 equals 有其本身的实现,而不再是比拟类在堆内存中的寄存地址了。
这么答复显的既业余又牛逼,还大气上档次,你学废了吗?
聊聊对 hashCode 和 equals 办法的了解
个别问到这种问题,候选人都能够答复:
如果两个对象 equals 办法相等,则它们的 hashCode 肯定雷同;
如果两个对象的 hashCode 雷同,它们的 equals() 办法则不肯定相等。
而两个对象的 hashCode() 返回值相等不能判断这两个对象是相等的,但两个对象的 hashcode() 返回值不相等则能够断定两个对象肯定不相等。
考查对 hashCode 的了解 那请问 hashCode 有什么作用呢?为什么要这么标准
基本上初学者或者应届生在这一步就被我卡主了,支支吾吾的答复不了多少,基本上都在这里掉分,因为下面的标准答复百度一查一大把,然而对 hashCode 作用有深刻理解的却很少,这道题也能够看出一个人的业余程度。
正确的答复是:
hashCode 的作用实际上是为了进步在散列构造存储中查找的效率,天然只有每个对象的 hashCode 尽可能的不同能力保障散列存储性能的进步,这也是为什么 Object 默认提供 hash 码都是不同的起因。
举个例子:
以 HashSet 为例,要想保障元素不反复则须要调用对象的 equals 办法比拟一次,然而如果这个构造放了很多元素,比方 5000 次,如果没有 hashCode 的话则须要在每次加元素的时候比照 5000 次,而如果有 hashCode 则不一样了,当汇合要增加新的元素的时候先调用 hashCode 办法,这样便能够定位到元素的地址,而无需屡次判断。
考查对 clone 办法的了解看看这道题,后果输入什么?
每次问到这道题,大部分人都是答复 2,小局部人是答复 1。
都错,正确答案是间接报错
为什么?因为 clone 办法是 Object 的 protect 办法,须要子类显示的去重写 clone 办法,并且实现 Cloneable 接口,这是规定。
那么问题来了?加上 Cloneable 接口后呢?到底是 2 还是 1 呢?
这又是我挖的坑,次要为了考查候选人对浅拷贝和深拷贝的了解
最终后果其实是 2,因为间接用 clone 拷贝的时候是一种浅拷贝,最终拷贝对象和原始对象的援用类型援用还是同一个对象。
如果想要实现深拷贝,则须要开发人员本人在 clone 办法内本人进行重写。
拓展: 在企业开发中个别咱们不容许间接用 clone 办法来做拷贝,存在抛出异样的危险,还须要进行类型转换。如果是我 review 到这种代码,都是间接通知共事:在 Effective Java 书上有讲到,最好不要去应用 clone(),咱们能够应用拷贝构造函数或者拷贝工厂来拷贝一个对象,比方这样
总结:咱们都晓得 Java 是面向对象编程的,我的了解实际上就是面对 Object 编程,可能正当的应用和理解原理 equals 和 hashCode 是一个高级程序员必须具备的素养,而对浅拷贝和深拷贝的了解也根本是根底中的根底,心愿看完这系列,大家能够了然于胸,下次遇见这种面试题,间接吹。
看看我在抽象类和接口埋了什么坑
考查候选人编码程度 说说看你对抽象类的了解
抽象类和形象办法都应用 abstract 关键字进行申明,如果一个类中蕴含形象办法,那么这个类必须申明为抽象类,并且抽象类和一般类最大的区别是,抽象类不能被实例化,只能被继承。
bingo, 答案是对的,然而还不够好
下面的是标准答案,轻易一本 Java 书籍都能够看到,然而能够补充下你们对利用的了解,这能够体现你的编码程度到了哪一步,我这边补充我现实的答案:
抽象类能够实现代码的重用,模板办法设计模式是抽象类的一个典型利用,例如咱们游戏的所有流动都要进行一样的初始化,然而初始化的时候须要依据不同流动进行不同性能开启判断,那么就能够定义一个流动的基类,将性能开启判断做成一个形象办法,让所有流动都继承这个基类,而后在子类自行重写性能开启判断。
补充上本人对利用的了解,能够充分体现你的业余,面试官听完,必定是心田一顿尼玛的牛逼。
持续考查候选人编码程度说说看你对接口的了解
接口能够说成是抽象类的一种延长,接口中的所有办法都必须是形象的。实际上,接口中的办法定义默认为 public abstract 类型,接口中的成员变量类型默认为 public static final。
你们懂的,这又是一个规范答复,实际上,不够好,能够补充以下几句话
从 Java8 开始,接口也能够领有默认的办法实现了,为啥 Java 团队要做这个反对呢?
实际上,在 Java 上深耕多年的老司机其实都被接口没有默认实现搞过,保护老本太高了,你想想,如果你当初有 100 个类实现了一个接口,而在这个时候,须要给接口新增一个办法,特么 Java8 之前不容许给接口加默认实现,所以你就得改 100 个类,这特么不得搞出人命吗?
真心话:可能说出对抽象类和接口利用的了解的候选人不多,基本上说进去的我心田都是往牛逼去吹的,大写的服,因为这充分体现一个开发人员对编码方面的思考,你不晓得一个写代码有思考和整洁,而不是只顾实现性能的程序员,主管会多喜爱!!!
真正的间接背的答案说说看抽象类和接口的区别
- 抽象类能够有构造方法,接口中不能有构造方法。
- 抽象类中能够有一般成员变量,接口中没有一般成员变量
- 抽象类中能够蕴含非形象的一般办法,接口中的所有办法必须都是形象的,不能有非形象的一般办法。
- 抽象类中能够蕴含静态方法,接口中不能蕴含静态方法
- 抽象类和接口中都能够蕴含动态成员变量,抽象类中的动态成员变量的拜访类型能够任意,但接口中定义的变量只能是 public static final 类型,并且默认即为 public static final 类型。
- 一个类能够实现多个接口,但只能继承一个抽象类。
这个就是标准答案了,不过咱们面试官比拟心愿能够在答复区别题的时候本人做些拓展答复,将下面接口和抽象类的了解都说一遍,而不是背书一样的答复,切记,答复问题,遇见本人懂的知识点,尽量做拓展,加上本人的了解,一是能够向面试官展现你的业余,二是能够拖时间,尽量避免让面试官想更多难题坑你
总结:看到这里,预计很多人对抽象类和接口都不屑一顾,都是随口能够说出的答案,然而,你认为咱们只是想要听你背书式的答复吗,错了,咱们想晓得的是前面你的拓展和了解,这才能够体现你的编码能力和业余。
看看我在重写和重载里埋了什么坑
给大家来一个口试中超级常见的题 看看以下这道题,说说看后果是啥?
这道题几乎就是了,很多年前我来我司应聘的时候也遇见过这道题,说实话,应届生和高级绕不过这道题,当初间接给大家亮牌:
给大家说说如何了解这种题,了解以下的准则就能够了:
JVM 在调用一个办法时,会优先从本类中查找看是否有对应的办法,如果没有再到父类中查看是否从父类继承来。
如果没有怎么办?那 JVM 就会对参数进行转型,转成父类之后看是否有对应的办法。
总的来说,办法调用的优先级如下:
- this.func(this)
- super.func(this)
- this.func(super)
- super.func(super)
记住这个过程就能够了。
开始挖坑 说说看以下的是不是办法重载?
class TestMain {
public int show(int x) {
return x;
}
public void show(int x) {
System.out.println(x);
}
}
我面试过的大部分高级或者应届都会答复是,不得不说这道题切实太坑了,不开玩笑,你看那堆被这道题埋过的人里边就有我。
千万记住了,重载的定义是:在同一个类中,一个办法与曾经存在的办法名称上雷同,并且参数类型、个数、程序至多有一个不同。这句话里边并没有蕴含着返回值,如果只是返回值不同,其它都雷同基本不算是重载。
当然,idea 是会间接提醒报错的,这也是为什么我没有截 idea 的源码进去给大家看的起因,一看有爆红你们就晓得有问题了。不过还是那句话,这并不意味着 idea 能够检测进去的货色,你就能够不懂,这是根底。
总结:说实话,在口试题中呈现重载和重写那两道题切实是太常见了,百分之九十的应届生或者高级开发都被坑过,所以看完这篇文章记得珍藏啊,并不是你看了就记住了,而是记得在面试前从新看一遍,这可是关系到你 offer 上那个金光闪闪的数字的下限的啊
看看我在反射方面埋了什么坑
终于到了反射了,咱们面试官其实很喜爱这个知识点,能够用它来筛掉一大批的 api 工程师
理解过反射吗?说说看什么是反射?
在运行时,Java 反射,能够获取任意类的名称、package 信息、所有属性、办法、注解、类型、类加载器、事实接口等,并且能够调用任意办法和实例化任意一个类的独享,通过反射咱们能够实现动静拆卸,升高代码的耦合度、实现动静代理等,不过反射的适度应用会重大耗费系统资源。
下面的答复很规范,不过开始深挖了 你刚刚的答复有提到了反射的作用,说说哪里用到了反射机制?
例子很多,比方:
- JDBC 中,利用反射动静加载了数据库驱动程序。
- Web 服务器中利用反射调用了 Sevlet 的服务办法。
- 还有多框架都用到反射机制,注入属性,调用办法,如 Spring 等。
基本上答复几个就能够了,这里因为还没到框架模块,所以先不对 Spring、JDBC 等源码进行深挖,个别都是根底题面完了,才开始挖对框架的应用和源码的了解。
持续挖,咱们面试官很喜爱抓细节,所以最好保障你说的货色你都有肯定的理解,否则嘿嘿嘿你刚刚还说到了动静代理,说说你对动静代理的了解,以及有什么用
动静代理其实就是是运行时动静生成代理类。动静代理的利用有 Spring AOP、测试框架的后端 mock、rpc,Java 注解对象获取等利用。
怎么实现动静代理呢?
目前动静代理能够提供两种,分为 JDK 原生动静代理和 CGLIB 动静代理;
JDK 原生动静代理是基于接口实现的,而 CGLIB 是基于继承以后类的子类实现的,当指标类有接口的时候才会应用 JDK 动静代理,其实是因为 JDK 动静代理无奈代理一个没有接口的类,因为 JDK 动静代理是利用反射机制生成一个实现代理接口的匿名类;
而 CGLIB 是针对类实现代理,次要是对指定的类生成一个子类,并且笼罩其中的办法。
挖一个大坑 你下面有说到 Spring AOP 有用到了动静代理,那你说说看 AOP 用到了哪种形式?
大部分都会答复 JDK 原生动静代理,小局部人会答复 CGLIB。
但其实两者都是错的,这是我挖好的坑,太多候选人都只晓得 AOP 用了动静代理了,然而可能残缺答复进去用了哪种的却寥寥无几,毕竟只有看过源码的人才能答复这个问题,个别可能答复进去的,我这边都会额定加分
理论答案是:在 Spring 中默认应用的是 JDK 动静代理,除非指标类没有实现接口,才会转为 CGLIB 代理,如果想要强行应用 CGLIB 代理免责须要在 Spring 配置文件中退出 <aop:aspectj-autoproxy proxy-target-class="true" />
,
然而在 SpringBoot 中,从 2.0 开始就默认应用 CGLIB 代理。**
说说看反射机制的优缺点
长处:能够动静执行,在运行期间依据业务性能动静执行办法、拜访属性,最大限度施展了 java 的灵活性。毛病:对性能有影响,这类操作总是慢于间接执行 java 代码。
对性能有影响,那请问怎么解决这个问题?
到了这里基本上很多候选人都无法回答了,我见过太多一开始就说性能性能的,可是一说到如何解决,就根本支支吾吾的答复不进去。
记住了,如果聊到性能,记得想好怎么答复优化方面的问题,否则就是本人搬起石头砸本人的脚。
实际上能够从以下几个方面答复:
- 在系统启动时,将反射失去元数据保存起来,应用时,只需从内存中调用即可。
- 尽量用高点的 JDK,因为高版本的虚构机会对执行次数较多的办法进行优化,例如应用 jit 技术,而低版本的那个时候还没实现,
- 能够思考应用高性能的反射库,Spring 外部也有提供一些。
总结:这里其实倡议大家多去玩玩反射,不要只会 api 调用,对于咱们面试官而言,相熟和了解反射是一个中级程序员必备的条件。
看看我在异样和注解方面埋的坑
做为一个 Javer,应该对 Error 和 Exception 很相熟吧,说说看它们的区别
目前来说,能够作为异样抛出的类,分为两种:Error 和 Exception。
而其中 Error 用来示意 JVM 无奈解决的谬误,而后 Exception 也分为两种,别离是:
- 受检异样:须要用 try…catch… 语句捕捉并进行解决,并且能够从异样中复原;
- 非受检异样:是程序运行时谬误,例如除 0 会引发 Arithmetic Exception,此时程序解体并且无奈复原。
说说看什么是注解?以及有什么用
注解提供了一种相似正文的机制,用来将任何的信息或数据与类、办法、或者成员变量等进行关联。
Annontation 像一种修饰符一样,利用于包、类型、构造方法、办法、成员变量、参数及本地变量的申明语句中。
注解的用途很多,举两个最常见的例子:
- 生成文档。这是最常见的,也是 java 最早提供的注解,零碎会在扫描到应用了注解的类后,依据注解信息生成文档。
- 在编译时进行格局查看。如 @override 放在办法前,如果你这个办法并不是笼罩了超类办法,则编译时就能查看出。
Java.lang.annotation 提供了四种元注解,是哪四种?有什么用呢?
JAVA 中有以下几个『元注解』:
- @Target:注解的作用指标
- @Retention:注解的生命周期
- @Documented:注解是否该当被蕴含在 JavaDoc 文档中
- @Inherited:是否容许子类继承该注解
没错,这几个元注解太常见了,然而却很少人可能真的用的好。
说说看 @Target 作用指标有哪些?
对于 @Target 的作用指标有多个指标类型,间接截图如下:
基本上答复几个就能够了,不过记住了,下面的 TYPE 就是指的是类,也就是说这个注解是作用在类上的。
@Retention 注解的生命周期有哪几种?有什么区别?
@Retention 注解的生命周期能够分为以下几种:
- etentionPolicy.SOURCE:以后注解编译期可见,不会写入 class 文件
- RetentionPolicy.CLASS:类加载阶段抛弃,会写入 class 文件
- RetentionPolicy.RUNTIME:永恒保留,能够反射获取
区别在于:
第一种是只能在编译期可见,编译后会被抛弃;
第二种会被编译器编译进 class 文件中,无论是类或是办法,乃至字段,他们都是有属性表的,而 JAVA 虚拟机也定义了几种注解属性表用于存储注解信息,然而这种可见性不能带到办法区,类加载时会予以抛弃;
第三种则是永恒存在的可见性,能够反射获取,基本上用这种居多。
对于注解生命周器的了解能够防止一些坑,还是那句话,基本上注解这块能答复的比拟晦涩的,阐明都是玩过组件或者看过源码的,因为对于开发一个组件来说,注解太罕用了。
送命题,百分之九十的候选人答不上来 父类应用了注解,请问子类继承了这个父类后,是否也携带了这个注解呢?如果没有,要怎么实现这个过程?
这道题很少人会答复的上来,毕竟大家对 @Inherited 这个元注解太生疏了。
在注解上应用元注解 @Inherited,示意该注解会被子类所继承,留神留神,仅针对类哟,成员、办法并不受该元注解的影响
因而,如果想要让子类也继承父类的注解,则须要给注解加上元注解 @Inherited。
拓展:个别高级开发都根本不会用上注解,因为注解更多的是用来写组件用的,咱们项目组这边就很喜爱自定义一些注解来实现组件,因为用起来切实是太难受了。
总结:对于异样这块,Error 和 Exception 是常常会被问到的根底考点,而注解这块是一个可能加分的点,心愿大家别错过这个知识点,学透它,不过记住下面几个坑点,其实也差不多了。
最初
上一篇文章:https://mp.weixin.qq.com/s/F73r_f5YcBOayPdsin4gBg 点赞和浏览量都很高,阐明文章品质是 ok 的,感激大家的反对;
Java 根底系列也根本差不多了,说实话,这两篇文章的坑点,只有你记住了,Java 根底这块基本上没问题了。
后续安顿:
- 【好好面试】Java 汇合系列
- 【好好面试】Java 岗位常考算法
- Caffeine 源码解析
有趣味的关注我一波,Java 面试官带你们跨过一个个的面试坑,保障不亏。
为了感激最近大家的反对,我这边顺便跳了一些 Java 相干的资源,很多专题,比方 JAVA+TCP、Java 反射机制、Java 多线程专题等,都是针对性训练的利器,倡议人手一份。
给文章点个再看,关注公众号,回复:Java 面试 即可拿到资源。
公众号:饭谈编程 原文链接:https://mp.weixin.qq.com/s/F73r_f5YcBOayPdsin4gBg
谢谢点赞反对????????????!