共计 12652 个字符,预计需要花费 32 分钟才能阅读完成。
写在最后面
这个我的项目是从 20 年末就立好的 flag,通过几年的学习,回过头再去看很多知识点又有新的了解。所以趁着找实习的筹备,联合以前的学习储备,创立一个次要针对应届生和初学者的 Java 开源常识我的项目,专一 Java 后端面试题 + 解析 + 重点常识详解 + 精选文章的开源我的项目,心愿它能随同你我始终提高!
阐明:此我的项目我的确有很用心在做,内容全副是我参考了诸多博主(已注明出处),材料,N 本书籍,以及联合本人了解,从新绘图,从新组织语言等等所制。集体之力菲薄,或有不足之处,在劫难逃,但更新 / 欠缺会始终进行。大家的每一个 Star 都是对我的激励!心愿大家能喜爱。
注:所有波及图片未应用网络图床,文章等均开源提供给大家。
我的项目名: Java-Ideal-Interview
Github 地址:Java-Ideal-Interview – Github
Gitee 地址:Java-Ideal-Interview – Gitee(码云)
继续更新中,在线浏览将会在前期提供,若认为 Gitee 或 Github 浏览不便,可克隆到本地配合 Typora 等编辑器舒服浏览
若 Github 克隆速度过慢,可抉择应用国内 Gitee 仓库
-
一 Java 基础知识
-
1. 概念常识
-
1.1 请你谈谈你对 JVM JDK JRE 的意识和了解
- 1.1.1 JVM(Java Virtual Machine)
- 1.1.2 JRE(Java Runtime Environment)
- 1.1.3 JDK(Java Development Kit)
-
1.2 请你比拟一下 Java 与 JavaScript、C++
- 1.2.1 Java 与 JavaScript
- 1.2.2 Java 与 C++
-
-
2. 根底语法
- 2.1 标识符和关键字的区别
- 2.2 Java 常见的命名规定(非标准)
-
2.3 正文的品种
- 2.3.1 谈谈你对正文标准的认识
- 2.4 字符常量和字符串常量的区别
- 2.5 char 型变量能不能存储一个中文汉字?
- 2.6 final 关键字有什么作用
- 2.7 前置或后置自增 / 自减运算符的区别
- 2.8 & 和 && 的区别
-
2.9 替换两个整型数的值你有几种办法?
- 2.9.1 简略讲一下原码,补码,反码
- 2.9.2 介绍一下几种位运算
- 2.10 用最有效率的办法算出 2 乘以 8 等于多少
- 2.11 break、continue、return 的区别?
-
3. 根本数据类型
- 3.1 讲一讲 Java 中的几种根本数据类型
-
3.2 谈谈数据类型转换时的精度解决问题
- 3.2.1 变量相加和常量相加类型转换时有什么区别
- 3.2.2 Java 背地是如何强制转换 byte 类型溢出谬误问题的
- 3.3 Java 中根底类型对应的包装类型是什么,主动装箱与拆箱又是什么?
- 3.4 几种包装类类型的常量池(缓冲区)问题
-
4. 办法
- 4.1 Java 中办法参数传递为值传递还是援用传递
-
4.2 说一说办法重载和重写的区别
- 4.2.1 如何了解办法的重载和重写都是实现多态的形式
- 4.2.1 为什么函数不能依据返回类型来辨别重载?
-
注:此篇次要蕴含 Java 基础知识(Java 入门常识概念 + 根底语法)
- 面向对象,汇合篇等等 前面的会依照打算分批更新
一 Java 基础知识
1. 概念常识
1.1 请你谈谈你对 JVM JDK JRE 的意识和了解
1.1.1 JVM(Java Virtual Machine)
JVM 又被称作 Java 虚拟机,用来运行 Java 字节码文件(.class
),因为 JVM 对于特定零碎(Windows,Linux,macOS)有不同的具体实现,即它屏蔽了具体的操作系统和平台等信息,因而同一字节码文件能够在各种平台中任意运行,且失去同样的后果。
1.1.1.1 什么是字节码?
扩大名为 .class
的文件叫做字节码,是程序的一种低级示意,它不面向任何特定的处理器,只面向虚拟机(JVM),在通过虚拟机的解决后,能够使得程序能在多个平台上运行。
1.1.1.2 采纳字节码的益处是什么?
Java 语言通过字节码的形式,在肯定水平上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比拟高效,而且,因为字节码并不专对一种特定的机器,因而,Java 程序毋庸从新编译便可在多种不同的计算机上运行。
为什么肯定水平上解决了传统解释型语言执行效率低的问题(参考自思否 -scherman,仅供参考)
首先晓得两点,① 因为 Java 字节码是伪机器码,所以会比解析型语言效率高 ②JVM 不是解析型语言,是半编译半解析型语言
解析型语言没有编译过程,是间接解析源代码文本的,相当于在执行时进行了一次编译,而 Java 的字节码尽管无奈和本地机器码齐全一一对应,但能够简略映射到本地机器码,不须要做简单的语法分析之类的编译解决,当然比纯解析语言快。
1.1.2 JRE(Java Runtime Environment)
JRE 是 Java 运行时环境,它蕴含了 JVM 和 Java 的一些根底类库,它用来运行曾经编译好的 Java 程序(它就是用来运行的,不能创立新程序)
1.1.3 JDK(Java Development Kit)
JDK 是 Java 开发工具包,是程序员应用 Java 语言开发 Java 程序必备的工具包,它不仅蕴含 JRE,同时还蕴含了编译器(javac)还蕴含了很多 java 调试,剖析,文档相干的工具。应用 JDK 能够创立以及编译程序。
1.1.3.1 只为 Java 运行环境 JRE,有必要装置 JDK 吗
单纯为了运行一个 Java 程序,JRE 是齐全够用的,但话不能这么相对
有时,即便您不打算在计算机上进行任何 Java 开发,依然须要装置 JDK。例如,如果要应用 JSP 部署 Web 应用程序,那么从技术上讲,您只是在应用程序服务器中运行 Java 程序。那你为什么须要 JDK 呢?因为应用程序服务器会将 JSP 转换为 Java servlet,并且须要应用 JDK 来编译 servlet。(参考自 Github-JavaGuide,仅供参考)
所以,大部分状况装置 JDK 还是有必要的,须要依据具体情况来决定。
1.1.3.2 你能谈一谈 Java 程序从代码到运行的一个过程吗?
过程:编写 -> 编译 -> 解释(这也是 Java 编译与解释共存的起因)
首先通过 IDE/ 编辑器编写源代码而后通过 JDK 中的编译器(javac)编译成 Java 字节码文件(.class 文件),字节码通过虚拟机执行,虚拟机将每一条要执行的字节码送给解释器,解释器会将其翻译成特定机器上的机器码(及其可执行的二进制机器码)。
1.2 请你比拟一下 Java 与 JavaScript、C++
1.2.1 Java 与 JavaScript
- 用途不同:Java 被宽泛用于互联网应用程序的开发。而 JavaScript 次要内嵌于 Web 页面中运行,用来读写 HTML,管制 cookies 等。
- 定位不同:Java 是基于对象的,简略开发也须要设计并创立类。而 JavaScript 这种脚本语言是基于对象的和事件驱动的,它能够通过大量提供好的外部对象实现各种性能。
- 代码执行过程不同:Java 源代码会通过编译编程字节码文件,而后 JVM 将字节码文件分发给解释器进行解释解决,因而属于编译与解释共存。而 JavaScript 是一种解释性语言,源代码不须要通过编译,浏览器即可解释执行(JIT(即时编译)能够进步 JavaScript 的运行效率)。
- 数据类型不同:Java 采纳强类型查看,编译前必须申明,而 JavaScript 是弱类型,甚至变量应用前能够不申明,JavaScript 在运行时查看推断其数据类型。
1.2.2 Java 与 C++
- 指针:Java 语言不显式地向用户提供指针来拜访内存,增加了主动内存治理性能,能够防止在 C/C++ 中因操作失误而导致的野指针的问题,使程序更平安(只是不提供,并不是没有指针,虚拟机中外部还是应用了指针只是不向外提供而已)。
- 继承:Java 的类是单继承的,而 C++ 却能够多重继承,但 Java 能够通过继承 / 实现多个接口。
- 内存治理:Java 的 JVM 中有本人的 GC 机制(垃圾回收机制),不须要程序员手动开释没用的内存
- 运算符重载:Java 不能够运算符重载,而 C++ 则能够。
2. 根底语法
阐明:此局部包含:关键字,标识符,正文,常量,变量,运算符,分支,循环的相干内容。
数据类型、办法独自整顿为 第 3 大点 和 第 4 大点
2.1 标识符和关键字的区别
标识符和关键字的实质都是一个名字,例如类名,办法名,变量名 …,而关键字,是一种非凡的标识符,它被冠以一种非凡的含意,例如 public return try catch …,因为关键字有其特定的地位和用处,所以一般标识符不容许与关键字重名。
2.2 Java 常见的命名规定(非标准)
注:上面所述,均为命名的硬性规定,而非举荐的标准,具体可参考《阿里巴巴 Java 开发手册》
根本:
- 包名:全副小写用
.
隔开 eg:com.baidu.www(域名反写) - 类名 / 接口:首字母大写,多个单词组成则应用驼峰命名
- 办法或变量名:首字母小写,多个单词组成则应用驼峰命名
- 常量名:全副大写,用
_
隔开
标识符:
- 首字符:字母(
A-Z、a-z
)、美元符($
)、下划线(_
) - 首字符之后:字母(
A-Z、a-z
)、美元符($
)、下划线(_
)或者数字的任何字符组合
2.3 正文的品种
正文有三种:① 单行正文(// 正文内容
)、② 多行正文(/* 正文内容 */
)、③ 文档正文(/** 正文内容 */
)
2.3.1 谈谈你对正文标准的认识
首先要说正文的作用:① 能精确的反映设计思维和代码逻辑 ② 可能形容业务含意
一份好的正文,能够在较长一段时间后,帮忙你疾速回顾过后的思路,也能够帮忙接管这份代码的新人,疾速理解你的想法。
代码的正文不是越具体越好。实际上好的代码自身就是正文,咱们要尽量标准和丑化本人的代码来缩小不必要的正文。若编程语言足够有表达力,就不须要正文,尽量通过代码来论述。——《Clean Code》
2.4 字符常量和字符串常量的区别
- 模式不同:字符常量是单引号引起的一个字符,而字符串常量是双引号引起的 0 个或若干个字符
- 含意不同:字符常量相当于一个整型值(ASCII 值),能够加入表达式运算,而字符串常量代表一个地址值(该字符串在内存中寄存地位)
- 占内存大小不同:字符常量只占 2 个字节(char 在 Java 中占两个字节),字符串常量占若干个字节
2.5 char 型变量能不能存储一个中文汉字?
char 型变量是用来存储 Unicode 编码的字符的,而 Unicode 编码字符集中蕴含了汉字,所以,char 型变量中当然能够存储汉字啦。如果某个非凡的汉字没有被蕴含在 unicode 编码字符集中,那么,这个 char 型变量中就不能存储这个非凡汉字。
补充阐明:unicode 编码占用两个字节,所以,char 类型的变量也是占用两个字节
2.6 final 关键字有什么作用
- final 润饰的类不能被继承,final 类中的成员变量能够依据须要设为 final,但要留神 final 类中的所有成员办法都会被隐式地指定为 final 办法。
- final 润饰的办法不能被重写
- final 润饰的变量叫做常量,如果是根本类型,则数值初始化后就不能扭转了,如果是援用类型,则对其初始化后则不能再让其指向到另一个对象了。
2.7 前置或后置自增 / 自减运算符的区别
++
和 --
就是对变量进行自增 1 或者自减 1 的运算符,前置后置是有区别的:
规定:运算符前置则先加 / 减,运算符后置则后加 / 减
int x = 4;
int y = (x++) + (++x) + (x * 10);
System.out.println(y);
首先 (x++) 中 x 后置 ++ 所以后加减,即 x 运算时取 4 而后自增为 5
其次 (++x) 中 x 前置 ++ 所以先加减,x = 6
接着 x 10 = 6 10 = 60
最初执行赋值语句,即:y = 4 + 6 + 60 = 70
2.8 & 和 && 的区别
&
运算符有两种用法:① 按位与 ② 逻辑与(这里只探讨)
&&
运算符是短路与运算
逻辑与跟短路与都要求运算符左右两端的布尔值都是 true 整个表达式的值才是 true
&& 具备短路作用,如果 && 右边的表达式的值是 false,左边的表达式会被间接短路掉,不会进行运算,因而效率更高
个别更举荐应用 &&,例如在验证用户登录时断定用户名不是 null 而且不是空字符串,该当写为:username != null &&!username.equals(“”),二者的程序不能替换,更不能用 & 运算符,因为第一个条件如果不成立,基本不能进行字符串的 equals 比拟,否则会产生 NullPointerException 异样。
留神:逻辑或运算符(|)和短路或运算符(||)的差异也是如此。
补充:&
还能够当做位运算符,当 &
两边操作数或表达式的后果不是布尔类型的时候,&
即依照位于运算符操作
2.9 替换两个整型数的值你有几种办法?
形式 1 :应用一个两头值传递(因其可读性高,所以开发中也罕用这种形式)
形式 2 :用位异或实现
^
位异或运算符的特点:一个数据对另一个数据位异或两次,该数自身不变
a = a ^ b;
b = a ^ b; // 将 a 带入, 即: b = a ^ b ^ b
a = a ^ b; // a 还是 a ^ b , b 变成了 a 即: a = a ^ b ^ a = b
形式 3 :用变量相加的办法
a = a + b;
b = a - b;
a = a - b;
形式 4 :一句话的事
b = (a + b) - (a = b);
此处形式 1 2 4 都好了解,顺便回顾一下原反补码,以及各种位运算
2.9.1 简略讲一下原码,补码,反码
在计算机内,有符号数有三种示意办法,源码、反码、和补码。而所有的数据运算都是采纳补码进行的
-
原码:二进制点表示法,最高位为符号位,“0”示意正,“1”示意负,其余地位示意数值大小,可直观反映出数据的大小。
- 负数的原码最高位是 0,正数的原码最高位是 1,其余的是数值位
-
反码:解决正数加法运算问题,将减法运算转换为加法运算,从而简化运算规定。
- 负数的反码与原码雷同,正数的反码与源码符号位雷同,数值位取反 1 -> 0、0 -> 1
-
补码:解决正数加法运算正负零问题,补救了反码的有余。
- 负数的补码与原码雷同,正数的补码是在反码的根底上 +1
2.9.2 介绍一下几种位运算
位运算须要将数据转换成二进制,用 0 补齐位数
&
位与运算符:有 0 则 0
|
位或运算符:有 1 则 1
^
位异或运算符:雷同则 0,不同则 1
~
按位取反运算符:0 变 1,1 变 0(拿到的是补码,要转换为原码)
<<
按位左移运算符:右边最高位抛弃,左边补齐
- 疾速计算:把
<<
右边的数据 乘以 2 的挪动次幂:例如 3 << 2 即:3 * 2 ^ 2 = 12
>>
按位右移运算符:最高位为 0,右边补齐 0,最高位是 1,右边补齐 1
- 疾速计算:把
>>
右边的数据 除以 2 的挪动次幂:例如 -24 >> 2 即:-24 / 2 ^ 2 = -6
>>>
按位右移补零操作符:无论最高位是 0 还是 1,右边补齐 0
别离演示 ^
和 >>
两个典型运算符
- 3 ^ 4
// 3 的二进制: 11 补齐位数
00000000 00000000 00000000 00000011
// 4 的二进制: 100 补齐位数
00000000 00000000 00000000 00000100
// 位异或运算符: 雷同则 0, 不同则 1
00000000 00000000 00000000 00000011
00000000 00000000 00000000 00000100
-----------------------------------
00000000 00000000 00000000 00000111
// 失去的为补码,因为符号位为 0 即为负数,所以原反补码统一,所以后果(原码)就是二进制的 111,即十进制的 7
- -24 >> 2
// -24 的二进制: 11000 正数符号位为 1, 补齐位数
原码: 10000000 00000000 00000000 00011000
反码: 11111111 11111111 11111111 11100111
补码: 11111111 11111111 11111111 11101000
// 右移 2 位 最高位是 1,右边补齐 1
11111111 11111111 11111111 11101000
1111111111 11111111 11111111 111010(00)
// 拿到的后果为补码,按 8 位划分开
补码: 11111111 11111111 11111111 11111010
反码: 11111111 11111111 11111111 11111001
原码: 10000000 00000000 00000000 00000110
// 后果是二进制的 110, 即十进制的 -6
2.10 用最有效率的办法算出 2 乘以 8 等于多少
应用位运算来实现效率最高。位运算符是对操作数以二进制比特位为单位进行操作和运算,操作数和后果都是整型数。
对于位运算符 <<
, 是将一个数左移 n 位,就相当于乘以了 2 的 n 次方,那么,一个数乘以 8 只有将其左移 3 位即可,位运算是 cpu 间接反对的,效率最高。
所以,2 乘以 8 等于几的最效率的办法是 2 << 3
2.11 break、continue、return 的区别?
break、continue 均属于跳出循环的关键字,return 属于跳出办法的关键字
- break:齐全跳出一个循环体,执行该循环体下接着的语句
- continue:跳过本次循环,执行下一次循环
-
return:完结办法的运行,有两种用法
return;
:用于没有返回值的办法(可不写)retu
rn value
:用于返回一个特定的值
3. 根本数据类型
3.1 讲一讲 Java 中的几种根本数据类型
首先 Java 是一种强类型的语言,针对每一种数据都定义了明确的数据类型(就是将一些值的范畴做了束缚,从而为不同类型的值在内存中调配不同的内存空间)
Name | Size(字节 \ | 位数) | Range |
---|---|---|---|
byte | 1byte \ | 8bit | -128~127 之间 |
short | 2bytes \ | 16bit | -32768~32767 之间,最大数据存储量是 65536 |
int | 4bytes \ | 32bit | -2^31 ~ 2^31-1 之间 |
long | 8bytes \ | 64bit | -2^63 ~ 2^63-1 |
float | 4bytes \ | 32bit | 3.4e-45~1.4e38,间接赋值时必须在数字后加上 f 或 F |
double | 8bytes \ | 64bit | 4.9e-324~1.8e308,赋值时能够加 d 或 D 也能够不加 |
boolean | 只有 true 和 false 两个取值 | ||
char | 2bytes | 存储 Unicode 码,用单引号赋值 |
留神:对于 boolean,官网文档未明确定义,它依赖于 JVM 厂商的具体实现。逻辑上了解是占用 1 位,然而理论中会思考计算机高效存储因素。
3.2 谈谈数据类型转换时的精度解决问题
一般来说,咱们在运算的时候,要求参加运算的数值类型必须统一,针对类型不统一的时候,有两种将不同数据类型对立的形式,即:默认主动转换(从小到大的转换)和 强制转换。
- 默认主动转换:即从 byte,short, char 三者都会被默认的转到更高的精度类型,精度等级程序如下(==> int ==> long ==> float ==> double)
纳闷:为什么 float(4 个字节)在 long(8 个字节)前面
A: 它们底层的存储构造不同
B: float 示意的数据范畴比 long 范畴要大
long:2^63-1
float:3.410^38 > 210^38 > 28^38 > 22^3^38
= 2*2^144 > 2^63 -1
默认类型转换示例:
// 例如低精度 byte 到高精度 int 会依据默认转换,主动转换类型
// 能够失常执行
public static void main(String[] args) {
byte a = 2;int b = 3;
int c = a + b
System.out.println(c);
}
// 高精度 int 到低精度 byte 可能会损失精度
// 间接报错,不兼容的类型: 从 int 转换到 byte 可能会有损失
public static void main(String[] args) {
byte a = 3;int b = 4;
byte c = a + b
System.out.println(c);
}
-
强制类型转换
- 格局:指标数据类型 变量 =(指标数据类型)(被转换的数据)
留神:不要轻易的去用强制转化,因为它隐含了精度损失的问题,把容量大的类型转换为容量小的类型时必须应用强制类型转换。
int i = 128;
// 因为 byte 类型是 8 位,最大值为 127,所以当 int 强制转换为 byte 类型的时候,值 128 就会导致溢出
byte b = (byte)i;
3.2.1 变量相加和常量相加类型转换时有什么区别
变量相加,会首先看类型问题,最终把后果赋值也会思考类型问题
常量相加,首先做加法,而后看后果是否在赋值的数据类型范畴内,如果不是,才报错
3.2.2 Java 背地是如何强制转换 byte 类型溢出谬误问题的
public static void main(String[] args) {
// byte 的范畴是: -128 到 127,所以报错
byte a = 130;
// 应用强制类型转换
byte b = (byte)130;
System.out.println(b);
}
咱们想要晓得后果是什么,就应该晓得是如何计算的,而咱们又晓得计算机中数据的运算都是补码进行的,失去补码,首先要计算出数据的二进制
// 求出 130 的二进制 10000010
// 130 是一个整数 所以补齐 4 个字节(一个字节 8 位)0000000 00000000 00000000 10000010
// 做截取操作,截成 byte 类型(1 个字节,8 位)10000010
// 上述后果是补码,求其原码
补码: 10000010
反码: 10000001
原码: 11111110
// 11111110 转换为十进制为 -126
3.3 Java 中根底类型对应的包装类型是什么,主动装箱与拆箱又是什么?
Java 中有 8 种根本数据类型,别离为:byte、short、int、long、float、double、char、boolean。
对应的包装类别离为:Byte、Short、Integer、Long、Float、Double、Character、Boolean
将根本数据类型封装成对象的的益处在于能够在对象中定义更多的性能办法操作该数据,比方 String 和 int 类型的互相转换。同时简化了根本数据类型和绝对应对象的转化步骤。
- 主动装箱:将根本类型用它们对应的援用类型包装起来
- 主动拆箱:将包装类型转换为根本数据类型
而在咱们想要应用包装类的一些办法的时候,能够通过根本类型包装类的构造方法将值传入,然而 JDK5 后的新个性就为咱们大大的简化了一些麻烦的步骤。
// 定义一个 包装类型 Integer 接管一个根本类型 int 整数 1, 这就是一个主动装箱。Integer a = 1;
// 如果没有主动装箱的话,须要应用构造函数
Integer a = new Integer(1)
// 持续用 int 类型 b 接管一个 下面的包装类型 Integer a, 这就是一个主动拆箱
int b = a;
// 如果没有主动拆箱的话,须要应用办法
int b = a.intValue()
3.4 几种包装类类型的常量池(缓冲区)问题
在 JDK 5 当前,几种包装类对象在外部实现中通过应用雷同的对象援用实 现了缓存和重用。例如:Integer 类型对于 -128-127 之间的数字是在缓冲区取的,所以对于在这个范畴内的数值用双等号(==
)比拟是统一的,因为对应的内存地址是雷同的。但对于不在这区间的数字是在堆中 new 进去的,所以地址空间不一样,也就不相等。
- Byte、Short、Integer、Long 缓存范畴:[-128,127]
- Character 缓存范畴:[0,127]
- Boolean 间接返回 True Or False
注:浮点数类型的包装类 Float 和 Double 并没有实现常量池技术
Boolean 源码节选:
// 一开始就定义 TRUE FALSE 两个常量
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
// 很少应用此构造函数, 非必须时举荐应用动态工厂
public Boolean(boolean value) {this.value = value;}
// valueOf 是一个更好的抉择,它能产生更好的工夫和空间性能
public static Boolean valueOf(boolean b) {return (b ? TRUE : FALSE);
}
Character 源码节选:
// 此办法通常优先于构造函数, 起因也是产生更好的工夫和空间性能
public static Character valueOf(char c) {if (c <= 127) { // must cache
return CharacterCache.cache[(int)c];
}
return new Character(c);
}
// 具体的逻辑在此
private static class CharacterCache {private CharacterCache(){}
static final Character cache[] = new Character[127 + 1];
static {for (int i = 0; i < cache.length; i++)
cache[i] = new Character((char)i);
}
}
Integer 源码节选:
// 该办法缓存的值总是在 -128 到 127 之间,并可能缓存该范畴之外的其余值
public static Integer valueOf(int i) {if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
// IntegerCache 具体逻辑可自行钻研
4. 办法
4.1 Java 中办法参数传递为值传递还是援用传递
Java 中办法参数传递形式是 按值传递。
- 如果参数是 根本类型 ,传递的是根本类型的字面量 值的拷贝 。形式参数的扭转对理论参数 没有影响
- 如果参数是 援用类型 ,传递的是该参量所援用的对象在堆中 地址值的拷贝 。形式参数的扭转 间接影响 理论参数
上面咱们对以上论断进行简略剖析:
示例 1:
public static void main(String[] args) {
// 根本类型
int a = 100;
int b = 200;
System.out.println("main 调用 modify 前:" + "a:" + a + ", b:" + b);
modify(a, b);
System.out.println("main 调用 modify 后:" + "a:" + a + ", b:" + b);
}
/**
* 参数为根本类型
* @param a
* @param b
*/
public static void modify(int a, int b) {System.out.println("modify 接管到参数:" + "a:" + a + ", b:" + b);
a = 300;
b = 400;
System.out.println("modify 批改参数后:" + "a:" + a + ", b:" + b);
}
运行后果:
main 调用 modify 前: a: 100, b: 200
modify 接管到参数: a: 100, b: 200
modify 批改参数后: a: 300, b: 400
main 调用 modify 后: a: 100, b: 200
示例 2:
public static void main(String[] args) {
// 援用类型
int[] arr = {1, 2, 3, 4, 5};
System.out.println("main 调用 modify 前:" + "arr[0]:" + arr[0]);
modify(arr);
System.out.println("main 调用 modify 后:" + "arr[0]:" + arr[0]);
}
/**
* 参数为援用类型
* @param arr
*/
public static void modify(int[] arr) {System.out.println("modify 接管到参数 (以 arr[0] 举例):" + "arr[0]:" + arr[0]);
arr[0] = 100;
System.out.println("modify 批改参数后 (以 arr[0] 举例):" + "arr[0]:" + arr[0]);
}
运行后果:
main 调用 modify 前: arr[0]: 1
modify 接管到参数 (以 arr[0] 举例): arr[0]: 1
modify 批改参数后 (以 arr[0] 举例): arr[0]: 100
main 调用 modify 后: arr[0]: 100
上述代码的后果,即:以根本类型作为办法参数,办法内对形参的批改,不会影响到理论参数。以援用类型作为办法参数,办法内对形参的批改,会间接影响到理论参数。画一张图简略剖析一下:
对于根本类型,a 和 b,在 modify(int, int) 办法中进行批改不会影响原先的值,这是因为 modify 办法中的参数 a 和 b 是从原先的 a 和 b 复制过去的一个正本。无论如何批改 a 和 b 的值,都不会影响到原先的值。
对于援用类型,arr 数组初始化后,指向到了一个具体的地址中,而将其作为办法参数传递,modify 办法中的 arr 也就指向到了同一个地址去,所以办法内的批改,会间接反映在所对应的对象上。
4.2 说一说办法重载和重写的区别
办法重载:在一个类中,同名的办法如果有不同的参数列表(参数类型、个数甚至程序不同)则叫做重载
- 规定:在同一个类中,办法名必须雷同,参数类型不同、个数不同、程序不同,办法返回值和拜访修饰符能够不同。
- 表现形式:办法名,返回值,拜访修饰符,雷同的办法,依据不同的数据列表,做出不同的逻辑解决。
办法重写:是子类对父类的容许拜访的办法的实现过程进行从新编写
-
规定:
- 办法名、参数列表、返回类型都雷同的状况,对办法体进行批改或者重写。
- 拜访修饰符的限度肯定要大于被重写办法的拜访修饰符(public > protected > default > private)。
- 重写办法肯定不能抛出新的查看异样或者比被重写办法申明更加宽泛的查看型异样
- 表现形式:重写就是当子类继承自父类的雷同办法,输出一样的数据,你就要笼罩父类办法,使得办法能做出不同的响应
4.2.1 如何了解办法的重载和重写都是实现多态的形式
办法的重载和重写都是实现多态的形式,区别在于重载实现的是编译时的多态性,而重写实现的是运行时的多态
性。这里的多态能够了解为一个办法的 调用,或者函数入口参数的不同,而造成的办法行为不同。
两种不同期间的多态:
-
① 编译期间多态:其又被称为动态多态,编译期间的多态是靠重载实现的,依据参数个数,类型和程序决定的(必须在同一个类中)
- 在办法调用之前,编译器就曾经确定了所要调用的办法,这称为“早绑定”或“动态绑定”;
-
② 运行时的多态:运行期间的多态是靠办法的重写实现的,在编译期间被视作雷同办法,然而运行期间依据对象的不同调用不同的办法
- 只有等到办法调用的那一刻,解释运行器才会确定所要调用的具体方法,这称为“晚绑定”或“动静绑定”。
- 这也就是咱们说的,编译看右边,运行看左边(会在面向对象篇设波及)
4.2.1 为什么函数不能依据返回类型来辨别重载?
Java 容许重载任何办法,而不只是结构器办法。因而要残缺的指出办法名以及参数类型。这叫做办法的签名(signature)。例如 String 类有 4 个称为 indexOf 的私有办法。它们的签名是:
indexOf(int)
indexOf(int, int)
indexOf(String)
indexOf(String, int)
返回值类型不是办法签名的一部分。也就是说,不能有两个名字雷同、参数类型也雷同却返回不同类型值的办法。
同时函数的返回值只是作为函数运行之后的一个“状态”,他是放弃办法的调用者与被调用者进行通信的要害。并不能作为某个办法的“标识”。