当前位置: 首页 > news >正文

最最最常见的Java面试题总结-第一周

这里会分享一些出现频率极其极其高的面试题,初定周更一篇,什么时候更完什么时候停止。

Github地址:https://github.com/Snailclimb/Java-Guide/blob/master/面试必备/最最最常见的Java面试题总结/第一周(2018-8-7).md

一 Java中的值传递和引用传递(非常重要)

首先要明确的是:“对象传递(数组、类、接口)是引用传递,原始类型数据(整型、浮点型、字符型、布尔型)传递是值传递。”

那么什么是值传递和应用传递呢?

值传递是指对象被值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。(因为值传递的时候,实际上是将实参的值复制一份给形参。)

引用传递是指对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有的对象上。(因为引用传递的时候,实际上是将实参的地址值复制一份给形参。)

有时候面试官不是单纯问你“Java中是值传递还是引用传递”是什么啊,骚年?而是给出一个例子,然后让你写出答案,这种也常见在笔试题目中!所以,非常重要了,请看下面的例子:

值传递和应用传递实例

1. 值传递

public static void main(String[] args) {
    int num1 = 10;
    int num2 = 20;

    swap(num1, num2);

    System.out.println("num1 = " + num1);
    System.out.println("num2 = " + num2);
}

public static void swap(int a, int b) {
    int temp = a;
    a = b;
    b = temp;

    System.out.println("a = " + a);
    System.out.println("b = " + b);
}

结果:

a = 20
b = 10
num1 = 10
num2 = 20

解析:

在swap方法中,a、b的值进行交换,并不会影响到num1、num2。因为,a、b中的值,只是从num1、num2的复制过来的。
也就是说,a、b相当于num1、num2的副本,副本的内容无论怎么修改,都不会影响到原件本身。

2. 引用传递

public static void main(String[] args) {
    int[] arr = {1,2,3,4,5};

    change(arr);

    System.out.println(arr[0]);
}

public static void change(int[] array) {
//将数组的第一个元素变为0
    array[0] = 0;
}

结果:

1
0

解析:

无论是主函数,还是change方法,操作的都是同一个地址值对应的数组。 。因此,外部对引用对象的改变会反映到所有的对象上。

一些特殊的例子

1. StringBuffer类型传递

    // 测试引用传递:StringBuffer
    @org.junit.Test
    public void method1() {
        StringBuffer str = new StringBuffer("公众号:Java面试通关手册");
        System.out.println(str);
        change1(str);
        System.out.println(str);
    }

    public static void change1(StringBuffer str) {
        str = new StringBuffer("abc");//输出:“公众号:Java面试通关手册”
        //str.append("欢迎大家关注");//输出:公众号:Java面试通关手册欢迎大家关注
        //str.insert(3, "(编程)");//输出:公众号(编程):Java面试通关手册
        
    }

结果:

公众号:Java面试通关手册
公众号:Java面试通关手册

解析:

很多要这个时候要问了:StringBuffer创建的明明也是对象,那为什么输出结果依然是原来的值呢?

因为在change1方法内部我们是新建了一个StringBuffer对象,所以str指向了另外一个地址,相应的操作也同样是指向另外的地址的。

那么,如果将change1方法改成如下图所示,想必大家应该知道输出什么了,如果你还不知道,那可能就是我讲的有问题了,我反思(开个玩笑,上面程序中已经给出答案):

    public static void change1(StringBuffer str) {

        str.append("欢迎大家关注");
        str.insert(3, "(编程)");
        
    }

2. String类型传递

    // 测试引用传递:Sring
    @org.junit.Test
    public void method2() {
        String str = new String("公众号:Java面试通关手册");
        System.out.println(str);
        change2(str);
        System.out.println(str);
    }

    public static void change2(String str) {
        // str="abc"; //输出:公众号:Java面试通关手册
        str = new String("abc"); //输出:公众号:Java面试通关手册
    }

结果:

公众号:Java面试通关手册
公众号:Java面试通关手册

可以看到不论是执行str="abc;"还是str = new String("abc");str的输出的值都不变。
按照我们上面讲“StringBuffer类型传递”的时候说的,str="abc;"应该会让str的输出的值都不变。为什么呢?因为String在创建之后是不可变的。

3. 一道类似的题目

下面的程序输出是什么?

public class Demo {
    public static void main(String[] args) {
        Person p = new Person("张三");

        change(p);

        System.out.println(p.name);
    }

    public static void change(Person p) {
        Person person = new Person("李四");
        p = person;
    }
}

class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }
}

很明显仍然会输出张三。因为change方法中重新创建了一个Person对象。

那么,如果把 change方法改为下图所示,输出结果又是什么呢?

    public static void change(Person p) {
        p.name="李四";
    }

答案我就不说了,我觉得大家如果认真看完上面的内容之后应该很很清楚了。

二 ==与equals(重要)

== : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)

equals() : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:

  • 情况1:类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
  • 情况2:类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。

举个例子:

public class test1 {
    public static void main(String[] args) {
        String a = new String("ab"); // a 为一个引用
        String b = new String("ab"); // b为另一个引用,对象的内容一样
        String aa = "ab"; // 放在常量池中
        String bb = "ab"; // 从常量池中查找
        if (aa == bb) // true
            System.out.println("aa==bb");
        if (a == b) // false,非同一对象
            System.out.println("a==b");
        if (a.equals(b)) // true
            System.out.println("aEQb");
        if (42 == 42.0) { // true
            System.out.println("true");
        }
    }
}

