• 有趣的java面试题-基础篇(一)


    一、 运算符 &和&&、|和||的区别

    1. & 按位与操作 只有对应的两个二进制数为1时,结果位才为1
    2. 1&1 = 1
    3. 1&0 = 0
    4. 0&1 = 0
    5. 0&0 = 0
    6. | 按位或操作 有一个为1的时候,结果位就为1
    7. 1|1 = 1
    8. 1|0 = 1
    9. 0|1 = 1
    10. 0|0 = 0

    ​&&和||称之为短路运算符

    1、& 和 && 都可以实现 和 这个功能
            区别:& 两边都运算,而 && 先算 && 左侧,若左侧为false 那么右侧就不运算,判断语句中推荐使用 &&,效率更高
    2、| 和 || 和上面类似
            区别:||只要满足第一个条件,后面的条件就不再判断,而|要对所有的条件进行判断
    在以下判断中,如果只使用 & 或者 | 会出现运行异常

    1. 空指针异常
    2. String s = null;
    3. if(null != s & s.equals(""))
    4. 如果使用 && 的话,当第一个条件满足时,就直接判定为false 第二个条件不会执行,程序则正常运行。

    二、用最有效率的方法计算2乘以8

    这里涉及到计算机基础知识 位运算符 << 左移 和 >> 右移 。

    答案:2<<3

    原理:将一个数左移n位,相当于乘以2的n次方,位运算是CPU直接支持的,所以效率高
    常见的JDK源码里面HashMap的默认容量16


    直接是二进制操作了,表示1左移4位,变成10000,转为10进制也就是16, 直接以二进制形式去运行,效率更高

     相反将一个数右移n位,相当于除以2的n次方

     三、传递两个非0的int数值进去,实现变量交换的方式,有几种方式?

    1. 方式一
    2. public static void test(int a, int b){
    3. ​ System.out.printf("a=%d, b=%d",a,b);
    4. a = a + b;
    5. b = a - b ;
    6. a = a - b;
    7. System.out.printf("\na=%d, b=%d",a,b);
    8. }
    1. 方式二 异或运算 (一个数与另一个数异或两次是其本身, 一个数和自身异或结果是0 )
    2. public static void test2(int a, int b){
    3. System.out.printf("a=%d, b=%d",a,b);​
    4. a = a^b; // a1 = a^b
    5. b = b^a; // b = b^a^b
    6. a = a^b; // a = a1^b = a^b^a​
    7. System.out.printf("\na=%d, b=%d",a,b);
    8. }

    四、java数据类型分类

    8种基础数据类型:byte、short、int、long、float、double、char、boolean
    引用数据类型:除8种数据类型外其他都是引用类型
    String和Enum也是引用类型

    五、++ --运算符

    1. int i = 5;
    2. return i++; 和 return ++i; 返回结果是什么?

    第一个先返回后运行++ 所以返回5, 第二个先运算后返回 所以返回6.

    六、== 和equals的区别

    8个基本数据类型比较 要用 == 判断是否相等
    引用数据类型: == 比较的是内存地址是否一样,不同对象的内存地址不一样,equals本质上也是==,

     但String类重写了equals方法,把内容拆成char类型的数组,先比较长度,如果相同,再逐个比较内容,如果完全相同返回true。

     开发者也可以自己重写equals方法去定义什么条件去判断两个对象是否一样。

    七、新特性考察 try-with-resource 知识点

    考点:编程基础和是否有学习新知识特性

    这是JDK7之后的写法,JDK9⼜进⾏了改良,可以写多个需要关闭的流在try()头中,变化不⼤
    需要关闭的资源只要实现了java.lang.AutoCloseable,就可以⾃动被关闭
    try()⾥⾯可以定义多个资源,它们的关闭顺序是最后在try()定义的资源先关闭

    1. try (
    2. FileInputStream fis = new FileInputStream("C:/Users/38219/Desktop/files/English.txt");
    3. BufferedInputStream bis = new BufferedInputStream(fis);
    4. FileOutputStream fos = new FileOutputStream("C:/Users/38219/Desktop/files/copy.txt");
    5. BufferedOutputStream bos = new BufferedOutputStream(fos);
    6. ) {
    7. int size;
    8. byte[] buf = new byte[1024];
    9. while ((size = bis.read(buf)) != -1) {
    10. bos.write(buf, 0, size);
    11. }
    12. } catch (Exception e) {
    13. e.printStackTrace();
    14. }

    八、文件API和递归考察

     需求:找出某目录下的所有子目录以及子文件并打印到控制台上

    1. public static void main(String[] args) {
    2. recursion("C:/Tom/Myself/sharding-jdbc");
    3. }
    4. public static void recursion(String pathFolder){
    5. //找出某目录下的所有子目录以及子文件并打印到控制台上
    6. List paths = new ArrayList<>();
    7. getAllFilePaths(new File(pathFolder), paths);
    8. for(String path : paths){
    9. System.out.println(path);
    10. }
    11. }
    12. private static void getAllFilePaths(File filePath, List paths) {
    13. File[] files = filePath.listFiles();
    14. if(files == null){
    15. return;
    16. }
    17. for(File f : files){
    18. if(f.isDirectory()){
    19. paths.add(f.getPath());
    20. getAllFilePaths(f,paths);
    21. }else{
    22. paths.add(f.getPath());
    23. }
    24. }
    25. }

    九、 String str = new String("s.yanhui.co"); 创建了几个对象?


    创建一个对象:常量池存在,则直接new一个对象;
    创建两个对象:常量池不存在,则在常量池创建一个对象,也在堆里面创建一个对象

    十、下面是比较什么?输出结果是什么?为什么是这样的结果

    1. String str1= new String("s.yanhui.co");
    2. String str2= "s.yanhui.co";
    3. String str3= "s.yanhui.co";
    4. System.out.println(str1 == str2); //false
    5. System.out.println(str2 == str3); //true
    答案:
    比较引用的内存地址是否一样
    第一个是false: new 创建新的对象会开辟新的空间,所以地址不一样
    第二个是true:都是从常量池里面获取,"s.yanhui.co" 存在于常量池中

    十一、 写出下面代码的各个结果?如果需要两个都为true,应该怎么修改

    1. String s1 = "s.yanhui";
    2. String s2 = s1 + ".co"; //变量 + 常量 = 来自堆
    3. String s3 = "s.yanhui" + ".co"; //常量 + 常量 = 来自常亮池
    4. System.out.println(s2 == "s.yanhui.co");
    5. System.out.println(s3 == "s.yanhui.co");
    答案
    第一条语句打印的结果为false, s2 = s1 + ".co",   //变量+常量=堆
    构建了一个新的string对象,并将对象引用赋予s2变量,常量池中的地址不一样,但是值一样。
    
    第二条语句打印的结果为true,javac编译可以对【字符串常量】直接相加的表达式进行优化,不用等到运行期再去进行加法运算处理,而是直接将其编译成一个这些常量相连的结果.
    
    如果需要第一个输出为true,只需要把变量改为常量即可 fianl String s1 = "s.yanhui";
    不管是new String("XXX")和直接常量赋值, 都会在字符串常量池创建.只是new String("XXX")方式会在堆中创建一个对象去指向常量池的对象, 普通的常量赋值是直接赋值给变量

    十二、String、StringBuffer与StringBuilder的区别?分别在哪些场景下使用?

    1、都是final类, 不允许被继承
    2、都是char[]字符数组实现
    3、String是不可变对象,另外两个是可变的
    4、StringBuilder 效率更快,因为它不需要加锁,不具备多线程安全
    5、StringBuffer里面操作方法用synchronized 修饰,效率相对更低,是线程安全的;
    使用场景:
    1、操作少量的数据用String,但是常改变内容且操作数据多情况下最好不要用 String (比如循环中),因为每次生成中间对象性能会降低
    2、单线程下操作大量的字符串用StringBuilder,虽然线程不安全但是不影响
    3、线程下操作大量的字符串,且需要保证线程安全 则用StringBuffer

    十三、面向对象思想OOP的理解

    答案:
    1、抽象
    	关键词abstract声明的类叫作抽象类,abstract声明的⽅法叫抽象⽅法,⼀个类⾥包含了⼀个或多个抽象⽅法,类就必须指定成抽象类。抽象⽅法属于⼀种特殊⽅法,只含有⼀个声明,没有⽅法体。
    比如抽象支付: pay(金额,订单号),默认实现是本地支付,然后可以有微信支付,支付宝支付,银行卡支付继承抽象支付。一般在工作过程中,很少使用抽象,通常是使用接口的形式去实现。
    2、封装
            封装是把过程和数据包围起来,对数据的访问只能通过已定义的接⼝即⽅法。在java中通过关键字private,protected和public实现封装。封装把对象的所有组成部分组合在⼀起,封装定义程序如何引⽤对象的数据,封装实际上使⽤⽅法将类的数据隐藏起来,控制⽤户对类的修改和访问数据的程度。 适当的封装可以让代码更容易理解和维护,也加强了代码的安全性。
    3、继承
    	⼦类继承⽗类的特征和⾏为,使得⼦类对象具有⽗类的⽅法和属性,⽗类也叫基类,具有公共的⽅法和属性
            动物<-猫
            动物<-狗
    
    1. abstract class animals{
    2. }
    3. cats extends animals{
    4. }
    5. dogs extends animals{
    6. }
    4、多态
    	同⼀个⾏为具有多个不同表现形式的能⼒
            优点:减少耦合、灵活可拓展
            ⼀般是继承类或者重写⽅法实现

    十四、Overload和Override的区别?

    重载Overload:表示同一个类中可以有多个名称相同的方法,但这些方法的参数列表各不相同,参数个数或类型不同
    
    
    1. public void test(String value){
    2. }
    3. public void test(Integer value){
    4. }
    重写Override:表示子类中的方法可以与父类中的某个方法的名称和参数完全相同。
    1. public class Test {
    2. public void test(String value){
    3. System.out.println("test");
    4. }
    5. }
    6. public class Test2 extends Test{
    7. @Override
    8. public void test(String value) {
    9. System.out.println("test's child");
    10. }
    11. }

    十五、接口是否可以继承接口?接口是否支持多继承?类是否支持多继承?接口里面是否可以有方法实现

    1、接⼝⾥可以有静态⽅法和⽅法体
    2、接⼝中所有的⽅法必须是抽象⽅法(JDK8之后就不是)
    3、接⼝不是被类继承了,⽽是要被类实现
    4、接⼝⽀持多继承, 类不⽀持多个类继承
    5、⼀个类只能继承⼀个类,但是能实现多个接⼝, 接⼝能继承另⼀个或多个接⼝,接⼝的继承使⽤extends关键字,和类继承⼀样

    十六、是否了解JDK8里面接口新特性?

    1、interface中可以有static⽅法,但必须有⽅法实现体,该⽅法只属于该接⼝,接⼝名直接调⽤ 该⽅法
    2、接⼝中新增default关键字修饰的⽅法,default⽅法只能定义在接⼝中,可以在⼦类或⼦接⼝ 中被重写default定义的⽅法必须有⽅法体
    3、⽗接⼝的default⽅法如果在⼦接⼝或⼦类被重写,那么⼦接⼝实现对象、⼦类对象,调⽤该 ⽅法,以重写为准
    4、本类、接⼝如果没有重写⽗类(即接⼝)的default⽅法,则在调⽤default⽅法时,使⽤⽗类(接口) 定义的default⽅法逻辑

  • 相关阅读:
    windows下OpenNN的编译与使用
    【三】ElasticSearch 索引操作
    【LeetCode热题100】--169.多数元素
    c++builder 6.0中OnCliked= fun实现的原理
    Linux学习-20-yum介绍,yum源配置
    Blog2:nchu-software-oop-2022-4+5+期中
    复习一下dp动规
    基于selenium的pyse自动化测试框架
    自己动手从零写桌面操作系统GrapeOS系列教程——20.汇编语言读硬盘实战
    hcip--复习第二天作业
  • 原文地址:https://blog.csdn.net/Swing_yue/article/details/126646133