Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
清新范er
JavaGuide
提交
c73d1edf
J
JavaGuide
项目概览
清新范er
/
JavaGuide
与 Fork 源项目一致
从无法访问的项目Fork
通知
4
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
J
JavaGuide
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
c73d1edf
编写于
8月 07, 2018
作者:
S
Snailclimb
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
增加“最最最常见的几道Java基础知识面试题总结”
上级
a1111b54
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
236 addition
and
0 deletion
+236
-0
面试必备/最最最常见的几道Java基础知识面试题总结.md
面试必备/最最最常见的几道Java基础知识面试题总结.md
+236
-0
未找到文件。
面试必备/最最最常见的几道Java基础知识面试题总结.md
0 → 100644
浏览文件 @
c73d1edf
## 一 Java中的值传递和引用传递(非常重要)
**首先要明确的是:“对象传递(数组、类、接口)是引用传递,原始类型数据(整型、浮点型、字符型、布尔型)传递是值传递。”**
### 那么什么是值传递和应用传递呢?
**值传递**
是指对象被值传递,意味着传递了对象的一个副本,即使副本被改变,也不会影响源对象。(因为值传递的时候,实际上是将实参的值复制一份给形参。)
**引用传递**
是指对象被引用传递,意味着传递的并不是实际的对象,而是对象的引用。因此,外部对引用对象的改变会反映到所有的对象上。(因为引用传递的时候,实际上是将实参的地址值复制一份给形参。)
有时候面试官不是单纯问你“Java中是值传递还是引用传递”是什么啊,骚年?而是给出一个例子,然后让你写出答案,这种也常见在笔试题目中!所以,非常重要了,请看下面的例子:
### 值传递和应用传递实例
#### 1. 值传递
```
java
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. 引用传递
```
java
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类型传递
```
java
// 测试引用传递: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类型传递
```
java
// 测试引用传递: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. 一道类似的题目
下面的程序输出是什么?
```
java
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`
方法改为下图所示,输出结果又是什么呢?
```
java
public
static
void
change
(
Person
p
)
{
p
.
name
=
"李四"
;
}
```
答案我就不说了,我觉得大家如果认真看完上面的内容之后应该很很清楚了。
## 二 ==与equals(重要)
**==**
: 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象。
**equals()**
: 它的作用也是判断两个对象是否相等。但它一般有两种使用情况(前面第1部分已详细介绍过):
-
情况1:类没有覆盖equals()方法。则通过equals()比较该类的两个对象时,等价于通过“==”比较这两个对象。
-
情况2:类覆盖了equals()方法。一般,我们都覆盖equals()方法来两个对象的内容相等;若它们的内容相等,则返回true(即,认为这两个对象相等)。
## 三 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的两个对象无论如何都不会相等(即使这两个对象指向相同的数据)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录