说明:

  • String中的equals方法是被重写过的,因为object的equals方法是比较的对象的内存地址,而String的equals方法比较的是对象的值。
  • 当创建String类型的对象时,虚拟机会在常量池中查找有没有已经存在的值和要创建的值相同的对象,如果有就把它赋给当前引用。如果没有就在常量池中重新创建一个String对象。

三 hashCode与equals(重要)

面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?”

hashCode()介绍

hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode() 函数。

散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)

为什么要有hashCode

我们以“HashSet如何检查重复”为例子来说明为什么要有hashCode:

当你把对象加入HashSet时,HashSet会先计算对象的hashcode值来判断对象加入的位置,同时也会与其他已经加入的对象的hashcode值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同hashcode值的对象,这时会调用equals()方法来检查hashcode相等的对象是否真的相同。如果两者相同,HashSet就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head fist java》第二版)。这样我们就大大减少了equals的次数,相应就大大提高了执行速度。

hashCode()与equals()的相关规定

  1. 如果两个对象相等,则hashcode一定也是相同的
  2. 两个对象相等,对两个对象分别调用equals方法都返回true
  3. 两个对象有相同的hashcode值,它们也不一定是相等的
  4. 因此,equals方法被覆盖过,则hashCode方法也必须被覆盖
  5. hashCode()的默认行为是对堆上的对象产生独特值。如果没有重写hashCode(),则该class的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

写在最后

推荐一个自己的开源的后端文档

Java-Guide: Java面试通关手册(Java学习指南)Java Interview Customs Manual (Java Study Guide)。star:1.4k。

Github地址:https://github.com/Snailclimb/Java-Guide

文档定位:一个专门为Java后端工程师准备的开源文档,相信不论你是Java新手还是已经成为一名Java工程师都能从这份文档中收获到一些东西。

面试相关资源免费分享

Java最新17年面试笔试题+Java面试宝典+简历模版就业指导笔记视频+
Java校招面试 Google面试官亲授+Java[BAT]面试必备+2017Google面试官亲授 java校招面试

关注微信公众号“Java面试通关手册”回复“面试”即可免费领取!

参考:

https://blog.csdn.net/zhzhao999/article/details/53449504

https://www.cnblogs.com/skywang12345/p/3324958.html

https://www.cnblogs.com/skywang12345/p/3324958.html

https://www.cnblogs.com/Eason-S/p/5524837.html

如果想要获取更多我的原创文章以及优质学习资源,欢迎关注我的微信公众号:"Java面试通关手册" 。无套路,希望能与您共同进步,互相学习。

相关文章:

  • 耗时一个月,我为拉勾设计的移动端
  • NGUI学习笔记(一):官方视频学习记录
  • 个推用户画像产品 (个像) Android 集成实践
  • asp.net下使用Cookie保存登录信息
  • SQLServer插入数据
  • Sql Xml
  • Notepad++的语法高亮
  • 电脑安装打印机设备搜索不到解决记录
  • JMX详解
  • Spring Security 基于表达式的权限控制
  • Storm 0.9 集群搭建
  • vs2017使用rdlc实现批量打印
  • Click Magick – 下一代点击跟踪和链接管理
  • GitHub推出更多课程
  • HTML/CSS实现的一个列表页
  • [case10]使用RSQL实现端到端的动态查询
  • 【剑指offer】让抽象问题具体化
  • js数组之filter
  • LintCode 31. partitionArray 数组划分
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • Python 使用 Tornado 框架实现 WebHook 自动部署 Git 项目
  • Redash本地开发环境搭建
  • Spring Security中异常上抛机制及对于转型处理的一些感悟
  • thinkphp5.1 easywechat4 微信第三方开放平台
  • Vue 重置组件到初始状态
  • 阿里云应用高可用服务公测发布
  • 爱情 北京女病人
  • 彻底搞懂浏览器Event-loop
  • 初识 webpack
  • 基于阿里云移动推送的移动应用推送模式最佳实践
  • 快速构建spring-cloud+sleuth+rabbit+ zipkin+es+kibana+grafana日志跟踪平台
  • 每天一个设计模式之命令模式
  • 前端之Sass/Scss实战笔记
  • 日剧·日综资源集合(建议收藏)
  • 格斗健身潮牌24KiCK获近千万Pre-A轮融资,用户留存高达9个月 ...
  • ​软考-高级-系统架构设计师教程(清华第2版)【第1章-绪论-思维导图】​
  • #单片机(TB6600驱动42步进电机)
  • (C语言版)链表(三)——实现双向链表创建、删除、插入、释放内存等简单操作...
  • (js)循环条件满足时终止循环
  • (MIT博士)林达华老师-概率模型与计算机视觉”
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (安卓)跳转应用市场APP详情页的方式
  • (附源码)springboot宠物医疗服务网站 毕业设计688413
  • (附源码)springboot炼糖厂地磅全自动控制系统 毕业设计 341357
  • (剑指Offer)面试题41:和为s的连续正数序列
  • (十二)devops持续集成开发——jenkins的全局工具配置之sonar qube环境安装及配置
  • (转)人的集合论——移山之道
  • .\OBJ\test1.axf: Error: L6230W: Ignoring --entry command. Cannot find argumen 'Reset_Handler'
  • .Net 4.0并行库实用性演练
  • .NET/C# 如何获取当前进程的 CPU 和内存占用?如何获取全局 CPU 和内存占用?
  • .Net6 Api Swagger配置
  • .net下简单快捷的数值高低位切换
  • [ vulhub漏洞复现篇 ] Celery <4.0 Redis未授权访问+Pickle反序列化利用
  • [ vulhub漏洞复现篇 ] ECShop 2.x / 3.x SQL注入/远程执行代码漏洞 xianzhi-2017-02-82239600
  • [20161101]rman备份与数据文件变化7.txt