1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-20 22:17:09 +08:00

Update Java基础知识.md

This commit is contained in:
shuang.kou 2020-02-26 19:43:12 +08:00
parent 3bb48208a8
commit 8d0501ab7a

View File

@ -8,12 +8,14 @@
- [JVM](#jvm)
- [JDK 和 JRE](#jdk-和-jre)
- [4. Oracle JDK 和 OpenJDK 的对比](#4-oracle-jdk-和-openjdk-的对比)
- [5. Java和C++的区别?](#5-java和c的区别)
- [5. Java C++的区别?](#5-java--c的区别)
- [6. 什么是 Java 程序的主类 应用程序和小程序的主类有何不同?](#6-什么是-java-程序的主类-应用程序和小程序的主类有何不同)
- [7. Java 应用程序与小程序之间有哪些差别?](#7-java-应用程序与小程序之间有哪些差别)
- [8. 字符型常量和字符串常量的区别?](#8-字符型常量和字符串常量的区别)
- [9. 构造器 Constructor 是否可被 override?](#9-构造器-constructor-是否可被-override)
- [10. 重载和重写的区别](#10-重载和重写的区别)
- [重载](#重载)
- [重写](#重写)
- [11. Java 面向对象编程三大特性: 封装 继承 多态](#11-java-面向对象编程三大特性-封装-继承-多态)
- [封装](#封装)
- [继承](#继承)
@ -22,7 +24,7 @@
- [13. 自动装箱与拆箱](#13-自动装箱与拆箱)
- [14. 在一个静态方法内调用一个非静态成员为什么是非法的?](#14-在一个静态方法内调用一个非静态成员为什么是非法的)
- [15. 在 Java 中定义一个不做事且没有参数的构造方法的作用](#15-在-java-中定义一个不做事且没有参数的构造方法的作用)
- [16. import java和javax有什么区别](#16-import-java和javax有什么区别)
- [16. import java javax 有什么区别?](#16-import-java--javax-有什么区别)
- [17. 接口和抽象类的区别是什么?](#17-接口和抽象类的区别是什么)
- [18. 成员变量与局部变量的区别有哪些?](#18-成员变量与局部变量的区别有哪些)
- [19. 创建一个对象用什么运算符?对象实体与对象引用有何不同?](#19-创建一个对象用什么运算符对象实体与对象引用有何不同)
@ -36,16 +38,16 @@
- [27. hashCode 与 equals (重要)](#27-hashcode-与-equals-重要)
- [hashCode介绍](#hashcode介绍)
- [为什么要有 hashCode](#为什么要有-hashcode)
- [hashCodeequals的相关规定](#hashcode与equals的相关规定)
- [28. 为什么Java中只有值传递](#28-为什么java中只有值传递)
- [hashCode equals的相关规定](#hashcode与-equals的相关规定)
- [28. 为什么 Java 中只有值传递?](#28-为什么-java-中只有值传递)
- [29. 简述线程、程序、进程的基本概念。以及他们之间关系是什么?](#29-简述线程程序进程的基本概念以及他们之间关系是什么)
- [30. 线程有哪些基本状态?](#30-线程有哪些基本状态)
- [31 关于 final 关键字的一些总结](#31-关于-final-关键字的一些总结)
- [32 Java 中的异常处理](#32-java-中的异常处理)
- [Java异常类层次结构图](#java异常类层次结构图)
- [Throwable类常用方法](#throwable类常用方法)
- [Java 异常类层次结构图](#java-异常类层次结构图)
- [Throwable 类常用方法](#throwable-类常用方法)
- [异常处理总结](#异常处理总结)
- [33 Java序列化中如果有些字段不想进行序列化,怎么办?](#33-java序列化中如果有些字段不想进行序列化怎么办)
- [33 Java 序列化中如果有些字段不想进行序列化,怎么办?](#33-java-序列化中如果有些字段不想进行序列化怎么办)
- [34 获取用键盘输入常用的两种方法](#34-获取用键盘输入常用的两种方法)
- [35 Java 中 IO 流](#35-java-中-io-流)
- [Java 中 IO 流分为几种?](#java-中-io-流分为几种)
@ -53,6 +55,7 @@
- [BIO,NIO,AIO 有什么区别?](#bionioaio-有什么区别)
- [36. 常见关键字总结:static,final,this,super](#36-常见关键字总结staticfinalthissuper)
- [37. Collections 工具类和 Arrays 工具类常见方法总结](#37-collections-工具类和-arrays-工具类常见方法总结)
- [38. 深拷贝 vs 浅拷贝](#38-深拷贝-vs-浅拷贝)
- [参考](#参考)
- [公众号](#公众号)
@ -141,7 +144,6 @@ JRE 是 Java运行时环境。它是运行已编译 Java 程序所需的所有
- Java 有自动内存管理机制,不需要程序员手动释放无用内存
- **在 C 语言中,字符串或字符数组最后都会有一个额外的字符‘\0来表示结束。但是Java 语言中没有结束符这一概念。** 这是一个值得深度思考的问题,具体原因推荐看这篇文章: [https://blog.csdn.net/sszgg2006/article/details/49148189](https://blog.csdn.net/sszgg2006/article/details/49148189)
## 6. 什么是 Java 程序的主类 应用程序和小程序的主类有何不同?
一个程序中可以有多个类,但只能有一个类是主类。在 Java 应用程序中,这个主类是指包含 main方法的类。而在 Java 小程序中,这个主类是一个继承自系统类 JApplet 或 Applet 的子类。应用程序的主类不一定要求是 public 类,但小程序的主类要求必须是 public 类。主类是 Java 程序执行的入口点。
@ -157,7 +159,7 @@ JRE 是 Java运行时环境。它是运行已编译 Java 程序所需的所有
3. 占内存大小 字符常量只占 2 个字节; 字符串常量占若干个字节 (**注意: char 在 Java 中占两个字节**)
> java 编程思想第四版2.2.2 节
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-15/86735519.jpg)
> ![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-15/86735519.jpg)
## 9. 构造器 Constructor 是否可被 override?
@ -171,7 +173,7 @@ Constructor 不能被 override重写,但是可以 overload重载,所
下面是《Java 核心技术》对重载这个概念的介绍:
![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/bg/desktopjava核心技术-重载.jpg) 
![](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/bg/desktopjava核心技术-重载.jpg)
#### 重写
@ -183,8 +185,8 @@ Constructor 不能被 override重写,但是可以 overload重载,所
封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果属性不想被外界访问,我们大可不必提供方法给外界访问。但是如果一个类没有提供给外界访问的方法,那么这个类也没有什么意义了。
### 继承
继承是使用已存在的类的定义作为基础建立新类的技术,新类的定义可以增加新的数据或新的功能,也可以用父类的功能,但不能选择性地继承父类。通过使用继承我们能够非常方便地复用以前的代码。
**关于继承如下 3 点请记住:**
@ -203,7 +205,7 @@ Constructor 不能被 override重写,但是可以 overload重载,所
**可变性**
简单的来说String 类中使用 final 关键字修饰字符数组来保存字符串,`private final char value[]`,所以 String 对象是不可变的。而StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串`char[]value` 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
简单的来说String 类中使用 final 关键字修饰字符数组来保存字符串,`private final char value[]`,所以 String 对象是不可变的。而 StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类,在 AbstractStringBuilder 中也是使用字符数组保存字符串`char[]value` 但是没有用 final 关键字修饰,所以这两种对象都是可变的。
StringBuilder 与 StringBuffer 的构造方法都是调用父类构造方法也就是 AbstractStringBuilder 实现的,大家可以自行查阅源码。
@ -226,10 +228,9 @@ abstract class AbstractStringBuilder implements Appendable, CharSequence {
}
```
**线程安全性**
String 中的对象是不可变的也就可以理解为常量线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。 
String 中的对象是不可变的也就可以理解为常量线程安全。AbstractStringBuilder 是 StringBuilder 与 StringBuffer 的公共父类,定义了一些字符串的基本操作,如 expandCapacity、append、insert、indexOf 等公共方法。StringBuffer 对方法加了同步锁或者对调用的方法加了同步锁所以是线程安全的。StringBuilder 并没有对方法进行加同步锁,所以是非线程安全的。
**性能**
@ -253,7 +254,7 @@ String 中的对象是不可变的,也就可以理解为常量,线程安全
## 15. 在 Java 中定义一个不做事且没有参数的构造方法的作用
Java 程序在执行子类的构造方法之前,如果没有用 `super()`来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用 `super()`来调用父类中特定的构造方法,则编译时将发生错误,因为 Java 程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。
 
## 16. import java 和 javax 有什么区别?
刚开始的时候 JavaAPI 所必需的包是 java 开头的包javax 当时只是扩展 API 包来使用。然而随着时间的推移javax 逐渐地扩展成为 Java API 的组成部分。但是,将扩展从 javax 包移动到 java 包确实太麻烦了,最终会破坏一堆现有的代码。因此,最终决定 javax 包将成为标准 API 的一部分。
@ -268,7 +269,16 @@ Java 程序在执行子类的构造方法之前,如果没有用 `super() `来
4. 接口方法默认修饰符是 public抽象方法可以有 public、protected 和 default 这些修饰符(抽象方法就是为了被重写所以不能使用 private 关键字修饰!)。
5. 从设计层面来说,抽象是对类的抽象,是一种模板设计,而接口是对行为的抽象,是一种行为的规范。
备注在JDK8中接口也可以定义静态方法可以直接用接口名调用。实现类和实现是不可以调用的。如果同时实现两个接口接口中定义了一样的默认方法则必须重写不然会报错。(详见issue:[https://github.com/Snailclimb/JavaGuide/issues/146](https://github.com/Snailclimb/JavaGuide/issues/146))
> 备注:
>
> 1. 在 JDK8 中,接口也可以定义静态方法,可以直接用接口名调用。实现类和实现是不可以调用的。如果同时实现两个接口,接口中定义了一样的默认方法,则必须重写,不然会报错。(详见 issue:[https://github.com/Snailclimb/JavaGuide/issues/146](https://github.com/Snailclimb/JavaGuide/issues/146)。
> 2. jdk9 的接口被允许定义私有方法 。
总结一下 jdk7~jdk9 Java 中接口概念的变化([相关阅读](https://www.geeksforgeeks.org/private-methods-java-9-interfaces/)
1. 在 jdk 7 或更早版本中,接口里面只能有常量变量和抽象方法。这些接口方法必须由选择实现接口的类实现。
2. jdk8 的时候接口可以有默认方法和静态方法功能。
3. Jdk 9 在接口中引入了私有方法和私有静态方法。
## 18. 成员变量与局部变量的区别有哪些?
@ -314,10 +324,10 @@ new运算符new创建对象实例对象实例在堆内存中对象
**==** : 它的作用是判断两个对象的地址是不是相等。即,判断两个对象是不是同一个对象(基本数据类型==比较的是值,引用数据类型==比较的是内存地址)。
**equals()** : 它的作用也是判断两个对象是否相等。但它一般有两种使用情况:
- 情况 1类没有覆盖 equals() 方法。则通过 equals() 比较该类的两个对象时,等价于通过“==”比较这两个对象。
- 情况 2类覆盖了 equals() 方法。一般,我们都覆盖 equals() 方法来比较两个对象的内容是否相等;若它们的内容相等,则返回 true (即,认为这两个对象相等)。
**举个例子:**
```java
@ -350,13 +360,14 @@ public class test1 {
面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写 equals 时必须重写 hashCode 方法?”
### hashCode介绍
hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个 int 整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在 JDK 的 Object.java 中,这就意味着 Java 中的任何类都包含有 hashCode() 函数。
散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象)
### 为什么要有 hashCode
**我们先以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode** 当你把对象加入 HashSet 时HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较如果没有相符的hashcodeHashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 `equals()`方法来检查 hashcode 相等的对象是否真的相同。如果两者相同HashSet 就不会让其加入操作成功。如果不同的话就会重新散列到其他位置。摘自我的Java启蒙书《Head first java》第二版。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
**我们先以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode** 当你把对象加入 HashSet 时HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与该位置其他已经加入的对象的 hashcode 值作比较,如果没有相符的 hashcodeHashSet 会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 `equals()`方法来检查 hashcode 相等的对象是否真的相同。如果两者相同HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的 Java 启蒙书《Head first java》第二版。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。
通过我们可以看出:`hashCode()` 的作用就是**获取哈希码**,也称为散列码;它实际上是返回一个 int 整数。这个**哈希码的作用**是确定该对象在哈希表中的索引位置。**`hashCode()`在散列表中才有用,在其它情况下没用**。在散列表中 hashCode() 的作用是获取对象的散列码,进而确定该对象在散列表中的位置。
@ -370,12 +381,10 @@ hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返
推荐阅读:[Java hashCode() 和 equals()的若干问题解答](https://www.cnblogs.com/skywang12345/p/3324958.html)
## 28. 为什么 Java 中只有值传递?
[为什么 Java 中只有值传递?](https://juejin.im/post/5e18879e6fb9a02fc63602e2)
## 29. 简述线程、程序、进程的基本概念。以及他们之间关系是什么?
**线程**与进程相似,但线程是一个比进程更小的执行单位。一个进程在其执行的过程中可以产生多个线程。与进程不同的是同类的多个线程共享同一块内存空间和一组系统资源,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多,也正因为如此,线程也被称为轻量级进程。
@ -395,8 +404,6 @@ Java 线程在运行的生命周期中的指定时刻只可能处于下面6种
![Java线程状态变迁](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/19-1-29/Java%20%E7%BA%BF%E7%A8%8B%E7%8A%B6%E6%80%81%E5%8F%98%E8%BF%81.png)
由上图可以看出:
线程创建之后它将处于 **NEW新建** 状态,调用 `start()` 方法后开始运行,线程这时候处于 **READY可运行** 状态。可运行状态的线程获得了 cpu 时间片timeslice后就处于 **RUNNING运行** 状态。
@ -421,8 +428,6 @@ final关键字主要用在三个地方变量、方法、类。
![Java异常类层次结构图](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-2/Exception.png)
在 Java 中,所有的异常都有一个共同的祖先 java.lang 包中的 **Throwable 类**。Throwable 有两个重要的子类:**Exception异常** 和 **Error错误** ,二者都是 Java 异常处理的重要子类,各自都包含大量子类。
**Error错误:是程序无法处理的错误**,表示运行应用程序中较严重问题。大多数错误与代码编写者执行的操作无关,而表示代码运行时 JVMJava 虚拟机出现的问题。例如Java 虚拟机运行错误Virtual MachineError当 JVM 不再有继续执行操作所需的内存资源时,将出现 OutOfMemoryError。这些异常发生时Java 虚拟机JVM一般会选择线程终止。
@ -512,7 +517,6 @@ Java Io流共涉及40多个类这些类看上去很杂乱但实际上很
![IO-操作方式分类](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/IO-操作方式分类.png)
按操作对象分类结构图:
![IO-操作对象分类](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/IO-操作对象分类.png)
@ -559,4 +563,3 @@ Java Io流共涉及40多个类这些类看上去很杂乱但实际上很
**Java 工程师必备学习资源:** 一些 Java 工程师常用学习资源公众号后台回复关键字 **“1”** 即可免费无套路获取。
![我的公众号](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-6/167598cd2e17b8ec.png)