一 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");//
//str.append("我喜欢");//
//str.insert(3, "(编程)"); }

结果:

java我喜欢

解析:

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

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

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

	public static void change1(StringBuffer str) {

		str.append("aa");
str.insert(3, "(bb)"); }

2. String类型传递

	// 测试引用传递:Sring
@org.junit.Test
public void method2() {
String str = new String("aaa");
System.out.println(str);
change2(str);
System.out.println(str);
} public static void change2(String str) {
// str="abc"; //aaa
str = new String("abc"); //aaa
}

结果:

aaa
aaa

可以看到不论是执行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() 函数。另外需要注意的是: Object 的 hashcode 方法是本地方法,也就是用 c 语言或 c++ 实现的,该方法直接返回对象的 内存地址。

散列表存储的是键值对(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的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)

为什么两个对象有相同的hashcode值,它们也不一定是相等的?

在这里解释一位小伙伴的问题。以下内容摘自《Head Fisrt Java》。

因为hashCode() 所使用的杂凑算法也许刚好会让多个对象传回相同的杂凑值。越糟糕的杂凑算法越容易碰撞,但这也与数据值域分布的特性有关(所谓碰撞也就是指的是不同的对象得到相同的 hashCode)。

我们刚刚也提到了 HashSet,如果 HashSet 在对比的时候,同样的 hashcode 有多个对象,它会使用 equals() 来判断是否真的相同。也就是说 hashcode 只是用来缩小查找成本。

参考:

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

2018.9.6 Java常考知识点总结的更多相关文章

  1. 找工作笔试面试那些事儿(13)---操作系统常考知识点总结 ZZ 【操作系统】

    http://blog.csdn.net/han_xiaoyang/article/details/11285485 上一节对数据库的知识做了一个小总结,实际找工作过程中,因为公司或单位侧重点不一样, ...

  2. Java常考面试题

    Java常考面试题 1. 什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? 答:Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行 ...

  3. 前端面试常考知识点---CSS

    前端面试常考知识点---js 1.CSS3的新特性有哪些 点我查看 CSS3选择器 . CSS3边框与圆角 CSS3圆角border-radius:属性值由两个参数值构成: value1 / valu ...

  4. 关于Java多线程的一些常考知识点

    前言 Java多线程也是面试中经常会提起到的一个点.面试官会问:实现多线程的两种方式以及区别,死锁发生的4个条件以及如何避免发生死锁,死锁和活锁的区别,常见的线程池以及区别,怎么理解有界队列与无界队列 ...

  5. Java面试常考知识点

    1.  什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. Jav ...

  6. 面试常考知识点——Java(JVM,JDK,JRE)

    1. 什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? 答:(1)Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. ...

  7. Java常考面试题(三)

    序言 说说今天遇到的一件小事吧,在遇到问题,查找答案时,看到很多人的博客里面都有提到关键字眼,可让人觉得可恨的是,大多数人写的博文中,基本上都是照着书上的语言发表的,看了跟没看一样,没有一点通俗的语言 ...

  8. 阿里巴巴JAVA常考面试题及汇总答案

    一.String,StringBuffer, StringBuilder 的区别是什么?String为什么是不可变的? 答:   1.String是字符串常量,StringBuffer和StringB ...

  9. Java常考面试题(经典)

    什么是Java虚拟机?为什么Java被称作是“平台无关的编程语言”? Java虚拟机是一个可以执行Java字节码的虚拟机进程.Java源文件被编译成能被Java虚拟机执行的字节码文件. Java被设计 ...

随机推荐

  1. my23_pxc其中一个节点重建记录

    PXC报废了一个节点,时间大概在周五,而此时故障的数据库节点比较多,警告信息也成百上千,此信息混合于已有的故障节点信息中,没有被及时发现:然后周六.周日各报废一个,在周一的时候,业务已经没有节点可以写 ...

  2. java——数组队列 ArrayQueue

    队列: Array: package Date_pacage; public class Array<E> { //叫它静态数组 //private int[] data; private ...

  3. leetcode 437. 路径总和 III

    题目描述: 给定一个二叉树,它的每个结点都存放着一个整数值. 找出路径和等于给定数值的路径总数. 路径不需要从根节点开始,也不需要在叶子节点结束,但是路径方向必须是向下的(只能从父节点到子节点). 二 ...

  4. tcp/ip 性能优化问题的思考学习

    首先要看TCP/IP协议,涉及到四层:链路层,网络层,传输层,应用层.  其中以太网(Ethernet)的数据帧在链路层 IP包在网络层 TCP或UDP包在传输层 TCP或UDP中的数据(Data)在 ...

  5. 数据库mysql--基础命令

    客户端 一.登录和退出 1.登录 mysql -h server-ip -u usename -p 回车,然后会提示输入密码 2.退出:"quit;" | "exit;& ...

  6. LeetCode 454.四数相加 II(C++)

    给定四个包含整数的数组列表 A , B , C , D ,计算有多少个元组 (i, j, k, l) ,使得 A[i] + B[j] + C[k] + D[l] = 0. 为了使问题简单化,所有的 A ...

  7. IIS/asp.net管道

    http://referencesource.microsoft.com/ 理解ASP.NET的前提是对ASP.NET管道式设计的深刻认识.而ASP.NET Web应用大都是寄宿于IIS上的. IIS ...

  8. Kudu-Master的设计

    不多说,直接上干货! http://blog.csdn.net/lookqlp/article/details/70858466

  9. 揭秘企业级web负载均衡完美架构

    相信很多朋友对企业级的负载均衡高可用实例非常感兴趣,此篇文章根据成熟的线上环境而写,旨在帮助大家迅速架构一个企业级的负载均衡高可用的web环境. 此系统架构仅映射内网VIP的80及443端口于外网的J ...

  10. Python 科学工具使用

    Python 科学工具笔记 numpy a = numpy.array([1,2,3,4]);// 创建一个numpy的数组对象 此时a.shape显示的值为(4,); 由此得出结论在一维的数组中, ...