提交 a1a1b625 编写于 作者: 沉默王二's avatar 沉默王二 💬
......@@ -104,12 +104,13 @@
## Java基础语法
- [Java中常用的48个关键字 & 2个保留字](docs/basic-extra-meal/48-keywords.md)
- [简单过一下Java中常用的48个关键字和2个保留字](docs/basic-extra-meal/48-keywords.md)
- [Java注释](docs/basic-grammar/javadoc.md)
- [Java中的数据类型](docs/basic-grammar/basic-data-type.md)
- [Java 数据类型转换](docs/basic-grammar/type-cast.md)
- [Java流程控制语句](docs/basic-grammar/flow-control.md)
- [Java中的数据类型(8种基本数据类型和引用数据类型)](docs/basic-grammar/basic-data-type.md)
- [Java数据类型转换(强制类型转换+自动类型转换)](docs/basic-grammar/type-cast.md)
- [聊聊Java基本数据类型缓存池](docs/basic-extra-meal/int-cache.md)
- [Java运算符](docs/basic-grammar/operator.md)
- [Java流程控制语句](docs/basic-grammar/flow-control.md)
## 数组&字符串
......@@ -123,28 +124,33 @@
- [Java如何判断两个字符串是否相等?](docs/string/equals.md)
- [最优雅的Java字符串拼接是哪种方式?](docs/string/join.md)
- [如何在Java中优雅地分割String字符串?](docs/string/split.md)
- [Java 9为什么要将String的底层实现由char数组改成了byte数组?](docs/basic-extra-meal/jdk9-char-byte-string.md)
## Java面向对象编程
- [怎么理解Java中的类和对象?](docs/oo/object-class.md)
- [Java 包,优雅地解决类名冲突](docs/oo/package.md)
- [一文彻底讲清楚Java中的类和对象](docs/oo/object-class.md)
- [简单过了一下Java中的包](docs/oo/package.md)
- [Java中的变量:局部变量、成员变量、静态变量、常量](docs/oo/var.md)
- [Java中的方法:实例方法、静态方法、抽象方法](docs/oo/method.md)
- [Java中的构造方法:对象创建时的必经之路](docs/oo/construct.md)
- [聊聊Java中的可变参数](docs/basic-extra-meal/varables.md)
- [手把手教你用 C语言实现 Java native 方法](docs/oo/native-method.md)
- [构造方法:Java对象创建时的必经之路](docs/oo/construct.md)
- [聊一聊Java中的访问权限修饰符](docs/oo/access-control.md)
- [Java中的代码初始化块:对成员变量进行更复杂的赋值](docs/oo/code-init.md)
- [Java中的代码初始化块](docs/oo/code-init.md)
- [Java抽象类,看这一篇就够了,豁然开朗](docs/oo/abstract.md)
- [Java接口,看这一篇就够了,简单易懂](docs/oo/interface.md)
- [Java 抽象类和接口的区别,看这一篇就够了](docs/oo/abstract-vs-interface.md)
- [Java内部类详解:成员内部类、局部内部类、匿名内部类、静态内部类](docs/oo/inner-class.md)
- [Java中this和super的用法总结](docs/oo/this-super.md)
- [Java 方法重写 Override 和方法重载 Overload 的区别,一下子就明白了](docs/basic-extra-meal/override-overload.md)
- [一文彻底搞懂 Java static 关键字:静态变量、静态方法、静态代码块、静态内部类](docs/oo/static.md)
- [一文彻底搞懂 Java final 关键字](docs/oo/final.md)
- [这次彻底搞清楚了 Java 的三大特征之一:封装](docs/oo/encapsulation.md)
- [一万字彻底搞懂 Java 继承(三大特征之一)](docs/oo/extends-bigsai.md)
- [几句话,直观解释清楚 Java 多态(三大特征之一)](docs/oo/polymorphism.md)
- [Java 抽象类和接口的区别](docs/oo/abstract-vs-interface.md)
- [聊聊Java内部类:成员内部类、局部内部类、匿名内部类、静态内部类](docs/oo/inner-class.md)
- [聊聊 Java 封装](docs/oo/encapsulation.md)
- [深入理解 Java 继承](docs/oo/extends-bigsai.md)
- [聊聊 Java 多态](docs/oo/polymorphism.md)
- [Java中this和super关键字的用法总结](docs/oo/this-super.md)
- [详解 static 关键字的作用:静态变量、静态方法、静态代码块、静态内部类](docs/oo/static.md)
- [一文彻底搞懂 final 关键字](docs/oo/final.md)
- [聊聊instanceof关键字](docs/basic-extra-meal/instanceof.md)
- [聊聊Java中的不可变对象](docs/basic-extra-meal/immutable.md)
- [方法重写 Override 和方法重载 Overload 有什么区别?](docs/basic-extra-meal/override-overload.md)
- [深入理解Java中的注解](docs/basic-extra-meal/annotation.md)
## 集合框架(容器)
......@@ -201,7 +207,6 @@
- [Java命名规范](docs/basic-extra-meal/java-naming.md)
- [彻底弄懂Java中的Unicode和UTF-8编码](docs/basic-extra-meal/java-unicode.md)
- [Java中new Integer与Integer.valueOf的区别](docs/basic-extra-meal/int-cache.md)
- [深入剖析Java中的拆箱和装箱](docs/basic-extra-meal/box.md)
- [一文彻底讲明白的Java中的浅拷贝与深拷贝](docs/basic-extra-meal/deep-copy.md)
- [深入理解Java中的hashCode方法](docs/basic-extra-meal/hashcode.md)
......@@ -209,16 +214,10 @@
- [Java重写(Overriding)时应当遵守的11条规则](docs/basic-extra-meal/Overriding.md)
- [Java到底是值传递还是引用传递?](docs/basic-extra-meal/pass-by-value.md)
- [详解Java中Comparable和Comparator接口的区别](docs/basic-extra-meal/comparable-omparator.md)
- [jdk9为什么要将String的底层实现由char数组改成了byte数组?](docs/basic-extra-meal/jdk9-char-byte-string.md)
- [为什么JDK源码中,无限循环大多使用for(;;)而不是while(true)?](docs/basic-extra-meal/jdk-while-for-wuxian-xunhuan.md)
- [Java 中,先有Class还是先有Object?](docs/basic-extra-meal/class-object.md)
- [详解Java中instanceof关键字的用法](docs/basic-extra-meal/instanceof.md)
- [instanceof关键字是如何实现的?](docs/basic-extra-meal/instanceof-jvm.md)
- [深入理解Java中的不可变对象](docs/basic-extra-meal/immutable.md)
- [Java中可变参数的使用](docs/basic-extra-meal/varables.md)
- [深入理解Java中的泛型](docs/basic-extra-meal/generic.md)
- [Java不能实现真正泛型的原因是什么?](docs/basic-extra-meal/true-generic.md)
- [深入理解Java中的注解](docs/basic-extra-meal/annotation.md)
- [新来个技术总监,彻底把 Java 枚举(enum)讲清楚了](docs/basic-extra-meal/enum.md)
- [大白话说清楚Java反射:入门、使用、原理](docs/basic-extra-meal/fanshe.md)
......
......@@ -115,6 +115,7 @@ export const sidebarConfig = sidebar({
"basic-grammar/javadoc",
"basic-grammar/basic-data-type",
"basic-grammar/type-cast",
"basic-extra-meal/int-cache",
"basic-grammar/operator",
"basic-grammar/flow-control",
],
......@@ -133,6 +134,7 @@ export const sidebarConfig = sidebar({
"string/equals",
"string/join",
"string/split",
"basic-extra-meal/jdk9-char-byte-string",
],
},
{
......@@ -143,6 +145,8 @@ export const sidebarConfig = sidebar({
"oo/package",
"oo/var",
"oo/method",
"basic-extra-meal/varables",
"oo/native-method",
"oo/construct",
"oo/access-control",
"oo/code-init",
......@@ -150,14 +154,16 @@ export const sidebarConfig = sidebar({
"oo/interface",
"oo/abstract-vs-interface",
"oo/inner-class",
"oo/this-super",
"basic-extra-meal/override-overload",
"oo/static",
"oo/final",
"oo/encapsulation",
"oo/extends-bigsai",
"oo/polymorphism",
"oo/this-super",
"oo/static",
"oo/final",
"basic-extra-meal/instanceof",
"basic-extra-meal/immutable",
"basic-extra-meal/override-overload",
"basic-extra-meal/annotation",
],
},
{
......@@ -235,9 +241,8 @@ export const sidebarConfig = sidebar({
prefix:"basic-extra-meal/",
collapsible: true,
children: [
"basic-extra-meal/java-naming",
"java-naming",
"java-unicode",
"int-cache",
"box",
"deep-copy",
"hashcode",
......@@ -245,16 +250,10 @@ export const sidebarConfig = sidebar({
"Overriding",
"pass-by-value",
"comparable-omparator",
"jdk9-char-byte-string",
"jdk-while-for-wuxian-xunhuan",
"class-object",
"instanceof",
"instanceof-jvm",
"immutable",
"varables",
"generic",
"true-generic",
"annotation",
"enum",
"fanshe",
],
......
......@@ -36,81 +36,6 @@ footer: |-
[![Star History Chart](https://api.star-history.com/svg?repos=itwanger/toBeBetterJavaer&type=Date)](https://star-history.com/#itwanger/toBeBetterJavaer&Date)
## 捐赠鼓励
开源不易,如果《Java程序员进阶之路》对你有些帮助,可以请作者喝杯咖啡,算是对开源做出的一点点鼓励吧!
<div align="left">
<img src="https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/weixin-zhifu.png" width="260px">
</div>
:gift_heart: 感谢大家对我资金的赞赏,每隔一个月会统计一次。
时间|小伙伴|赞赏金额
---|---|---
2023-02-11|昵*.|6.6元
2023-02-09|*明|10元
2023-02-09|*风|5元
2023-02-09|*z|3元
2023-02-09|*夫|10元
2023-02-08|*相|6元
2023-01-18|*念|0.01元
2023-01-18|*来|1元
2023-01-10|*A*t|1元
2023-01-07|*忠|5元
2023-12-02|g*g|0.1元
2022-11-13|*王|5元
2022-11-10|*车|1元
2022-11-10|F*k|1元
2022-11-05|*H|3元
2022-11-04|*千|0.02元
2022-11-04|*尘|15元
2022-11-02|*峰|1元
2022-11-10|*车|1元
2022-10-29|~*~|6元
2022-10-28|*官|1元
2022-10-20|*电|2元
2022-10-15|*深|5元
2022-09-30|*君|1元
2022-09-28|*懂|1元
2022-09-27|*府|1元
2022-09-23|*物|5元
2022-09-23|H*n|1元
2022-09-23|*a|0.01元
2022-09-08|*👀|20元
2022-09-07|丹*1|20元
2022-08-27|*夹|40元
2022-07-06|体*P|2元
2022-07-05|*谦|5元
2022-06-18|*杰|2元
2022-06-15|L*c|15元
2022-06-10|*❤|1元
2022-06-09|'*'|1元
2022-06-07|*勇|1元
2022-06-03|*张|1元
2022-05-12|*烟|10元
2022-04-25|*思|5元
2022-04-20|w*n|1元
2022-04-12|*生|10元
2022-03-04|袁*波|99元
2022-02-17|*色|1元
2022-02-17|M*y|1元
2022-01-28|G*R|6.6元
2022-01-20|*光|50元
2022-01-14|*浩|1元
2022-01-01|马*谊|6.6元
2022-01-01|刚*好|3.6元
2021-12-20|t*1|5 元
2021-10-26|*鱼|28 元
2021-10-11|*人|28 元
2021-09-01|S*n|6.6 元
2021-08-02|*秒|1 元
2021-06-13|*7| 28 元
2021-04-29|p*e|2 元
## 参与贡献
1. 如果你对本项目有任何建议或发现文中内容有误的,欢迎提交 issues 进行指正。
......
......@@ -12,7 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java二维数组,数组
---
# 4.2 聊聊Java的二维数组
# 4.2 二维数组
“二哥,今天我们简单过一下二维数组吧,挺简单的。”三妹放下手机对我说。
......
---
title: Java中常用的48个关键字和2个保留字
title: 简单过一下Java中常用的48个关键字和2个保留字
shortTitle: 48个关键字和2个保留字
category:
- Java核心
......@@ -12,7 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java保留字,Java关键字,关键字,保留字
---
# 3.1 Java中常用的48个关键字和2个保留字
# 3.1 48个关键字和2个保留字
“二哥,就之前你给我展示的 Java 代码中,有 public、static、void、main 等等,它们应该都是关键字吧?”三妹的脸上泛着甜甜的笑容,我想她在学习 Java 方面已经变得越来越自信了。
......
---
title: 深入理解Java中的注解
shortTitle: 深入理解Java中的注解
shortTitle: Java注解
category:
- Java核心
tag:
......@@ -9,12 +9,14 @@ description: Java程序员进阶之路,小白的零基础Java教程,从入
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,注解,annotation
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,注解,annotation,java 注解,java annotation
---
# 5.22 Java注解
“二哥,这节讲注解吗?”三妹问。
“是的。”我说,“注解是 Java 中非常重要的一部分,但经常被忽视也是真的。之所以这么说是因为我们更倾向成为一名注解的使用者而不是创建者。`@Override` 注解用过吧?但你知道怎么自定义一个注解吗?”
“是的。”我说,“注解是 Java 中非常重要的一部分,但经常被忽视也是真的。之所以这么说是因为我们更倾向成为一名注解的使用者而不是创建者。`@Override` 注解用过吧?[方法重写](https://tobebetterjavaer.com/basic-extra-meal/override-overload.html)的时候用到过。但你知道怎么自定义一个注解吗?”
三妹毫不犹豫地摇摇头,摆摆手,不好意思地承认自己的确没有自定义过。
......@@ -37,7 +39,7 @@ public class AutowiredTest {
}
```
注意到 `@Autowired` 这个注解了吧?它本来是为 Spring 容器注入 Bean 的,现在被我无情地扔在了字段 name 的身上,但这段代码所在的项目中并没有启用 Spring,意味着 `@Autowired` 注解此时只是一个摆设。
注意到 `@Autowired` 这个注解了吧?它本来是为 Spring(后面会讲)容器注入 Bean 的,现在被我无情地扔在了字段 name 的身上,但这段代码所在的项目中并没有启用 Spring,意味着 `@Autowired` 注解此时只是一个摆设。
“既然只是个摆设,那你这个地方为什么还要用 `@Autowired` 呢?”三妹好奇地问。
......
---
title: 深入理解Java中的不可变对象
shortTitle: 深入理解Java中的不可变对象
title: 聊聊Java中的不可变对象
shortTitle: Java中的不可变对象
category:
- Java核心
tag:
......@@ -12,14 +12,13 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,不可变对象,immutable
---
# 深入理解Java中的不可变对象
# 5.20 Java中的不可变对象
>二哥,你能给我说说为什么 String 是 immutable 类(不可变对象)吗?我想研究它,想知道为什么它就不可变了,这种强烈的愿望就像想研究浩瀚的星空一样。但无奈自身功力有限,始终觉得雾里看花终隔一层。二哥你的文章总是充满趣味性,我想一定能够说明白,我也一定能够看明白,能在接下来写一写吗?
“二哥,你能给我说说为什么 String 是 immutable 类(不可变对象)吗?我想研究它,想知道为什么它就不可变了,这种强烈的愿望就像想研究浩瀚的星空一样。但无奈自身功力有限,始终觉得雾里看花终隔一层。”三妹的这句话里满是彩虹屁的味道。
收到读者小 R 的私信后,我就总感觉自己有一种义不容辞的责任,非要把 immutable 类说明白不可!
“既然三妹你说话这么好听,那我们就开始吧!”我愉快的心情就好像吃了两罐蜂蜜一样(😂)。
## 01、什么是不可变类
### 01、什么是不可变类
一个类的对象在通过构造方法创建后如果状态不会再被改变,那么它就是一个不可变(immutable)类。它的所有成员变量的赋值仅在构造方法中完成,不会提供任何 setter 方法供外部类去修改。
......@@ -31,19 +30,19 @@ head:
假如说类是不可变的,那么对象的状态就也是不可变的。这样的话,每次修改对象的状态,就会产生一个新的对象供不同的线程使用,我们程序员就不必再担心并发问题了。
## 02、常见的不可变类
### 02、常见的不可变类
提到不可变类,几乎所有的程序员第一个想到的,就是 String 类。那为什么 String 类要被设计成不可变的呢?
1)常量池的需要
#### 1)常量池的需要
字符串常量池是 Java 堆内存中一个特殊的存储区域,当创建一个 String 对象时,假如此字符串在常量池中不存在,那么就创建一个;假如已经存,就不会再创建了,而是直接引用已经存在的对象。这样做能够减少 JVM 的内存开销,提高效率。
[字符串常量池](https://tobebetterjavaer.com/string/constant-pool.html)是 Java 堆内存中一个特殊的存储区域,当创建一个 String 对象时,假如此字符串在常量池中不存在,那么就创建一个;假如已经存,就不会再创建了,而是直接引用已经存在的对象。这样做能够减少 JVM 的内存开销,提高效率。
2)hashCode 的需要
#### 2)hashCode 需要
因为字符串是不可变的,所以在它创建的时候,其 hashCode 就被缓存了,因此非常适合作为哈希值(比如说作为 HashMap 的键),多次调用只返回同一个值,来提高效率。
因为字符串是不可变的,所以在它创建的时候,其 hashCode 就被缓存了,因此非常适合作为哈希值(比如说作为 [HashMap](https://tobebetterjavaer.com/collection/hashmap.html) 的键),多次调用只返回同一个值,来提高效率。
3)线程安全
#### 3)线程安全
就像之前说的那样,如果对象的状态是可变的,那么在多线程环境下,就很容易造成不可预期的结果。而 String 是不可变的,就可以在多个线程之间共享,不需要同步处理。
......@@ -59,19 +58,19 @@ System.out.println(cmower);// 沉默王二,一枚有趣的程序员
除了 String 类,包装器类 Integer、Long 等也是不可变类。
## 03、手撸不可变类
### 03、手撸一个不可变类
看懂一个不可变类也许容易,但要创建一个自定义的不可变类恐怕就有点难了。但知难而进是我们作为一名优秀的程序员不可或缺的品质,正因为不容易,我们才能真正地掌握它。
接下来,就请和我一起,来自定义一个不可变类吧。一个不可变类,必须要满足以下 4 个条件:
1)确保类是 final 的,不允许被其他类继承
**1)确保类是 final 的**,不允许被其他类继承*
2)确保所有的成员变量(字段)是 final 的,这样的话,它们就只能在构造方法中初始化值,并且不会在随后被修改。
**2)确保所有的成员变量(字段)是 final 的**,这样的话,它们就只能在构造方法中初始化值,并且不会在随后被修改。
3)不要提供任何 setter 方法
**3)不要提供任何 setter 方法**
4)如果要修改类的状态,必须返回一个新的对象
**4)如果要修改类的状态,必须返回一个新的对象**
按照以上条件,我们来自定义一个简单的不可变类 Writer。
......@@ -166,7 +165,7 @@ public final class Writer {
public class WriterDemo {
public static void main(String[] args) {
Book book = new Book();
book.setName("Web全栈开发进阶之路");
book.setName("二哥的 Java 进阶之路");
book.setPrice(79);
Writer writer = new Writer("沉默王二",18, book);
......@@ -180,8 +179,8 @@ public class WriterDemo {
程序输出的结果如下所示:
```java
定价Book{name='Web全栈开发进阶之路', price=79}
促销价Book{name='Web全栈开发进阶之路', price=59}
定价Book{name='二哥的 Java 进阶之路', price=79}
促销价Book{name='二哥的 Java 进阶之路', price=59}
```
糟糕,Writer 类的不可变性被破坏了,价格发生了变化。为了解决这个问题,我们需要为不可变类的定义规则追加一条内容:
......@@ -200,14 +199,22 @@ public Book getBook() {
这样的话,构造方法初始化后的 Book 对象就不会再被修改了。此时,运行 WriterDemo,就会发现价格不再发生变化了。
```
定价:Book{name='Web全栈开发进阶之路', price=79}
促销价:Book{name='Web全栈开发进阶之路', price=79}
定价:Book{name='二哥的 Java 进阶之路', price=79}
促销价:Book{name='二哥的 Java 进阶之路', price=79}
```
## 04、总结
### 04、总结
不可变类有很多优点,就像之前提到的 String 类那样,尤其是在多线程环境下,它非常的安全。尽管每次修改都会创建一个新的对象,增加了内存的消耗,但这个缺点相比它带来的优点,显然是微不足道的——无非就是捡了西瓜,丢了芝麻。
“好了,三妹,你应该理解了吧?”
“嗯,哥,你这本《Java 进阶之路》还没有出书吧?”三妹质疑道。
“害,出版社都找过来要签合同了,我只好推脱说 GitHub 破 1 万 star 再考虑,先优化吧,后面看机会。”
“哦哦,原来如此啊。”三妹释然道。
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
......
---
title: 详解Java中instanceof关键字的用法
shortTitle: instanceof关键字的用法
title: 聊聊instanceof关键字
shortTitle: instanceof关键字
category:
- Java核心
tag:
......@@ -9,9 +9,14 @@ description: Java程序员进阶之路,小白的零基础Java教程,从入
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,instanceof
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,instanceof,java instanceof
---
# 5.19 instanceof关键字
“三妹,今天我们来过一个非常简单的知识点,instanceof关键字。”
“用不着哥你来讲了,今天就换个形式,我来讲给你听。”三妹雄赳赳气昂昂地说。
instanceof 关键字的用法其实很简单:
......@@ -19,7 +24,7 @@ instanceof 关键字的用法其实很简单:
(object) instanceof (type)
```
用意也非常简单,判断对象是否符合指定的类型,结果要么是 true,要么是 false。在反序列化的时候,instanceof 操作符还是蛮常用的,因为这时候我们不太确定对象属不属于指定的类型,如果不进行判断的话,就容易抛出 ClassCastException 异常。
用意也非常简单,判断对象是否符合指定的类型,结果要么是 true,要么是 false。在[反序列化](https://tobebetterjavaer.com/io/serialize.html)的时候,instanceof 操作符还是蛮常用的,因为这时候我们不太确定对象属不属于指定的类型,如果不进行判断的话,就容易抛出 ClassCastException 异常。
我们来建这样一个简单的类 Round:
......@@ -109,9 +114,9 @@ Thread thread = new Thread();
System.out.println(thread instanceof Object);
```
“那如果对象为 null 呢?”三妹这时候插话了。
“那如果对象为 null 呢?”这时候插话了。
“这个还真的是一个好问题啊。”我忍不住对三妹竖了一个大拇指。
“这个还真的是一个好问题啊。”三妹忍不住对我竖了一个大拇指。
```java
System.out.println(null instanceof Object);
......@@ -142,9 +147,9 @@ if (obj instanceof String s) {
可以直接在 if 条件判断类型的时候添加一个变量,就不需要再强转和声明新的变量了。
“哇,这样就简洁了呀!”三妹不仅惊叹到!
“哇,这样就简洁了呀!”为了配合三妹,我不仅惊叹到!
好了,关于 instanceof 操作符我们就先讲到这吧,难是一点都不难,希望各位同学也能够很好的掌握
“好了,关于 instanceof 操作符我们就先讲到这吧,难是一点都不难,希望哥也能够很好的掌握。”三妹笑嘻嘻地说,看来她很享受这个讲的过程嘛
----
......
---
title: Java中new Integer与Integer.valueOf的区别
shortTitle: new Integer与Integer.valueOf的区别
title: 聊聊Java基本数据类型缓存池
shortTitle: Java基本数据类型缓存池
category:
- Java核心
tag:
- Java重要知识点
description: Java程序员进阶之路,小白的零基础Java教程,从入门到进阶,Java中new Integer与Integer.valueOf的区别
description: Java程序员进阶之路,小白的零基础Java教程,从入门到进阶,Java基本数据类型缓存池
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Integer
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Integer,java数据类型缓存池,java IntegerCache,Java 基本数据类型缓存池
---
“三妹,今天我们来补一个小的知识点:Java 数据类型缓存池。”我喝了一口枸杞泡的茶后对三妹说,“考你一个问题哈:`new Integer(18) 与 Integer.valueOf(18)` 的区别是什么?”
# 3.5 基本数据类型缓存池
“三妹,今天我们来补一个小的知识点:Java 基本数据类型缓存池。”我喝了一口枸杞泡的茶后对三妹说,“考你一个问题哈:`new Integer(18) 与 Integer.valueOf(18)` 的区别是什么?”
“难道不一样吗?”三妹有点诧异。
......@@ -111,9 +113,11 @@ private static class IntegerCache {
}
```
详细解释下:当我们通过 Integer.valueOf() 方法获取整数对象时,会先检查该整数是否在 IntegerCache 中,如果在,则返回缓存中的对象,否则创建一个新的对象并缓存起来。
需要注意的是,如果使用 new Integer() 创建对象,即使值在 -128 到 127 范围内,也不会被缓存,每次都会创建新的对象。因此,推荐使用 Integer.valueOf() 方法获取整数对象。
之前我们在[学习 static 关键字](https://tobebetterjavaer.com/oo/static.html)的时候,提到过静态代码块,还记得吧?三妹。静态代码块通常用来初始化一些静态变量,它会优先于 main() 方法执行。
[学习 static 关键字](https://tobebetterjavaer.com/oo/static.html)的时候,会详细解释静态代码块,你暂时先记住,三妹,静态代码块通常用来初始化一些静态变量,它会优先于 main() 方法执行。
在静态代码块中,low 为 -128,也就是缓存池的最小值;high 默认为 127,也就是缓存池的最大值,共计 256 个。
......@@ -169,9 +173,9 @@ Exception in thread "main" java.lang.AssertionError
“原来 assert 是这样用的啊,我明白了。”三妹表示学会了。
“那,缓存池之所以存在的原因也是因为这样做可以提高程序的整体性能,因为相对来说,比如说 Integer,-128~127 这个范围内的 256 个数字使用的频率会高一点。”我总结道
在 Java 中,针对一些基本数据类型(如 Integer、Long、Boolean 等),Java 会在程序启动时创建一些常用的对象并缓存在内存中,以提高程序的性能和节省内存开销。这些常用对象被缓存在一个固定的范围内,超出这个范围的值会被重新创建新的对象
“get 了!二哥你真棒,又学到了。”三妹很开心~
使用数据类型缓存池可以有效提高程序的性能和节省内存开销,但需要注意的是,在特定的业务场景下,缓存池可能会带来一些问题,例如缓存池中的对象被不同的线程同时修改,导致数据错误等问题。因此,在实际开发中,需要根据具体的业务需求来决定是否使用数据类型缓存池。
----
......
---
title: jdk9为什么要将String的底层实现由char数组改成了byte数组?
title: Java 9为什么要将String的底层实现由char数组改成了byte数组?
shortTitle: String的底层实现由char改成了byte?
category:
- Java核心
......@@ -9,18 +9,20 @@ description: Java程序员进阶之路,小白的零基础Java教程,从入
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,string,char,byte
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,string,char,byte,java string 底层实现,java字符串源码,java string char,java string byte,java string char byte,java
---
大家好,我是二哥呀!如果你不是 Java8 的钉子户,你应该早就发现了:String 类的源码已经由 `char[]` 优化为了 `byte[]` 来存储字符串内容,为什么要这样做呢?
# 4.11 Java 9为什么要将String的底层实现由char数组改成了byte数组?
开门见山地说,从 `char[]``byte[]`,最主要的目的是**为了节省字符串占用的内存**。内存占用减少带来的另外一个好处,就是 GC 次数也会减少。
“二哥,最近在我阅读 Java 11 的字符串源码,发现和 Java 8 的有很大不同。”三妹的脸上洋溢着青春的微笑😊,甜美地说道:“String 类的源码已经由 `char[]` 优化为了 `byte[]` 来存储字符串内容,为什么要这样做呢?”
## 一、为什么要优化 String 节省内存空间
“开门见山地说,从 `char[]``byte[]`,最主要的目的是**节省字符串占用的内存空间**。内存占用减少带来的另外一个好处,就是 GC 次数也会减少。”我用右手的大拇指凑了一下眼镜解释道。
### 为什么要优化?
我们使用 `jmap -histo:live pid | head -n 10` 命令就可以查看到堆内对象示例的统计信息、查看 ClassLoader 的信息以及 finalizer 队列。
以我正在运行着的编程喵喵项目实例(基于 Java 8)来说,结果是这样的。
以我正在运行着的[编程喵](https://github.com/itwanger/coding-more)项目实例(基于 Java 8)来说,结果是这样的。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/basic-extra-meal/jdk9-char-byte-string-d826ce88-bbbe-47a3-a1a9-4dd86dd3632f.png)
......@@ -30,17 +32,15 @@ head:
`char[]` 对象有 17673 个,占用了 1621352 个字节的内存,排在第一位。
那也就是说优化 String 节省内存空间是非常有必要的,如果是去优化一个使用频率没有 String 这么高的类库,就显得非常的鸡肋。
## 二、`byte[]` 为什么就能节省内存空间呢?
众所周知,char 类型的数据在 JVM 中是占用两个字节的,并且使用的是 UTF-8 编码,其值范围在 '\u0000'(0)和 '\uffff'(65,535)(包含)之间。
那也就是说优化 String 节省内存空间是非常有必要的,如果是去优化一个使用频率没有 String 这么高的类,就没什么必要,对吧?
### 为什么能节省内存空间?
众所周知,char 类型的数据在 JVM 中是占用两个字节的,并且使用的是 UTF-8 [编码](https://tobebetterjavaer.com/basic-extra-meal/java-unicode.html),其值范围在 '\u0000'(0)和 '\uffff'(65,535)(包含)之间。
也就是说,使用 `char[]` 来表示 String 就导致了即使 String 中的字符只用一个字节就能表示,也得占用两个字节。
也就是说,使用 `char[]` 来表示 String 就会导致,即使 String 中的字符只用一个字节就能表示,也得占用两个字节。
而实际开发中,单字节的字符使用频率仍然要高于双字节的
>PS:在计算机中,单字节字符通常指的是一个字节(8位)可以表示的字符,而双字节字符则指需要两个字节(16位)才能表示的字符。单字节字符和双字节字符的定义是相对的,不同的编码方式对应的单字节和双字节字符集也不同。常见的单字节字符集有ASCII(美国信息交换标准代码)、ISO-8859(国际标准化组织标准编号8859)、GBK(汉字内码扩展规范)、GB2312(中国国家标准,现在已经被GBK取代),像拉丁字母、数字、标点符号、控制字符都是单字节字符。双字节字符集包括 Unicode、UTF-8、GB18030(中国国家标准),中文、日文、韩文、拉丁文扩展字符属于双字节字符
当然了,仅仅将 `char[]` 优化为 `byte[]` 是不够的,还要配合 Latin-1 的编码方式,该编码方式是用单个字节来表示字符的,这样就比 UTF-8 编码节省了更多的空间。
......@@ -81,7 +81,7 @@ Java 会根据字符串的内容自动设置为相应的编码,要么 Latin-1
也就是说,从 `char[]``byte[]`**中文是两个字节,纯英文是一个字节,在此之前呢,中文是两个字节,英文也是两个字节**
## 三、为什么用UTF-16而不用UTF-8呢?
### 为什么用UTF-16而不用UTF-8呢?
在 UTF-8 中,0-127 号的字符用 1 个字节来表示,使用和 ASCII 相同的编码。只有 128 号及以上的字符才用 2 个、3 个或者 4 个字节来表示。
......@@ -95,13 +95,9 @@ Java 会根据字符串的内容自动设置为相应的编码,要么 Latin-1
- 1110xxxx 10xxxxxx 10xxxxxx:三字节编码形式(开始三个 1);
- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx:四字节编码形式(开始四个 1)。
关于字符编码,我在《Java程序员进阶之路》里曾讲到过,想要深入了解的小伙伴查看下面的链接🔗:
>https://tobebetterjavaer.com/basic-extra-meal/java-unicode.html
也就是说,UTF-8 是变长的,那对于 String 这种有随机访问方法的类来说,就很不方便。所谓的随机访问,就是charAt、subString这种方法,随便指定一个数字,String要能给出结果。如果字符串中的每个字符占用的内存是不定长的,那么进行随机访问的时候,就需要从头开始数每个字符的长度,才能找到你想要的字符。
有小伙伴可能会问,UTF-16也是变长的呢?一个字符还可能占用 4 个字节呢?
三妹可能会问,UTF-16也是变长的呢?一个字符还可能占用 4 个字节呢?
的确,UTF-16 使用 2 个或者 4 个字节来存储字符。
......@@ -114,6 +110,14 @@ Java 会根据字符串的内容自动设置为相应的编码,要么 Latin-1
>参考链接:[https://www.zhihu.com/question/447224628](https://www.zhihu.com/question/447224628)
“好了,三妹,那关于Java 9为什么要将String的底层实现由char数组改成了byte数组就聊到这里吧。”我对三妹说,“有时候,读一读源码确实能成长很多,多问问为什么,挺好!”
“是啊,任何知识想要深入去学习,就能挖掘出来很多。”三妹说,“比如说今天聊到的UTF-16和UTF-8。”
“好了,我要去回答星球球友的提问了,你可以休息会,比如说听听 H.O.T 的歌,真不错。”
“哈哈,没想到,哥你也是个 H.O.T 的粉丝啊!”
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
......
---
title: Java 方法重写 Override 和方法重载 Overload 的区别,一下子就明白了
shortTitle: Java 方法重写和方法重载的区别
title: 方法重写 Override 和方法重载 Overload 有什么区别?
shortTitle: 方法重写和方法重载
description: Java程序员进阶之路,小白的零基础Java教程,Java 中方法重写 Override 和方法重载 Overload 的区别
category:
- Java 核心
......@@ -9,16 +9,16 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,方法重写,方法重载,Override,Overload
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,方法重写,方法重载,Override,Overload,java 方法重载 方法重写,java Override Overload,java 方法重载,java 方法重写
---
## 01、开篇
# 5.21 方法重写和方法重载
入冬的夜,总是来得特别的早。我静静地站在阳台,目光所及之处,不过是若隐若现的钢筋混凝土,还有那毫无情调的灯光。
“哥,别站在那发呆了。今天学啥啊,七点半我就要回学校了,留给你的时间不多了,你要抓紧哦。”三妹傲娇的声音一下子把我从游离的状态拉回到了现实。
“今天要学习 Java 中的方法重载与方法重写。”我迅速地走到电脑前面,打开一份 Excel 文档,看了一下《教妹学 Java》的进度,然后对三妹说。
“今天要学习 Java 中的方法重载与方法重写。”我迅速地走到电脑前面,打开一份 Excel 文档,看了一下《教妹学 Java(二哥的 Java 进阶之路前身)》的进度,然后对三妹说。
“如果一个类有多个名字相同但参数个数不同的方法,我们通常称这些方法为方法重载。 ”我面带着朴实无华的微笑继续说,“如果方法的功能是一样的,但参数不同,使用相同的名字可以提高程序的可读性。”
......@@ -34,7 +34,7 @@ head:
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/core-points/21-01.png)
## 02、方法重载
### 01、方法重载
“三妹,你仔细听哦。”我缓了一口气后继续说道。
......@@ -144,7 +144,7 @@ String[] args
“由于可以通过改变参数类型的方式实现方法重载,那么当传递的参数没有找到匹配的方法时,就会发生隐式的类型转换。”
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/core-points/21-03.png)
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/basic-extra-meal/override-overload-0d30f41f-1f53-4988-b506-731d79ed16d1.png)
“如上图所示,byte 可以向上转换为 short、int、long、float 和 double,short 可以向上转换为 int、long、float 和 double,char 可以向上转换为 int、long、float 和 double,依次类推。”
......@@ -223,7 +223,7 @@ public class OverloadingTypePromotion2 {
“不明确,编译器会很为难,究竟是把第一个 20 从 int 转成 long 呢,还是把第二个 20 从 int 转成 long,智障了!所以,不能写这样让编译器左右为难的代码。”
## 03、方法重写
### 02、方法重写
“三妹,累吗?我们稍微休息一下吧。”我把眼镜摘下来,放到桌子上,闭上了眼睛,开始胡思乱想起来。
......@@ -296,7 +296,7 @@ class Vehicle {
“Bike 重写了 `run()` 方法,也就意味着,Bike 可以跑出自己的风格。”
## 04、总结
### 03、总结
“好了,三妹,我来简单做个总结。”我瞥了一眼电脑右上角的时钟,离三妹离开的时间不到 10 分钟了。
......
---
title: 详解Java中可变参数的使用
shortTitle: 详解Java中可变参数的使用
title: 聊聊Java中的可变参数
shortTitle: Java中的可变参数
category:
- Java核心
tag:
......@@ -9,12 +9,12 @@ description: Java程序员进阶之路,小白的零基础Java教程,从入
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,可变参数
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java,可变参数,java 可变参数
---
# 详解Java中可变参数的使用
# 5.5 Java中的可变参数
为了让铁粉们能白票到阿里云的服务器,老王当了整整两天的客服,真正体验到了什么叫做“为人民群众谋福利”的不易和辛酸。正在他眼睛红肿打算要休息之际,小二跑过来问他:“Java 的可变参数究竟是怎么一回事?”老王一下子又清醒了,他爱 Java,他爱传道解惑,他爱这群尊敬他的读者
为了让铁粉们能白票到阿里云的服务器,我当了整整两天的客服,真正体验到了什么叫做“为人民群众谋福利”的不易和辛酸。正在我眼睛红肿打算要休息之际,三妹跑过来问:“Java 的可变参数究竟是怎么一回事?”我一下子又清醒了,我爱 Java,我爱传道解惑,也享受三妹的赞许(😂)
可变参数是 Java 1.5 的时候引入的功能,它允许方法使用任意多个、类型相同(`is-a`)的值作为参数。就像下面这样。
......@@ -43,10 +43,7 @@ public static void print(String... strs) {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/basic-extra-meal/varables-02.png)
可变参数看起来就像是个语法糖,它背后究竟隐藏了什么呢?老王想要一探究竟,它在追求真理这条路上一直很执着。
可变参数看起来就像是个语法糖,它背后究竟隐藏了什么呢?让我们来一探究竟,在追求真理这条路上我们要执着。
其实也很简单。**当使用可变参数的时候,实际上是先创建了一个数组,该数组的大小就是可变参数的个数,然后将参数放入数组当中,再将数组传递给被调用的方法**
......@@ -69,11 +66,7 @@ public static void print(String... strs) {
那如果方法的参数是一个数组,然后像使用可变参数那样去调用方法的时候,能行得通吗?
*留个思考题,大家也可以去试一试*
那一般什么时候使用可变参数呢?
“三妹,给你留个思考题:一般什么时候使用可变参数呢?”
可变参数,可变参数,顾名思义,当一个方法需要处理任意多个相同类型的对象时,就可以定义可变参数。Java 中有一个很好的例子,就是 String 类的 `format()` 方法,就像下面这样。
......@@ -86,7 +79,7 @@ System.out.println(String.format("年纪是: %d 名字是: %s", 18, "沉默王
如果不使用可变参数,那需要格式化的参数就必须使用“+”号操作符拼接起来了。麻烦也就惹上身了。
在实际的项目代码中,开源包 slf4j.jar 的日志输出就经常要用到可变参数(log4j 就没法使用可变参数,日志中需要记录多个参数时就痛苦不堪了)。就像下面这样。
在实际的项目代码中,[slf4j](https://tobebetterjavaer.com/gongju/slf4j.html) 的日志输出就经常要用到可变参数([log4j](https://tobebetterjavaer.com/gongju/log4j.html) 就没法使用可变参数,日志中需要记录多个参数时就痛苦不堪了)。就像下面这样。
```java
protected Logger logger = LoggerFactory.getLogger(getClass());
......@@ -100,7 +93,7 @@ logger.debug("名字是{},年纪是{}", mem.getName(), mem.getAge());
public void debug(String format, Object... arguments);
```
那在使用可变参数的时候有什么注意事项吗?
“那在使用可变参数的时候有什么注意事项吗?”三妹问。
有的。我们要避免重载带有可变参数的方法——这样很容易让编译器陷入自我怀疑中。
......@@ -126,7 +119,6 @@ public static void print(Integer... ints) {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/basic-extra-meal/varables-03.png)
假如真的需要重载带有可变参数的方法,就必须在调用方法的时候给出明确的指示,不要让编译器去猜。
```java
......@@ -147,6 +139,10 @@ public static void print(Integer... ints) {
上面这段代码是可以编译通过的。因为编译器知道参数是 String 类型还是 Integer 类型,只不过为了运行时不抛出 `NullPointerException`,两个 `print()` 方法的内部要做好判空操作。
“好了,关于可变参数,我们就先讲到这里吧。三妹,你都理解了吧?”
“嗯嗯,不难,我理解了,哥。”三妹最近的学习状态真不错,能看得出来,她有在认真地做笔记📒。
---
......
......@@ -12,7 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java流程控制语句,Java判断语句,Java循环语句,if,switch,while,do-while,for
---
# 3.5 Java流程控制语句
# 3.7 Java流程控制语句
“二哥,流程控制语句都有哪些呢?”三妹的脸上泛着甜甜的笑容,她开始对接下来要学习的内容充满期待了,这正是我感到欣慰的地方。
......
......@@ -12,7 +12,11 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java 简介,数据类型转换,强制数据类型转换,自动类型转换,java类型转换
---
# 3.4 Java数据类型转换(强制类型转换+自动类型转换)
# 3.4 Java数据类型转换
“三妹,今天我们来聊聊 Java 中的数据类型转换。”我开门见山地对三妹说。
“好啊。”三妹愉快地说。
数据类型转换发生在所赋值的数值类型和接收数据的变量类型不一致的时候,它需要从一种数据类型转换成另一种数据类型。数据类型的转换可以分为隐式转换(自动类型转换)和显式转换(强制类型转换)两种。
......@@ -36,9 +40,9 @@ head:
```java
public static void main(String[] args) {
float price1 = 10.9f; // 定义牙膏的价格
double price2 = 5.8; // 定义面巾纸的价格
int num1 = 2; // 定义牙膏的数量
float price1 = 10.9f; // 定义牙膏的价格,单精度浮点型float
double price2 = 5.8; // 定义面巾纸的价格,双精度浮点型double
int num1 = 2; // 定义牙膏的数量,整型 int
int num2 = 4; // 定义面巾纸的数量
double res = price1 * num1 + price2 * num2; // 计算总价
System.out.println("一共付给收银员" + res + "元"); // 输出总价
......@@ -63,7 +67,6 @@ b = b * 2; // Type mismatch: cannot convert from int to byte
如上所示,第二行会报“类型不匹配:无法从int转换为byte”错误。
该程序试图将一个完全合法的 byte 型的值 `50*2` 存储给一个 byte 型的变量。但是当表达式求值的时候,操作数被自动的提升为 int 型,计算结果也被提升为 int 型。这样表达式的结果现在是 int 型,不强制转换它就不能被赋为 byte 型。
所以应该使用一个显示的强制类型转换,例如:
......@@ -80,11 +83,13 @@ b = (byte)(b*2);
### 强制类型转换
尽管自动类型转换是很有帮助的,但并不能满足所有的编程需要。例如,如果你需要将 double 型的值赋给一个 int 型的变量,你将怎么办?
尽管自动类型转换是很有帮助的,但并不能满足所有的编程需要。
“例如,三妹,注意听哦,如果你需要将 double 型的值赋给一个 int 型的变量,你将怎么办?”我瞅准时机,对三妹提出了这个问题,“这种转换不会自动进行,因为 double 型的变化范围比 int 型的要小。这种转换有使成为“缩小转换”,因为你肯定要将源数据类型的值变小才能适合目标数据类型。”
这种转换不会自动进行,因为 double 型的变化范围比 int 型的要小。这种转换有使成为“缩小转换”,因为你肯定要将源数据类型的值变小才能适合目标数据类型
“我不会啊!”三妹有点难为情地说
所以当两种数据类型不兼容,或目标类型的取值范围小于源类型时,自动转换将无法进行,这时就需要进行强制类型转换。其语法格式如下:
“当两种数据类型不兼容,或目标类型的取值范围小于源类型时,自动转换将无法进行,这时就需要进行强制类型转换。其语法格式如下”,我喝了一口拿铁说到。
```java
(type)variableName
......
......@@ -114,12 +114,14 @@ head:
### Java基础语法
- [Java中常用的48个关键字 & 2个保留字](basic-extra-meal/48-keywords.md)
- [简单过一下Java中常用的48个关键字和2个保留字](basic-extra-meal/48-keywords.md)
- [Java注释](basic-grammar/javadoc.md)
- [Java 中的数据类型](basic-grammar/basic-data-type.md)
- [Java 数据类型转换](basic-grammar/type-cast.md)
- [Java流程控制语句](basic-grammar/flow-control.md)
- [Java中的数据类型(8种基本数据类型和引用数据类型)](basic-grammar/basic-data-type.md)
- [Java数据类型转换(强制类型转换+自动类型转换)](basic-grammar/type-cast.md)
- [聊聊Java基本数据类型缓存池](basic-extra-meal/int-cache.md)
- [Java运算符](basic-grammar/operator.md)
- [Java流程控制语句](basic-grammar/flow-control.md)
### 数组&字符串
......@@ -133,27 +135,33 @@ head:
- [Java如何判断两个字符串是否相等?](string/equals.md)
- [最优雅的Java字符串拼接是哪种方式?](string/join.md)
- [如何在Java中优雅地分割String字符串?](string/split.md)
- [Java 9为什么要将String的底层实现由char数组改成了byte数组?](basic-extra-meal/jdk9-char-byte-string.md)
### 面向对象编程
- [怎么理解Java中的类和对象?](oo/object-class.md)
- [Java 包,优雅地解决类名冲突](oo/package.md)
- [一文彻底讲清楚Java中的类和对象](oo/object-class.md)
- [简单过了一下Java中的包](oo/package.md)
- [Java中的变量:局部变量、成员变量、静态变量、常量](oo/var.md)
- [Java中的方法:实例方法、静态方法、抽象方法](oo/method.md)
- [Java中的构造方法:对象创建时的必经之路](oo/construct.md)
- [聊聊Java中的可变参数](basic-extra-meal/varables.md)
- [手把手教你用 C语言实现 Java native 方法](oo/native-method.md)
- [构造方法:Java对象创建时的必经之路](oo/construct.md)
- [聊一聊Java中的访问权限修饰符](oo/access-control.md)
- [Java中的代码初始化块:对成员变量进行更复杂的赋值](oo/code-init.md)
- [Java中的代码初始化块](oo/code-init.md)
- [Java抽象类,看这一篇就够了,豁然开朗](oo/abstract.md)
- [Java接口,看这一篇就够了,简单易懂](oo/interface.md)
- [Java 抽象类和接口的区别,看这一篇就够了](oo/abstract-vs-interface.md)
- [Java内部类详解:成员内部类、局部内部类、匿名内部类、静态内部类](oo/inner-class.md)
- [Java中this和super的用法总结](oo/this-super.md)
- [Java 方法重写 Override 和方法重载 Overload 的区别,一下子就明白了](basic-extra-meal/override-overload.md)
- [一文彻底搞懂 Java static 关键字:静态变量、静态方法、静态代码块、静态内部类](oo/static.md)
- [一文彻底搞懂 Java final 关键字](oo/final.md)
- [这次彻底搞清楚了 Java 的三大特征之一:封装](oo/encapsulation.md)
- [一万字彻底搞懂 Java 继承(三大特征之一)](oo/extends-bigsai.md)
- [几句话,直观解释清楚 Java 多态(三大特征之一)](oo/polymorphism.md)
- [Java 抽象类和接口的区别](oo/abstract-vs-interface.md)
- [聊聊Java内部类:成员内部类、局部内部类、匿名内部类、静态内部类](oo/inner-class.md)
- [聊聊 Java 封装](oo/encapsulation.md)
- [深入理解 Java 继承](oo/extends-bigsai.md)
- [聊聊 Java 多态](oo/polymorphism.md)
- [Java中this和super关键字的用法总结](oo/this-super.md)
- [详解 static 关键字的作用:静态变量、静态方法、静态代码块、静态内部类](oo/static.md)
- [一文彻底搞懂 final 关键字](oo/final.md)
- [聊聊instanceof关键字](basic-extra-meal/instanceof.md)
- [聊聊Java中的不可变对象](basic-extra-meal/immutable.md)
- [方法重写 Override 和方法重载 Overload 有什么区别?](basic-extra-meal/override-overload.md)
- [深入理解Java中的注解](basic-extra-meal/annotation.md)
### 集合框架(容器)
......@@ -211,7 +219,6 @@ head:
- [Java命名规范](basic-extra-meal/java-naming.md)
- [彻底弄懂Java中的Unicode和UTF-8编码](basic-extra-meal/java-unicode.md)
- [Java中new Integer与Integer.valueOf的区别](basic-extra-meal/int-cache.md)
- [深入剖析Java中的拆箱和装箱](basic-extra-meal/box.md)
- [一文彻底讲明白的Java中的浅拷贝与深拷贝](basic-extra-meal/deep-copy.md)
- [深入理解Java中的hashCode方法](basic-extra-meal/hashcode.md)
......@@ -219,16 +226,10 @@ head:
- [Java重写(Overriding)时应当遵守的11条规则](basic-extra-meal/Overriding.md)
- [Java到底是值传递还是引用传递?](basic-extra-meal/pass-by-value.md)
- [详解Java中Comparable和Comparator接口的区别](basic-extra-meal/comparable-omparator.md)
- [jdk9为什么要将String的底层实现由char数组改成了byte数组?](basic-extra-meal/jdk9-char-byte-string.md)
- [为什么JDK源码中,无限循环大多使用for(;;)而不是while(true)?](basic-extra-meal/jdk-while-for-wuxian-xunhuan.md)
- [Java 中,先有Class还是先有Object?](basic-extra-meal/class-object.md)
- [详解Java中instanceof关键字的用法](basic-extra-meal/instanceof.md)
- [instanceof关键字是如何实现的?](basic-extra-meal/instanceof-jvm.md)
- [深入理解Java中的不可变对象](basic-extra-meal/immutable.md)
- [Java中可变参数的使用](basic-extra-meal/varables.md)
- [深入理解Java中的泛型](basic-extra-meal/generic.md)
- [Java不能实现真正泛型的原因是什么?](basic-extra-meal/true-generic.md)
- [深入理解Java中的注解](basic-extra-meal/annotation.md)
- [新来个技术总监,彻底把 Java 枚举(enum)讲清楚了](basic-extra-meal/enum.md)
- [大白话说清楚Java反射:入门、使用、原理](basic-extra-meal/fanshe.md)
......
此差异已折叠。
---
title: Java 抽象类和接口的区别,看这一篇就够了
shortTitle: Java抽象类和接口的区别
shortTitle: 抽象类和接口的区别
description: Java程序员进阶之路,小白的零基础Java教程,认真聊聊 Java抽象类和接口的区别
category:
- Java 核心
......@@ -9,16 +9,21 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java 接口,接口,interface
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java 抽象类 接口,java interface abstract
---
通过前面两篇,我们已经深入地了解了 Java 抽象类和 Java 接口,那这篇我们来重点说一下抽象类和接口之间的区别。
# 5.12 抽象类和接口的区别
## 01、抽象类
“三妹,通过前面两篇,我们已经深入地了解了 Java [抽象类](https://tobebetterjavaer.com/oo/abstract.html)和 Java [接口](https://tobebetterjavaer.com/oo/interface.html),那这篇我们来重点说一下抽象类和接口之间的区别。”我放下手中的鼠标和键盘,转向右手边,对三妹说。
“好啊。我挺想总结一波的,也算是对抽象类和接口做个了结。”三妹回应到。
### 01、抽象类
在 Java 中,通过关键字 `abstract` 定义的类叫做抽象类。Java 是一门面向对象的语言,因此所有的对象都是通过类来描述的;但反过来,并不是所有的类都是用来描述对象的,抽象类就是其中的一种。
以下示例展示了一个简单的抽象类:
```java
// 个人认为,一名教练必须攻守兼备
abstract class Coach {
......@@ -28,15 +33,15 @@ abstract class Coach {
}
```
## 02、接口
### 02、接口
我们知道,有抽象方法的类被称为抽象类,也就意味着抽象类中还能有不是抽象方法的方法。这样的类就不能算作纯粹的接口,尽管它也可以提供接口的功能——只能说抽象类是普通类与接口之间的一种中庸之道。
**接口(英文:Interface),在 Java 中是一个抽象类型,是抽象方法的集合**;接口通过关键字 `interface` 来定义。接口与抽象类的不同之处在于:
1、抽象类可以有方法体的方法,但接口没有
2、接口中的成员变量隐式为 `static final`,但抽象类不是的。
3、一个类可以实现多个接口,但只能继承一个抽象类。
- 1、抽象类可以有方法体的方法,但接口没有(Java 8 以前)
- 2、接口中的成员变量隐式为 `static final`,但抽象类不是的。
- 3、一个类可以实现多个接口,但只能继承一个抽象类。
以下示例展示了一个简单的接口:
......@@ -53,21 +58,20 @@ interface Coach {
- 接口的每个方法都是隐式抽象的,所以同样不需要使用 `abstract` 关键字;
- 接口中的方法都是隐式 `public` 的。
## 03、两者差别
### 03、两者差别
“哦,我理解了哥。那我再问一下,抽象类和接口有什么差别呢?”
“哇,三妹呀,你这个问题恰到好处,问到了点子上。”我不由得为三妹竖起了大拇指。
1)语法层面上
#### 1)语法层面上
- 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法;
- 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的;
- 接口中不能含有静态代码块,而抽象类可以有静态代码块;
- 一个类只能继承一个抽象类,而一个类却可以实现多个接口。
2)设计层面上
#### 2)设计层面上
抽象类是对一种事物的抽象,即对类抽象,继承抽象类的子类和抽象类本身是一种 `is-a` 的关系。而接口是对行为的抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。
......
......@@ -12,16 +12,15 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java抽象类,抽象类
---
# 5.10 Java抽象类
“二哥,你这明显加快了更新的频率呀!”三妹对于我最近的肝劲由衷的佩服了起来。
“哈哈,是呀,我要给广大的学弟学妹们一个完整的 Java 学习体系。”我对未来充满了信心。
“哈哈,是呀,我要给广大的学弟学妹们一个完整的 Java 学习体系,记住我们的口号,**学 Java 就上二哥的 Java 进阶之路**。”我对未来充满了信心。
“那就开始吧。”三妹说。
---
## 定义抽象类
### 01、定义抽象类
定义抽象类的时候需要用到关键字 `abstract`,放在 `class` 关键字前,就像下面这样。
......@@ -30,9 +29,9 @@ abstract class AbstractPlayer {
}
```
关于抽象类的命名,《阿里的 Java 开发手册》上有强调,“抽象类命名要使用 Abstract 或 Base 开头”,这条规约还是值得遵守的
关于抽象类的命名,《[阿里的 Java 开发手册](https://tobebetterjavaer.com/pdf/ali-java-shouce.html)》上有强调,“抽象类命名要使用 Abstract 或 Base 开头”,这条规约还是值得遵守的,真正做到名如其意
## 抽象类的特征
### 02、抽象类的特征
抽象类是不能实例化的,尝试通过 `new` 关键字实例化的话,编译器会报错,提示“类是抽象的,不能实例化”。
......@@ -82,13 +81,13 @@ public class BasketballPlayer extends AbstractPlayer {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/abstract-04.png)
## 抽象类的应用场景
### 03、抽象类的应用场景
“二哥,抽象方法我明白了,那什么时候使用抽象方法呢?能给我讲讲它的应用场景吗?”三妹及时的插话道。
“这问题问的恰到好处呀!”我扶了扶眼镜继续说。
### **第一种场景**
#### **01)第一种场景**
当我们希望一些通用的功能被多个子类复用的时候,就可以使用抽象类。比如说,AbstractPlayer 抽象类中有一个普通的方法 `sleep()`,表明所有运动员都需要休息,那么这个方法就可以被子类复用。
......@@ -130,7 +129,7 @@ footballPlayer.sleep();
这样是不是就实现了代码的复用呢?
### **第二种场景**
#### **02)第二种场景**
当我们需要在抽象类中定义好 API,然后在子类中扩展实现的时候就可以使用抽象类。比如说,AbstractPlayer 抽象类中定义了一个抽象方法 `play()`,表明所有运动员都可以从事某项运动,但需要对应子类去扩展实现,表明篮球运动员打篮球,足球运动员踢足球。
......@@ -162,23 +161,45 @@ public class FootballPlayer extends AbstractPlayer {
}
```
为了进一步展示抽象类的特性,我们再来看一个具体的示例。假设现在有一个文件,里面的内容非常简单,只有一个“Hello World”,现在需要有一个读取器将内容从文件中读取出来,最好能按照大写的方式,或者小写的方式来读。
为了进一步展示抽象类的特性,我们再来看一个具体的示例。
>PS:[网站](https://tobebetterjavaer.com/oo/abstract.html)评论区说涉及到了文件的读写以及 Java 8 的新特性,不适合新人,如果觉得自己实在是看不懂,跳过,等学了 IO 流再来看也行。如果说是为了复习 Java 基础知识,就不存在这个问题了。
假设现在有一个文件,里面的内容非常简单,只有一个“Hello World”,现在需要有一个读取器将内容从文件中读取出来,最好能按照大写的方式,或者小写的方式来读。
这时候,最好定义一个抽象类 BaseFileReader:
```java
/**
* 抽象类,定义了一个读取文件的基础框架,其中 mapFileLine 是一个抽象方法,具体实现需要由子类来完成
*/
abstract class BaseFileReader {
protected Path filePath;
protected Path filePath; // 定义一个 protected 的 Path 对象,表示读取的文件路径
/**
* 构造方法,传入读取的文件路径
* @param filePath 读取的文件路径
*/
protected BaseFileReader(Path filePath) {
this.filePath = filePath;
}
/**
* 读取文件的方法,返回一个字符串列表
* @return 字符串列表,表示文件的内容
* @throws IOException 如果文件读取出错,抛出该异常
*/
public List<String> readFile() throws IOException {
return Files.lines(filePath)
.map(this::mapFileLine).collect(Collectors.toList());
return Files.lines(filePath) // 使用 Files 类的 lines 方法,读取文件的每一行
.map(this::mapFileLine) // 对每一行应用 mapFileLine 方法,将其转化为指定的格式
.collect(Collectors.toList()); // 将处理后的每一行收集到一个字符串列表中,返回
}
/**
* 抽象方法,子类需要实现该方法,将文件中的每一行转化为指定的格式
* @param line 文件中的每一行
* @return 转化后的字符串
*/
protected abstract String mapFileLine(String line);
}
```
......@@ -250,14 +271,14 @@ public class FileReaderTest {
[HELLO WORLD]
```
## 抽象类总结
### 04、抽象类总结
好了,对于抽象类我们简单总结一下:
1、抽象类不能被实例化。
2、抽象类应该至少有一个抽象方法,否则它没有任何意义。
3、抽象类中的抽象方法没有方法体。
4、抽象类的子类必须给出父类中的抽象方法的具体实现,除非该子类也是抽象类。
- 1、抽象类不能被实例化。
- 2、抽象类应该至少有一个抽象方法,否则它没有任何意义。
- 3、抽象类中的抽象方法没有方法体。
- 4、抽象类的子类必须给出父类中的抽象方法的具体实现,除非该子类也是抽象类。
“完了吗?二哥”三妹似乎还沉浸在聆听教诲的快乐中。
......
---
title: 聊一聊Java中的访问权限修饰符
shortTitle: 聊一聊Java中的访问权限修饰符
shortTitle: Java中的访问权限修饰符
description: Java程序员进阶之路,小白的零基础Java教程,聊一聊Java中的访问权限修饰符
category:
- Java 核心
......@@ -12,8 +12,13 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java访问权限修饰符,public,private,protected,访问权限修饰符
---
# 5.8 Java中的访问权限修饰符
我们先来讨论一下为什么需要访问权限控制。考虑两个场景:
“我们先来讨论一下为什么需要访问权限控制。其实之前我们在讲类和对象的时候有提到,今天我们来详细地聊一聊,三妹。”我开门见山地说,“三妹,你打开思维导图,记得做笔记哦。”
“好的。”三妹应声回答。
考虑两个场景:
场景 1:工程师 A 编写了一个类 ClassA,但是工程师 A 并不希望 ClassA 被其他类都访问到,该如何处理呢?
......@@ -30,20 +35,19 @@ head:
类只可以用默认访问权限和 public 修饰。比如说:
```
```java
public class Wanger{}
```
或者
```
```java
class Wanger{}
```
但变量和方法则都可以修饰。
## 1. 修饰类
### 1. 修饰类
- 默认访问权限(包访问权限):用来修饰类的话,表示该类只对同一个包中的其他类可见。
- public:用来修饰类的话,表示该类对其他所有的类都可见。
......@@ -53,7 +57,7 @@ class Wanger{}
Main.java:
```
```java
package com.tobetterjavaer.test1;
public class Main {
......@@ -68,7 +72,7 @@ public class Main {
People.java
```
```java
package com.tobetterjavaer.test1;
class People {//默认访问权限(包访问权限)
......@@ -95,7 +99,7 @@ class People {//默认访问权限(包访问权限)
People.java
```
```java
package com.tobetterjavaer.test2;
class People {//默认访问权限(包访问权限)
......@@ -128,7 +132,7 @@ class People {//默认访问权限(包访问权限)
正如上图的快速修正提示所示,将 People 类的默认访问权限更改为 public 的话,People 类对于 Main 类便可见了。
## 2. 修饰类的方法和变量
### 2. 修饰方法和变量
- 默认访问权限(包访问权限):如果一个类的方法或变量被包访问权限修饰,也就意味着只能在同一个包中的其他类中显示地调用该类的方法或者变量,在不同包中的类中不能显式地调用该类的方法或变量。
- private:如果一个类的方法或者变量被 private 修饰,那么这个类的方法或者变量只能在该类本身中被访问,在类外以及其他类中都不能显式的进行访问。
......@@ -142,7 +146,7 @@ Main.java 没有变化
People.java
```
```java
package com.tobebetterjavaer.test1;
public class People {
......@@ -167,7 +171,7 @@ public class People {
但是如果 People 类和 Main 类不在同一个包中:
```
```java
package com.tobebetterjavaer.test2; //与Main类处于不同包中
public class People {
......@@ -200,7 +204,7 @@ public class People {
People.java
```
```java
package com.tobebetterjavaer.test1;
public class People {
......@@ -225,7 +229,7 @@ public class People {
如果 People 类和 Main 类处于不同包中:
```
```java
package com.tobebetterjavaer.test2;
public class People {
......@@ -254,7 +258,7 @@ public class People {
如果在 com.cxh.test1 中定一个类 Man 继承 People,则可以在类 Man 中显示调用方法 getName 和 setName:
```
```java
package com.tobebetterjavaer.test1;
import com.tobebetterjavaer.test2.People;
......@@ -279,11 +283,15 @@ public class Man extends People {
另外,如果还存在其他类,这些类在包外是不可见的。如果源代码文件没有 public 类,则源代码文件的名称可以随意命名。
>原文链接:[https://www.cnblogs.com/dolphin0520/p/3734915.html](https://www.cnblogs.com/dolphin0520/p/3734915.html) 作者: Matrix海子,编辑:沉默王二
“三妹,理解了吧?”我问三妹。
“是的,很简单,换句话说,不想让别人看的就 private,想让人看的就 public,想同一个班级/部门看的就默认,想让下一级看的就 protected,对吧?哥”三妹很自信地回答。
----
“不错不错,总结得有那味了。”
>原文链接:[https://www.cnblogs.com/dolphin0520/p/3734915.html](https://www.cnblogs.com/dolphin0520/p/3734915.html) 作者: Matrix海子,编辑:沉默王二
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
......
---
title: Java中的代码初始化块:对成员变量进行更复杂的赋值
title: Java中的代码初始化块
shortTitle: Java中的代码初始化块
description: Java程序员进阶之路,小白的零基础Java教程,认真聊聊 Java中的代码初始化块:对成员变量进行更复杂的赋值
category:
......@@ -12,6 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java代码初始化块,代码初始化块
---
# 5.9 Java中的代码初始化块
“哥,今天我们要学习的内容是‘代码初始化块’,对吧?”看来三妹已经提前预习了我上次留给她的作业。
......@@ -86,7 +87,7 @@ public class Car {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/22-01.png)
“哦,原来如此啊!”三妹仿佛发现了新大陆,意味深长地说
“哦,原来如此啊!”三妹仿佛发现了新大陆,意味深长地说,“编译器把代码初始化块放到了构造方法中,怪不得。”
等三妹明白彻底搞明白后,我对她继续说道:“对于代码初始化来说,它有三个规则。”
......@@ -129,8 +130,9 @@ public class B extends A{
“这个例子再次印证了之前的第二条规则:代码初始化块是放在构造方法中执行的,只不过比较靠前。”
----
“好了,今天就先讲到这吧,中午休息一下,下午的精神会更足。”刚对三妹说完这句话,我的哈欠就上来了,好困。
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
......
---
title: Java中的构造方法:对象创建时的必经之路
shortTitle: Java 中的构造方法
title: 构造方法:Java对象创建时的必经之路
shortTitle: Java中的构造方法
description: Java程序员进阶之路,小白的零基础Java教程,认真聊聊 Java中的构造方法:对象创建时的必经之路
category:
- Java 核心
......@@ -9,31 +9,34 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java构造方法,构造方法
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java构造方法,构造方法,java construct
---
# 5.7 Java中的构造方法
我对三妹说,“上一节学了 Java 中的方法,接着学构造方法的话,难度就小很多了。”
“三妹,[上一节](https://tobebetterjavaer.com/oo/method.html)学了 Java 中的方法,接着学构造方法的话,难度就小很多了。”刚吃完中午饭,虽然有些困意,但趁机学个 10 分钟也是不错的,睡眠会更心满意足一些,于是我面露微笑地对三妹说。
“在 Java 中,构造方法是一种特殊的方法,当一个类被实例化的时候,就会调用构造方法。只有在构造方法被调用的时候,对象才会被分配内存空间。每次使用 `new` 关键字创建对象的时候,构造方法至少会被调用一次。”
“如果你在一个类中没有看见构造方法,并不是因为构造方法不存在,而是被缺省了,编译器会给这个类提供一个默认的构造方法。往大的方面说,就是,Java 有两种类型的构造方法:**无参构造方法和有参构造方法**。”
“如果你在一个类中没有看见构造方法,并不是因为构造方法不存在,而是被缺省了,编译器会给这个类提供一个默认的构造方法。就是说,Java 有两种类型的构造方法:**无参构造方法和有参构造方法**。”
“注意,之所以叫它构造方法,是因为对象在创建的时候,需要通过构造方法初始化值——就是描写对象的那些状态,对应的是类中的字段。”
“注意,之所以叫它构造方法,是因为对象在创建的时候,需要通过构造方法初始化值——描写对象有哪些初始化状态。”
## 01、创建构造方法的规则有哪些
“哥,你缓缓,一口气说这么多,也真有你的。”三妹听得聚精会神,但也知道关心她这个既当哥又当老师的二哥了。
### 01、创建构造方法的规则
构造方法必须符合以下规则:
- 构造方法的名字必须和类名一样;
- 构造方法没有返回类型,包括 void;
- 构造方法不能是抽象的、静态的、最终的、同步的,也就是说,构造方法不能通过 abstract、static、final、synchronized 关键字修饰
- 构造方法不能是抽象的(abstract)、静态的(static)、最终的(final)、同步的(synchronized)
简单解析一下最后一条规则。
- 由于构造方法不能被子类继承,所以用 final 和 abstract 修饰没有意义;
- 构造方法用于初始化一个对象,所以用 static 修饰没有意义;
- 多个线程不会同时创建内存地址相同的同一个对象,所以用 synchronized 修饰没有必要。
- 由于构造方法不能被子类继承,所以用 final 和 abstract 关键字修饰没有意义;
- 构造方法用于初始化一个对象,所以用 static 关键字修饰没有意义;
- 多个线程不会同时创建内存地址相同的同一个对象,所以用 synchronized 关键字修饰没有必要。
构造方法的语法格式如下:
......@@ -74,10 +77,10 @@ public class Demo {
`public Demo() {}` 才是真正的无参构造方法。
不过,可以使用访问权限修饰符(private、protected、public、default)来修饰构造方法,访问权限修饰符决定了构造方法的创建方式。
不过,可以使用[访问权限修饰符](https://tobebetterjavaer.com/oo/access-control.html)(private、protected、public、default)来修饰构造方法,访问权限修饰符决定了构造方法的创建方式。
## 02、什么是默认构造方法
### 02、默认构造方法
如果一个构造方法中没有任何参数,那么它就是一个默认构造方法,也称为无参构造方法。
......@@ -104,7 +107,7 @@ public class Bike {
一辆自行车被创建
```
通常情况下,无参构造方法是可以缺省的,我们开发者并不需要显式的声明无参构造方法,把这项工作交给编译器更轻松一些
通常情况下,无参构造方法是可以缺省的,我们开发者并不需要显式的声明无参构造方法,把这项工作交给编译器就可以了
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/18-01.png)
......@@ -136,7 +139,7 @@ public class Person {
在上面的例子中,默认构造方法初始化了 name 和 age 的值,name 是 String 类型,所以默认值为 null,age 是 int 类型,所以默认值为 0。如果没有默认构造方法的话,这项工作就无法完成了。
## 03、什么是有参构造方法
### 03、有参构造方法
有参数的构造方法被称为有参构造方法,参数可以有一个或多个。有参构造方法可以为不同的对象提供不同的值。当然,也可以提供相同的值。
......@@ -177,9 +180,9 @@ new ParamConstructorPerson("沉默王三",16);
如果没有有参构造方法的话,就需要通过 setter 方法给字段赋值了。
## 04、如何重载构造方法
### 04、重载构造方法
在 Java 中,构造方法和方法类似,只不过没有返回类型。它也可以像方法一样被重载。构造方法的重载也很简单,只需要提供不同的参数列表即可。编译器会通过参数的数量来决定应该调用哪一个构造方法。
在 Java 中,构造方法和方法类似,只不过没有返回类型。它也可以像方法一样被[重载](https://tobebetterjavaer.com/basic-extra-meal/override-overload.html)。构造方法的重载也很简单,只需要提供不同的参数列表即可。编译器会通过参数的数量来决定应该调用哪一个构造方法。
```java
/**
......@@ -218,7 +221,7 @@ public class OverloadingConstrutorPerson {
创建对象的时候,如果传递的是三个参数,那么就会调用 `OverloadingConstrutorPerson(String name, int age, int sex)` 这个构造方法;如果传递的是两个参数,那么就会调用 `OverloadingConstrutorPerson(String name, int age)` 这个构造方法。
## 05、构造方法和方法有什么区别
### 05、构造方法和方法的区别
构造方法和方法之间的区别还是蛮多的,比如说下面这些:
......@@ -226,7 +229,7 @@ public class OverloadingConstrutorPerson {
## 06、如何复制对象
### 06、复制对象
复制一个对象可以通过下面三种方式完成:
......@@ -234,7 +237,7 @@ public class OverloadingConstrutorPerson {
- 通过对象的值
- 通过 Object 类的 `clone()` 方法
1)通过构造方法
#### 1)通过构造方法
```java
/**
......@@ -270,7 +273,7 @@ public class CopyConstrutorPerson {
在上面的例子中,有一个参数为 CopyConstrutorPerson 的构造方法,可以把该参数的字段直接复制到新的对象中,这样的话,就可以在 new 关键字创建新对象的时候把之前的 p1 对象传递过去。
2)通过对象的值
#### 2)通过对象的值
```java
/**
......@@ -307,7 +310,7 @@ public class CopyValuePerson {
这种方式比较粗暴,直接拿 p1 的字段值复制给 p2 对象(`p2.name = p1.name`)。
3)通过 Object 类的 `clone()` 方法
#### 3)通过 Object 类的 `clone()` 方法
```java
/**
......@@ -343,7 +346,9 @@ public class ClonePerson implements Cloneable {
通过 `clone()` 方法复制对象的时候,ClonePerson 必须先实现 Cloneable 接口的 `clone()` 方法,然后再调用 `clone()` 方法(`ClonePerson p2 = (ClonePerson) p1.clone()`)。
## 07、ending
>拓展阅读:[浅拷贝与深拷贝](https://tobebetterjavaer.com/basic-extra-meal/deep-copy.html)
### 07、ending
“二哥,我能问一些问题吗?”三妹精神焕发,没有丝毫的疲惫。
......
---
title: 这次彻底搞清楚了 Java 的三大特征之一:封装
shortTitle: 这次彻底搞清楚 Java 封装
title: 聊聊Java封装
shortTitle: Java 封装
description: Java程序员进阶之路,小白的零基础Java教程,认真聊聊 Java的三大特征:封装
category:
- Java 核心
......@@ -12,7 +12,11 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java封装
---
## 关于封装
# 5.14 Java封装
“三妹,准备好了没,我们这节来讲 Java 封装,算是 Java 的三大特征之一,理清楚了,对以后的编程有较大的帮助。”我对三妹说。
“好的,哥,准备好了。”三妹一边听我说,一边迅速地打开了 XMind,看来一边学习一边总结思维导图这个高效的学习方式三妹已经牢记在心了。
封装从字面上来理解就是包装的意思,专业点就是信息隐藏,**是指利用抽象将数据和基于数据的操作封装在一起,使其构成一个不可分割的独立实体**
......@@ -27,9 +31,11 @@ head:
- 3、可以对成员进行更精确的控制。
- 4、隐藏信息,实现细节。
首先我们先来看两个类:Husband.java、Wife.java
首先我们先来看两个类
```
Husband.java
```java
public class Husband {
/*
......@@ -74,7 +80,9 @@ public class Husband {
}
```
```
Wife.java
```java
public class Wife {
private String name;
private int age;
......@@ -112,7 +120,9 @@ public class Wife {
}
```
可以看得出, Husband 类里面的 wife 属性是没有 getter()的,同时 Wife 类的 age 属性也是没有 getter()方法的。至于理由我想各位都懂的,男人嘛深屋藏娇妻嘛,还有就是没有哪个女人愿意别人知道她的年龄的。
可以看得出, Husband 类里面的 wife 属性是没有 getter()的,同时 Wife 类的 age 属性也是没有 getter()方法的。至于理由我想三妹你是懂的。
没有哪个女人愿意别人知道她的年龄。
所以封装把一个对象的属性私有化,同时提供一些可以被外界访问的属性的方法,如果不想被外界方法,我们大可不必提供方法给外界访问。
......@@ -126,7 +136,7 @@ public class Wife {
通过这个我们还不能真正体会封装的好处。现在我们从程序的角度来分析封装带来的好处。如果我们不使用封装,那么该对象就没有 setter()和 getter(),那么 Husband 类应该这样写:
```
```java
public class Husband {
public String name ;
public String sex ;
......@@ -137,16 +147,16 @@ public class Husband {
我们应该这样来使用它:
```
```java
Husband husband = new Husband();
husband.age = 30;
husband.name = "张三";
husband.sex = "男"; //貌似有点儿多余
```
但是哪天如果我们需要修改 Husband,例如将 age 修改为 String 类型的呢?你只有一处使用了这个类还好,如果你有几十个甚至上百个这样地方,你是不是要改到崩溃。如果使用了封装,我们完全可以不需要做任何修改,只需要稍微改变下 Husband 类的 setAge()方法即可。
但是哪天如果我们需要修改 Husband,例如将 age 修改为 String 类型的呢?你只有一处使用了这个类还好,如果你有几十个甚至上百个这样地方,你是不是要改到崩溃。如果使用了封装,我们完全可以不需要做任何修改,只需要稍微改变下 Husband 类的 setAge()方法即可。
```
```java
public class Husband {
/*
......@@ -180,7 +190,7 @@ public class Husband {
还是那个 Husband,一般来说我们在引用这个对象的时候是不容易出错的,但是有时你迷糊了,写成了这样:
```
```java
Husband husband = new Husband();
husband.age = 300;
```
......@@ -189,7 +199,7 @@ husband.age = 300;
但是使用封装我们就可以避免这个问题,我们对 age 的访问入口做一些控制(setter)如:
```
```java
public class Husband {
/*
......@@ -221,7 +231,7 @@ public class Husband {
上面都是对 setter 方法的控制,其实通过封装我们也能够对对象的出口做出很好的控制。例如性别在数据库中一般都是以 1、0 的方式来存储的,但是在前台我们又不能展示 1、0,这里我们只需要在 getter()方法里面做一些转换即可。
```
```java
public String getSexName() {
if("0".equals(sex)){
sexName = "女";
......@@ -229,16 +239,13 @@ public String getSexName() {
else if("1".equals(sex)){
sexName = "男";
}
else{
sexName = "人妖???";
}
return sexName;
}
```
在使用的时候我们只需要使用 sexName 即可实现正确的性别显示。同理也可以用于针对不同的状态做出不同的操作。
```
```java
public String getCzHTML(){
if("1".equals(zt)){
czHTML = "<a href='javascript:void(0)' onclick='qy("+id+")'>启用</a>";
......@@ -250,7 +257,9 @@ public String getCzHTML(){
}
```
好了,关于封装我们就暂时聊这么多。
“好了,关于封装我们就暂时就聊这么多吧。”我喝了一口普洱茶后,对三妹说。
“好的,哥,我懂了。”
> 参考链接:[https://www.cnblogs.com/chenssy/p/3351835.html](https://www.cnblogs.com/chenssy/p/3351835.html),整理:沉默王二
......
此差异已折叠。
---
title: 一文彻底搞懂 Java final 关键字
shortTitle: 一文彻底搞懂Java final关键字
title: 一文彻底搞懂 final 关键字
shortTitle: final关键字
description: Java程序员进阶之路,小白的零基础Java教程,一文彻底搞懂 Java final 关键字
category:
- Java 核心
......@@ -9,9 +9,10 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,final,静态变量,静态方法,静态代码块,静态内部类
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,final,静态变量,静态方法,静态代码块,静态内部类,java final
---
# 5.18 final关键字
“哥,今天学什么呢?”
......@@ -21,7 +22,7 @@ head:
“好吧。”我摊摊手,表示很无辜,真的是所有的决定都交给我这个哥哥了,如果决定错了,锅得背上。
## 01、final 变量
### 01、final 变量
“好了,我们先来看 final 修饰的变量吧!”
......@@ -104,7 +105,7 @@ public class ArgFinalTest {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/keywords/23-04.png)
## 02、final 方法
### 02、final 方法
“被 final 修饰的方法不能被重写。如果我们在设计一个类的时候,认为某些方法不应该被重写,就应该把它设计成 final 的。”
......@@ -144,7 +145,7 @@ public class Actor {
“那必须啊,谁叫我是你妹呢。”
## 03、final 类
### 03、final 类
“如果一个类使用了 final 关键字修饰,那么它就无法被继承.....”
......@@ -204,15 +205,12 @@ System.out.println(writer.getName()); // 沉默王二
“Writer 的 name 字段的默认值是 null,但可以通过 settter 方法将其更改为沉默王二。也就是说,如果一个类只是 final 的,那么它并不是不可变的全部条件。”
“关于不可变类,我之前也单独讲过一篇,你一会去看看。”
“关于不可变类,我们留到后面来细讲。”
[不可变类](https://tobebetterjavaer.com/basic-extra-meal/immutable.html)
“把一个类设计成 final 的,有其安全方面的考虑,但不应该故意为之,因为把一个类定义成 final 的,意味着它没办法继承,假如这个类的一些方法存在一些问题的话,我们就无法通过重写的方式去修复它。”
------
“三妹,final 关键字我们就学到这里吧,你一会再学习一下 Java 字符串为什么是不可变的和不可变类。”我揉一揉犯困的双眼,疲惫地给三妹说,“学完这两个知识点,你会对 final 的认知更清晰一些。”
“好的,二哥,我这就去学习去。你去休息会。”
......
---
title: Java内部类详解:成员内部类、局部内部类、匿名内部类、静态内部类
shortTitle: Java内部类详解
title: 聊聊Java内部类:成员内部类、局部内部类、匿名内部类、静态内部类
shortTitle: Java内部类
description: Java程序员进阶之路,小白的零基础Java教程,Java内部类详解:成员内部类、局部内部类、匿名内部类、静态内部类
category:
- Java 核心
......@@ -9,15 +9,12 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,内部类,成员内部类,局部内部类,匿名内部类,静态内部类
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,内部类,成员内部类,局部内部类,匿名内部类,静态内部类,java 内部类
---
# 5.13 Java内部类
## 内部类简介
在 Java 中,可以将一个类定义在另外一个类里面或者一个方法里面,这样的类叫做内部类。
一般来说,内部类分为成员内部类、局部内部类、匿名内部类和静态内部类。
“在 Java 中,可以将一个类定义在另外一个类里面或者一个方法里面,这样的类叫做内部类。”我放下手中的枸杞杯,对三妹说,“一般来说,内部类分为成员内部类、局部内部类、匿名内部类和静态内部类。”
### **1)成员内部类**
......@@ -175,10 +172,9 @@ public class Wangsi {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/inner-class-69523196-37fe-43c6-a52e-5a8c94fdd2d8.png)
“为什么要使用内部类呢?”三妹问。
## 总结
为什么要使用内部类?
三妹这个问题问的非常妙,是时候引经据典了。
在《Think in java》中有这样一句话:
......@@ -186,7 +182,7 @@ public class Wangsi {
在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。
使用内部类还能够为我们带来如下特性(摘自《Think in java》)
使用内部类还能够为我们带来如下特性:
- 1、内部类可以使用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。
- 2、在单个外部类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。
......
......@@ -9,25 +9,28 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,接口
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,接口,java 接口,java interface
---
“今天开始讲 Java 的接口。”我对三妹说,“对于面向对象编程来说,抽象是一个极具魅力的特征。如果一个程序员的抽象思维很差,那他在编程中就会遇到很多困难,无法把业务变成具体的代码。在 Java 中,可以通过两种形式来达到抽象的目的,一种上一篇的主角——[抽象类](https://tobebetterjavaer.com/oo/abstract.html),另外一种就是今天的主角——接口。”
# 5.11 Java接口
“二哥,开讲之前,先恭喜你呀。我看你朋友圈说《Java程序员进阶之路》开源知识库收到了第一笔赞赏呀,虽然只有一块钱,但我也替你感到开心。”三妹的脸上洋溢着自信的微笑,仿佛这钱是打给她的一样。
“今天开始讲 Java 的接口。”我对三妹说,“对于面向对象编程来说,抽象是一个极具魅力的特征。如果一个程序员的抽象思维很差,那他在编程中就会遇到很多困难,无法把业务变成具体的代码。在 Java 中,可以通过两种形式来达到抽象的目的,一种上一篇的主角——[抽象类](https://tobebetterjavaer.com/oo/abstract.html),另外一种就是今天的主角——[接口](https://tobebetterjavaer.com/oo/interface.html)。”
“二哥,开讲之前,先恭喜你呀。我看你朋友圈说《[Java进阶之路](https://github.com/itwanger/toBeBetterJavaer)》开源知识库在 GitHub 上收到了第一笔赞赏呀,虽然只有一块钱,但我也替你感到开心。”三妹的脸上洋溢着自信的微笑,仿佛这钱是打给她的一样。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/interface-01.png)
>PS:2021-04-29到2023-02-11期间,《二哥的 Java 进阶之路》收到了 58 笔赞赏,真的非常感谢大家的认可和支持😍,我会继续肝下去的。
“是啊,早上起来的时候看到这条信息,还真的是挺开心的,虽然只有一块钱,但是开源的第一笔,也是我人生当中的第一笔,真的非常感谢这个读者,值得纪念的一天。”我自己也掩饰不住内心的激动。
“有了这份鼓励,我相信你更新下去的动力更足了!”三妹今天说的话真的是特别令人喜欢。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/interface-02.png)
“是呀是呀,让我们开始吧!”
## 定义接口
### 01、定义接口
“接口是什么呀?”三妹顺着我的话题及时的插话到。
......@@ -79,7 +82,7 @@ public interface Electronic
接下来,我来一一解释下 Electronic 接口中的核心知识点。
1)接口中定义的变量会在编译的时候自动加上 `public static final` 修饰符(注意看一下反编译后的字节码),也就是说上例中的 LED 变量其实就是一个常量。
**1)接口中定义的变量会在编译的时候自动加上 `public static final` 修饰符**(注意看一下反编译后的字节码),也就是说上例中的 LED 变量其实就是一个常量。
Java 官方文档上有这样的声明:
......@@ -89,15 +92,15 @@ Java 官方文档上有这样的声明:
不过,这种选择并不可取。因为接口的本意是对方法进行抽象,而常量接口会对子类中的变量造成命名空间上的“污染”。
2)没有使用 `private``default` 或者 `static` 关键字修饰的方法是隐式抽象的,在编译的时候会自动加上 `public abstract` 修饰符。也就是说上例中的 `getElectricityUse()` 其实是一个抽象方法,没有方法体——这是定义接口的本意。
**2)没有使用 `private`、`default` 或者 `static` 关键字修饰的方法是隐式抽象的**,在编译的时候会自动加上 `public abstract` 修饰符。也就是说上例中的 `getElectricityUse()` 其实是一个抽象方法,没有方法体——这是定义接口的本意。
3)从 Java 8 开始,接口中允许有静态方法,比如说上例中的 `isEnergyEfficient()` 方法。
**3)从 Java 8 开始,接口中允许有静态方法**,比如说上例中的 `isEnergyEfficient()` 方法。
静态方法无法由(实现了该接口的)类的对象调用,它只能通过接口名来调用,比如说 `Electronic.isEnergyEfficient("LED")`
接口中定义静态方法的目的是为了提供一种简单的机制,使我们不必创建对象就能调用方法,从而提高接口的竞争力。
4)接口中允许定义 `default` 方法也是从 Java 8 开始的,比如说上例中的 `printDescription()` 方法,它始终由一个代码块组成,为,实现该接口而不覆盖该方法的类提供默认实现。既然要提供默认实现,就要有方法体,换句话说,默认方法后面不能直接使用“;”号来结束——编译器会报错。
**4)接口中允许定义 `default` 方法**也是从 Java 8 开始的,比如说上例中的 `printDescription()` 方法,它始终由一个代码块组成,为,实现该接口而不覆盖该方法的类提供默认实现。既然要提供默认实现,就要有方法体,换句话说,默认方法后面不能直接使用“;”号来结束——编译器会报错。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/interface-03.png)
......@@ -114,7 +117,7 @@ Java 官方文档上有这样的声明:
除此之外,我们还应该知道:
1)接口不允许直接实例化,否则编译器会报错。
**1)接口不允许直接实例化**,否则编译器会报错。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/interface-04.png)
......@@ -140,7 +143,7 @@ public class Computer implements Electronic {
Electronic e = new Computer();
```
2)接口可以是空的,既可以不定义变量,也可以不定义方法。最典型的例子就是 Serializable 接口,在 `java.io` 包下。
**2)接口可以是空的**,既可以不定义变量,也可以不定义方法。最典型的例子就是 Serializable 接口,在 `java.io` 包下。
```java
public interface Serializable {
......@@ -149,19 +152,21 @@ public interface Serializable {
Serializable 接口用来为序列化的具体实现提供一个标记,也就是说,只要某个类实现了 Serializable 接口,那么它就可以用来序列化了。
3)不要在定义接口的时候使用 final 关键字,否则会报编译错误,因为接口就是为了让子类实现的,而 final 阻止了这种行为。
**3)不要在定义接口的时候使用 final 关键字**,否则会报编译错误,因为接口就是为了让子类实现的,而 final 阻止了这种行为。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/interface-05.png)
4)接口的抽象方法不能是 private、protected 或者 final,否则编译器都会报错。
**4)接口的抽象方法不能是 private、protected 或者 final**,否则编译器都会报错。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/object-class/interface-06.png)
5)接口的变量是隐式 `public static final`(常量),所以其值无法改变。
**5)接口的变量是隐式 `public static final`(常量)**,所以其值无法改变。
### 02、接口的作用
“接口可以做什么呢?”三妹见缝插针,问的很及时。
第一,使某些实现类具有我们想要的功能,比如说,实现了 Cloneable 接口的类具有拷贝的功能,实现了 Comparable 或者 Comparator 的类具有比较功能。
**第一,使某些实现类具有我们想要的功能**,比如说,实现了 Cloneable 接口的类具有拷贝的功能,实现了 Comparable 或者 Comparator 的类具有比较功能。
Cloneable 和 Serializable 一样,都属于标记型接口,它们内部都是空的。实现了 Cloneable 接口的类可以使用 `Object.clone()` 方法,否则会抛出 CloneNotSupportedException。
......@@ -206,7 +211,7 @@ Exception in thread "main" java.lang.CloneNotSupportedException: com.cmower.bael
```
第二,Java 原则上只支持单一继承,但通过接口可以实现多重继承的目的
**第二,Java 原则上只支持单一继承,但通过接口可以实现多重继承的目的**
如果有两个类共同继承(extends)一个父类,那么父类的方法就会被两个子类重写。然后,如果有一个新类同时继承了这两个子类,那么在调用重写方法的时候,编译器就不能识别要调用哪个类的方法了。这也正是著名的菱形问题,见下图。
......@@ -244,7 +249,7 @@ public class Pig implements Fly,Run{
在某种形式上,接口实现了多重继承的目的:现实世界里,猪的确只会跑,但在雷军的眼里,站在风口的猪就会飞,这就需要赋予这只猪更多的能力,通过抽象类是无法实现的,只能通过接口。
第三,实现多态
**第三,实现多态**
什么是多态呢?通俗的理解,就是同一个事件发生在不同的对象上会产生不同的结果,鼠标左键点击窗口上的 X 号可以关闭窗口,点击超链接却可以打开新的网页。
......@@ -312,11 +317,11 @@ for (Shape shape : shapes) {
也就意味着,尽管在 for 循环中,shape 的类型都为 Shape,但在调用 `name()` 方法的时候,它知道 Circle 对象应该调用 Circle 类的 `name()` 方法,Square 对象应该调用 Square 类的 `name()` 方法。
### 04、 接口在应用中常见的三种模式
### 03、接口的三种模式
**在编程领域,好的设计模式能够让我们的代码事半功倍**。在使用接口的时候,经常会用到三种模式,分别是策略模式、适配器模式和工厂模式。
1)策略模式
#### 1)策略模式
策略模式的思想是,针对一组算法,将每一种算法封装到具有共同接口的实现类中,接口的设计者可以在不影响调用者的情况下对算法做出改变。示例如下:
......@@ -361,7 +366,7 @@ public class Demo {
`Demo.defend()` 方法可以接受不同风格的 Coach,并根据所传递的参数对象的不同而产生不同的行为,这被称为“策略模式”。
2)适配器模式
#### 2)适配器模式
适配器模式的思想是,针对调用者的需求对原有的接口进行转接。生活当中最常见的适配器就是HDMI(英语:`High Definition Multimedia Interface`,中文:高清多媒体接口)线,可以同时发送音频和视频信号。适配器模式的示例如下:
......@@ -395,7 +400,7 @@ Coach 接口中定义了两个方法(`defend()` 和 `attack()`),如果类
如果我们只需要对其中一个方法进行实现的话,就可以使用一个抽象类作为中间件,即适配器(AdapterCoach),用这个抽象类实现接口,并对抽象类中的方法置空(方法体只有一对花括号),这时候,新类就可以绕过接口,继承抽象类,我们就可以只对需要的方法进行覆盖,而不是接口中的所有方法。
3)工厂模式
#### 3)工厂模式
所谓的工厂模式理解起来也不难,就是什么工厂生产什么,比如说宝马工厂生产宝马,奔驰工厂生产奔驰,A 级学院毕业 A 级教练,C 级学院毕业 C 级教练。示例如下:
......@@ -468,6 +473,12 @@ public class Demo {
依次类推,我们还可以用 BCoach 类实现 Coach 接口,BCoachFactory 类实现 CoachFactory 接口,从而不断地丰富教练的梯队。
“怎么样三妹,一下子接收这么多知识点不容易吧?”
“其实还好啊,二哥你讲的这么细致,我都做好笔记📒了,学习嘛,认真一点,效果就会好很多了。”
三妹这种积极乐观的态度真的让我感觉到“付出就会有收获”,💪🏻。
----
......
---
title: Java中的方法:实例方法、静态方法、抽象方法
shortTitle: Java 中的方法
shortTitle: Java中的方法
description: Java程序员进阶之路,小白的零基础Java教程,Java中的方法:实例方法、静态方法、抽象方法
category:
- Java 核心
......@@ -12,17 +12,19 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,方法,实例方法,静态方法,抽象方法,java方法
---
# 5.4 Java中的方法
“二哥,这一节我们学什么呢?”三妹满是期待的问我。
“这一节我们来了解一下 Java 中的方法——什么是方法?如何声明方法?方法有哪几种?什么是实例方法?什么是静态方法?什么是抽象方法?”我笑着对三妹说,“我开始了啊,你要注意力集中啊。”
“这一节我们来了解一下 Java 中的方法——什么是方法?如何声明方法?方法有哪几种?什么是实例方法?什么是静态方法?什么是抽象方法?什么是本地方法?”我笑着对三妹说,“我开始了啊,你要注意力集中啊。”
## 01、Java 中的方法是什么?
### 01、Java中的方法是什么?
方法用来实现代码的可重用性,我们编写一次方法,并多次使用它。通过增加或者删除方法中的一部分代码,就可以提高整体代码的可读性。
只有方法被调用时,它才会执行。Java 中最有名的方法当属 `main()` 方法,这是程序的入口。
## 02、如何声明方法?
### 02、如何声明方法?
方法的声明反映了方法的一些信息,比如说可见性、返回类型、方法名和参数。如下图所示。
......@@ -52,11 +54,11 @@ head:
**方法体**:方法体放在一对花括号内,把一些代码放在一起,用来执行特定的任务。
## 03、方法有哪几种?
### 03、方法有哪几种?
方法可以分为两种,一种叫预先定义方法,一种叫用户自定义方法。
方法可以分为两种,一种叫标准类库方法,一种叫用户自定义方法。
### **1)预先定义方法**
#### **1)预先定义方法**
Java 提供了大量预先定义好的方法供我们调用,也称为标准类库方法,或者内置方法。比如说 String 类的 `length()``equals()``compare()` 方法,以及我们在初学 Java 阶段最常用的 `println()` 方法,用来在控制台打印信息。
......@@ -81,7 +83,11 @@ public class PredefinedMethodDemo {
预先定义方法让编程变得简单了起来,我们只需要在实现某些功能的时候直接调用这些方法即可,不需要重新编写。
### **2)用户自定义方法**
Java 的一个非常大的优势,就是,JDK 的设计者(开发者)为我们提供了大量的标准类库方法,这对于初学编程的新手来说极其友好;不仅如此,GitHub/码云上也有大量可以直接拿到生产环境下使用的第三方类库,比如说 hutool 啊、Apache 包啊、一线大厂或者顶级开发大佬贡献的类库,比如说 Druid、Gson 等等。
但如果你想从一个初级开发者(俗称调包侠)晋升为一名优秀的 Java 工程师,那就需要深入研究这些源码,并掌握,最好是能自己写出来这些源码,最起码能自定义一些源码,以便为我们所用。
#### **2)用户自定义方法**
当预先定义方法无法满足我们的要求时,就需要自定义一些方法,比如说,我们来定义这样一个方法,用来检查数字是偶数还是奇数。
......@@ -123,7 +129,7 @@ public class EvenOddDemo {
当一个方法被 static 关键字修饰时,它就是一个静态方法。换句话说,静态方法是属于类的,不属于类实例的(不需要通过 new 关键字创建对象来调用,直接通过类名就可以调用)。
## 04、什么是实例方法?
### 04、什么是实例方法?
没有使用 [static 关键字](https://tobebetterjavaer.com/oo/static.html)修饰,但在类中声明的方法被称为实例方法,在调用实例方法之前,必须创建类的对象。
......@@ -189,7 +195,7 @@ public class Person {
getter 方法以 get 开头,setter 方法以 set 开头。
## 05、什么是静态方法?
### 05、什么是静态方法?
相应的,有 [static 关键字](https://tobebetterjavaer.com/oo/static.html)修饰的方法就叫做静态方法。
......@@ -222,7 +228,7 @@ StaticMethodExample 类中,mian 和 add 方法都是静态方法,不同的
Hutool 的存在就是为了减少代码搜索成本,避免网络上参差不齐的代码出现导致的 bug。
## 06、什么是抽象方法?
### 06、什么是抽象方法?
没有方法体的方法被称为抽象方法,它总是在抽象类中声明。这意味着如果类有抽象方法的话,这个类就必须是抽象的。可以使用 atstract 关键字创建抽象方法和抽象类。
......@@ -260,170 +266,9 @@ public class MyAbstractDemo extends AbstractDemo {
重写了抽象方法
```
## 07、什么是本地 native 方法?
类似 Thread 类中的 `private native start0()` 方法;
又或者 Object.class 类中的 getClass() 方法、hashCode()方法、clone() 方法,其中方法签名如下:
```java
public final native Class<?> getClass();
public native int hashCode();
protected native Object clone() throws CloneNotSupportedException;
```
也就是用【native】关键词修饰的方法,多数情况下不需要用 Java 语言实现。
“二哥,为什么要用 native 来修饰方法呢,这样做有什么用?”三妹很乖,但这个问题也问的很掷地有声。
“好的,三妹,我们一步步来扒拉”。
### **1、JNI:Java Native Interface**
在介绍 native 之前,我们先了解什么是 JNI。
一般情况下,我们完全可以使用 Java 语言编写程序,但某些情况下,Java 可能满足不了需求,或者不能更好的满足需求,比如:
- ①、标准的 Java 类库不支持。
- ②、我们已经用另一种语言,比如说 C/C++ 编写了一个类库,如何用 Java 代码调用呢?
- ③、某些运行次数特别多的方法,为了加快性能,需要用更接近硬件的语言(比如汇编)编写。
上面这三种需求,说到底就是如何用 Java 代码调用不同语言编写的代码。那么 JNI 应运而生了。
从 Java 1.1 开始,Java Native Interface (JNI)标准就成为 Java 平台的一部分,它允许 Java 代码和其他语言编写的代码进行交互。
JNI 一开始是为了本地已编译语言,尤其是 C 和 C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用 Java 与本地已编译的代码交互,通常会丧失平台可移植性,但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI 标准至少保证本地代码能工作能在任何 Java 虚拟机实现下。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-67e26e52-bf45-4126-a516-1e768632aaa8.jpg)
通过 JNI,我们就可以通过 Java 程序(代码)调用到操作系统相关的技术实现的库函数,从而与其他技术和系统交互;同时其他技术和系统也可以通过 JNI 提供的相应原生接口调用 Java 应用系统内部实现的功能。
在 Windows 上,一般可执行的应用程序都是基于 native 的 PE 结构,Windows 上的 JVM 也是基于 native 结构实现的。Java 应用体系都是构建于 JVM 之上。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-61f0597a-b164-4128-a55d-1ee65189eae1.jpg)
“二哥,等一下,Java 不是跨平台的吗?如果用 JNI,那么程序不就失去了跨平台的优点?”不得不说,三妹这个问题起到好处。
“确实是这样的。”我掐灭了中指和无名指之间的烟头,继续娓娓道来。
JNI 的缺点:
- ①、程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
- ②、程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了 Java 和 C/C++ 之间的耦合性。
目前来讲使用 JNI 的缺点相对于优点还是可以接受的,可能后面随着 Java 的技术发展,我们不在需要 JNI,但是目前 JDK 还是一直提供了对 JNI 标准的支持。
### **3、用 C 语言编写程序本地方法**
“上面讲解了什么是 JNI,接下来我们来写个例子:如何用 Java 代码调用本地的 C 程序。”我扭头对三妹说,“你注意📢看。”
>官方文档如下:[https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html](https://link.zhihu.com/?target=https%3A//docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html)
步骤如下:   
①、编写带有 native 方法的 Java 类,生成.java 文件;
②、使用 javac 命令编译所编写的 Java 类,生成.class 文件;
③、使用 javah -jni java 类名 生成扩展名为 h 的头文件,也即生成 .h 文件;
④、使用 C/C++(或者其他编程想语言)实现本地方法,创建 .h 文件的实现,也就是创建 .cpp 文件实现.h 文件中的方法;
⑤、将 C/C++ 编写的文件生成动态连接库,生成 dll 文件;
下面我们通过一个 HelloWorld 程序的调用来完成这几个步骤。
>注意:下面所有操作都是在所有操作都是在目录:D:\\JNI 下进行的。
#### 一、编写带有 native 声明的方法的 java 类
```text
public class HelloJNI {
//native 关键字告诉 JVM 调用的是该方法在外部定义
private native void helloJNI();
static{
System.loadLibrary("helloJNI");//载入本地库
}
public static void main(String[] args) {
HelloJNI jni = new HelloJNI();
jni.helloJNI();
}
}
```
用 native 声明的方法告知 JVM 调用该方法在外部定义,也就是我们会用 C 语言去实现。
`System.loadLibrary("helloJNI");`加载动态库,参数 helloJNI 是动态库的名字。我们可以这样理解:程序中的方法 helloJNI() 在程序中没有实现,但是我们下面要调用这个方法,怎么办呢?我们就需要对这个方法进行初始化,所以用了 [static 代码块进行初始化](https://tobebetterjavaer.com/oo/static.html)
这时候如果我们直接运行该程序,会报“A Java Exception has occurred”错误:
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-b5a7e2d8-5bae-45ae-8225-6c21090b506a.jpg)
#### 二、使用 javac 命令编译 java 类,生成.class 文件
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-1131ccf8-e4d0-4e4c-b7f6-659f0906c5d4.jpg)
执行上述命令后,生成 HelloJNI.class 文件:
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-b015e4ae-d636-42ef-93e7-381e33587ea9.jpg)
#### 三、使用 javah -jni java 类名 生成扩展名为 h 的头文件
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-0f2755b6-45ad-44d6-88ff-2eb3fa5cba3b.jpg)
执行上述命令后,在 D:/JNI 目录下会多出一个 HelloJNI.h 文件:
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-7798a73c-1fdf-4f08-9d29-9ee5dfaa8a1b.jpg)
#### 四、使用 C 语言实现本地方法   如果不想安装 Visual Studio,需要在 Windows 平台安装 gcc。
安装教程如下:[http://blog.csdn.net/altland/article/details/63252757](https://blog.csdn.net/altland/article/details/63252757)
注意安装版本的选择,根据系统是 32 位还是 64 位来选择。
安装完成之后注意配置环境变量,在 cmd 中输入 `g++ -v`,如果出现如下信息,则安装配置完成:
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-43b26326-e461-4b55-b029-d8b8e745ecbe.jpg)
接着输入如下命令:
```
gcc -m64 -Wl,--add-stdcall-alias -I"C:\Program Files\Java\jdk1.8.0_152\include" -I"C:\Program Files\Java\jdk1.8.0_152\include\include\win32" -shared -o helloJNI.dll helloJNI.c
```
\-m64 表示生成 dll 库是 64 位的。后面的路径表示本机安装的 JDK 路径。生成之后多了一个 helloJNI.dll 文件
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-07eabf6b-166a-4537-9521-8781887e4ad7.jpg)
最后运行 HelloJNI:输出 Hello JNI! 大功告成。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-541e9154-1643-42f7-9baf-357405466711.jpg)
### **4、JNI 调用 C 的流程图**
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/method-a2103240-def4-460f-a12c-8f74e08e2b1b.jpg)
### **5、native 关键字**
“三妹,现在应该知道什么是 native 了吧?”我问三妹。
“嗯嗯,我来简述一下,二哥你看看我说的是否正确。”
native 用来修饰方法,用 native 声明的方法表示该方法的实现在外部定义,可以用任何语言去实现它,比如说 C/C++。 简单地讲,一个 native Method 就是一个 Java 调用非 Java 代码的接口。
native 语法:
- ①、修饰方法的位置必须在返回类型之前,和其余的方法控制符前后关系不受限制。
- ②、不能用 abstract 修饰,也没有方法体,也没有左右大括号。
- ③、返回值可以是任意类型
“三妹,你学的不错嘛。”我对三妹的学习能力感到非常的欣慰,“**我们在日常编程中看到 native 修饰的方法,只需要知道这个方法的作用是什么,至于别的就不用管了,操作系统会给我们实现**。”
“关于方法,我们就讲到这里吧,学会了类/变量/方法,基本上就可以做一个入门级的 Java 程序员了。”我面露微笑,继续对三妹说,“继续加油吧!”
>参考链接:[https://www.zhihu.com/question/28001771/answer/2049534464](https://www.zhihu.com/question/28001771/answer/2049534464)
“好的,谢谢二哥你的细心帮助。”
---
......
---
title: 手把手教你用 C语言实现 Java native 方法
shortTitle: 用C语言实现本地方法
description: Java程序员进阶之路,小白的零基础Java教程,手把手教你用 C语言实现 Java native 方法
category:
- Java 核心
tag:
- 面向对象编程
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java native,java本地方法,java native method
---
# 5.6 Java中的本地方法
“三妹,之前我们学习了 Java 中的[基本方法](https://tobebetterjavaer.com/oo/method.html),其实 Java 还有一种方法,本地方法,或者叫 native 方法,它与之前的方法有很大的不同。”我放下手中的手机,扭过脸来对三妹说。
“听起来挺有意思的。”三妹很期待。
“我会教你用 C语言实现一个 native 方法。”我继续说到,“C语言是另外一种编程语言,你可以点这个[链接](https://tobebetterjavaer.com/xuexiluxian/c.html)去了解和学习。让我们开始吧”
类似 Thread 类中的 `private native start0()` 方法;
又或者 Object.class 类中的 getClass() 方法、hashCode()方法、clone() 方法,其中方法签名如下:
```java
public final native Class<?> getClass();
public native int hashCode();
protected native Object clone() throws CloneNotSupportedException;
```
也就是用【native】关键词修饰的方法,多数情况下不需要用 Java 语言实现。
“二哥,为什么要用 native 来修饰方法呢,这样做有什么用?”三妹很乖,但这个问题也问的很掷地有声。
“好的,三妹,我们一步步来扒拉”。
### **1、JNI:Java Native Interface**
在介绍 native 之前,我们先了解什么是 JNI。
一般情况下,我们完全可以使用 Java 语言编写程序,但某些情况下,Java 可能满足不了需求,或者不能更好的满足需求,比如:
- ①、标准的 Java 类库不支持。
- ②、我们已经用另一种语言,比如说 C/C++ 编写了一个类库,如何用 Java 代码调用呢?
- ③、某些运行次数特别多的方法,为了加快性能,需要用更接近硬件的语言(比如汇编)编写。
上面这三种需求,说到底就是如何用 Java 代码调用不同语言编写的代码。那么 JNI 应运而生了。
从 Java 1.1 开始,Java Native Interface (JNI)标准就成为 Java 平台的一部分,它允许 Java 代码和其他语言编写的代码进行交互。
JNI 一开始是为了本地已编译语言,尤其是 C 和 C++而设计的,但是它并不妨碍你使用其他语言,只要调用约定受支持就可以了。使用 Java 与本地已编译的代码交互,通常会丧失平台可移植性,但是,有些情况下这样做是可以接受的,甚至是必须的,比如,使用一些旧的库,与硬件、操作系统进行交互,或者为了提高程序的性能。JNI 标准至少保证本地代码能工作能在任何 Java 虚拟机实现下。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/native-method-2a6fd1da-8b64-4fe1-bf3b-fbb117774549.png)
通过 JNI,我们就可以通过 Java 程序(代码)调用到操作系统相关的技术实现的库函数,从而与其他技术和系统交互;同时其他技术和系统也可以通过 JNI 提供的相应原生接口调用 Java 应用系统内部实现的功能。
“二哥,等一下,Java 不是跨平台的吗?如果用 JNI,那么程序不就失去了跨平台的优点?”不得不说,三妹这个问题起到好处。
“确实是这样的。”我掐灭了中指和无名指之间的烟头,继续娓娓道来。
JNI 的缺点:
- ①、程序不再跨平台。要想跨平台,必须在不同的系统环境下重新编译本地语言部分。
- ②、程序不再是绝对安全的,本地代码的不当使用可能导致整个程序崩溃。一个通用规则是,你应该让本地方法集中在少数几个类当中。这样就降低了 Java 和 C/C++ 之间的耦合性。
目前来讲使用 JNI 的缺点相对于优点还是可以接受的,可能后面随着 Java 的技术发展,我们不在需要 JNI,但是目前 JDK 还是一直提供了对 JNI 标准的支持。
### **2、用 C 语言编写程序本地方法**
“上面讲解了什么是 JNI,接下来我们来写个例子:如何用 Java 代码调用本地的 C 程序。”我扭头对三妹说,“你注意📢看。”
>官方文档如下:[https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html](https://docs.oracle.com/javase/8/docs/technotes/guides/jni/spec/jniTOC.html)
步骤如下:   
①、编写带有 native 方法的 Java 类,生成.java 文件;
②、使用 javac 命令编译所编写的 Java 类,生成.class 文件;
③、使用 javah -jni java 类名 生成扩展名为 h 的头文件,也即生成 .h 文件;
④、使用 C/C++(或者其他编程想语言)实现本地方法,创建 .h 文件的实现,也就是创建 .cpp 文件实现.h 文件中的方法;
⑤、将 C/C++ 编写的文件生成动态连接库,生成 dll 文件;
下面我们通过一个 HelloWorld 程序的调用来完成这几个步骤。
#### 01)编写带有 native 方法的 Java 类 HelloJNI.java
`/Users/itwanger/Documents/Github/javabetter/testjni` 目录下创建 HelloJNI.java 文件,内容如下所示。
```java
public class HelloJNI {
static {
System.loadLibrary("hello"); // 加载名为 libhello.dylib 的动态链接库
}
// 定义本地方法
private native void helloJNI();
public static void main(String[] args) {
new HelloJNI().helloJNI(); // 调用本地方法
}
}
```
**PS:后面执行的命令都将在 testjni 的目录下**
解释一下这段代码:
`private native void helloJNI()`:用 native 声明的方法告知 JVM 调用该方法在外部定义,也就是我们会用 C 语言去实现。
`System.loadLibrary("hello")`:加载动态库,参数 hello 是动态库的名字。我们可以这样理解:程序中的方法 helloJNI() 在程序中没有实现,但是我们下面要调用这个方法,怎么办呢?
我们就需要对这个方法进行初始化,所以用了 [static 代码块进行初始化](https://tobebetterjavaer.com/oo/static.html),后面会讲到。
#### 02)编译 HelloJNI.java
在命令行通过 `javac HelloJNI.java` 来编译源代码。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/native-method-41e11e7f-31c1-4611-9b85-63ec211ff31b.png)
#### 03)使用 `javah -jni HelloJNI` 生成扩展名为 h 的头文件
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/native-method-0b08bf51-7bd9-4d06-a0dc-4262c1a71fd5.png)
>PS:Java 9 以后,javah 被弃用,取而代之的是使用 -h 选项来生成头文件,例如 `javac -h . ClassName.java`。
执行完毕后,会在 HelloJNI.java 所在目录下生成一个名为 HelloJNI.h 的头文件。打开 HelloJNI.h 文件,可以看到如下代码。  
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/native-method-e5c34f63-84df-4a99-96e1-b45ea04929df.png)
看不懂没关系,无所谓,直到它是自动生成的就好。
#### 04)使用 C 语言实现本地方法
创建一个 C 文件 HelloJNI.c,实现本地方法 sayHello。
```c
#include <stdio.h>
#include <jni.h>
#include "HelloJNI.h"
JNIEXPORT void JNICALL Java_HelloJNI_helloJNI(JNIEnv *env, jobject obj) {
printf("Hello, JNI!\n");
return;
}
```
注意,这里需要引入 JNI 头文件,并且实现的方法名称需要与在 Java 中声明的名称一致(`HelloJNI_helloJNI` HelloJNI 类的 helloJNI 方法)。
#### 05)编写编译脚本 compile.sh
```sh
#!/bin/bash
# 编译 HelloJNI.c 文件
gcc -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" -shared -o libhello.dylib HelloJNI.c
# 把生成的 libhello.dylib 文件拷贝到当前目录
cp libhello.dylib .
```
注意事项:
- `$JAVA_HOME` 是 JDK 的安装路径,需要根据实际情况修改。
- 在 macOS 上,动态链接库(hello)的后缀是 .dylib,而不是 Linux 上的 .so。
这里的 -I 选项是为了告诉编译器头文件的位置,`$JAVA_HOME` 是 Java 安装目录的路径。
#### 06)执行编译脚本
```
sh compile.sh
```
执行完毕后,会在当前目录下生成一个名为 libhello.dylib 的动态链接库。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/native-method-e93c8fa8-6e33-4374-81da-8bd9360d1bb4.png)
#### 07)运行 HelloJNI
执行`java HelloJNI`命令运行 HelloJNI,如果一切正常,就会在终端上输出 Hello, JNI!。
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/native-method-34beba0f-8fe8-48d0-aa48-b25c1b504b59.png)
### **3、JNI 调用 C 的流程图**
![](http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/oo/native-method-6673cf73-c4dd-4434-b821-0d705f756a73.png)
### **4、native 关键字**
“三妹,现在应该知道什么是 native 了吧?”我问三妹。
“嗯嗯,我来简述一下,二哥你看看我说的是否正确。”
native 用来修饰方法,用 native 声明的方法表示该方法的实现在外部定义,可以用任何语言去实现它,比如说 C/C++。 简单地讲,一个 native Method 就是一个 Java 调用非 Java 代码的接口。
native 语法:
- ①、修饰方法的位置必须在返回类型之前,和其余的方法控制符前后关系不受限制。
- ②、不能用 abstract 修饰,也没有方法体,也没有左右大括号。
- ③、返回值可以是任意类型
“三妹,你学的不错嘛。”我对三妹的学习能力感到非常的欣慰,“**我们在日常编程中看到 native 修饰的方法,只需要知道这个方法的作用是什么,至于别的就不用管了,操作系统会给我们实现,初学的时候也不需要太过深入**。”
>- Windows 下安装 gcc 教程:[http://blog.csdn.net/altland/article/details/63252757](https://blog.csdn.net/altland/article/details/63252757)
>- native 参考链接:[https://www.zhihu.com/question/28001771/answer/2049534464](https://www.zhihu.com/question/28001771/answer/2049534464)
---
最近整理了一份牛逼的学习资料,包括但不限于 Java 基础部分(JVM、Java 集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类 Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是 2022 年全网最全的学习和找工作的 PDF 资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
微信搜 **沉默王二** 或扫描下方二维码关注二哥的原创公众号沉默王二,回复 **111** 即可免费领取。
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/gongzhonghao.png)
---
title: 怎么理解Java中的类和对象?
shortTitle: 怎么理解Java中的类和对象?
title: 一文彻底讲清楚Java中的类和对象
shortTitle: Java中的类和对象
category:
- Java核心
tag:
......@@ -9,14 +9,16 @@ description: Java程序员进阶之路,小白的零基础Java教程,从入
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,类和对象,class,object
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java类和对象,class,object,java class,java object,java class object,类和对象,object class
---
“二哥,我那天在图书馆复习《Java程序员进阶之路》的时候,刚好碰见一个学长,他问我有没有‘对象’,我说还没有啊。结果你猜他说什么,‘要不要我给你 new 一个啊?’我当时就懵了,new 是啥意思啊,二哥?”三妹满是疑惑的问我。
# 5.1 Java中的类和对象
“二哥,那天我在图书馆复习《Java进阶之路》的时候,刚好碰见一个学长,他问我有没有‘对象’,我说还没有啊。结果你猜他说什么,‘要不要我给你 new 一个啊?’我当时就懵了,new 是啥意思啊,二哥?”三妹满是疑惑的问我。
“哈哈,三妹,你学长还挺幽默啊。new 是 Java 中的一个关键字,用来把类变成对象。”我笑着对三妹说,“对象和类是 Java 中最基本的两个概念,可以说撑起了面向对象编程(OOP)的一片天。”
## 01、面向过程和面向对象
### 01、面向过程和面向对象
三妹是不是要问,什么是 OOP?
......@@ -42,7 +44,7 @@ OOP 的英文全称是 Object Oriented Programming,要理解它的话,就要
不过,如果追到底的话,面向对象的底层其实还是面向过程,只不过把面向过程进行了抽象化,封装成了类,方便我们的调用。
## 02、类
### 02、类
对象可以是现实中看得见的任何物体,比如说,一只特立独行的猪;也可以是想象中的任何虚拟物体,比如说能七十二变的孙悟空。
......@@ -83,7 +85,7 @@ public class Person {
成员变量有时候也叫做实例变量,在编译时不占用内存空间,在运行时获取内存,也就是说,只有在对象实例化(`new Person()`)后,字段才会获取到内存,这也正是它被称作“实例”变量的原因。
方法 3 个,分别是 `eat()``sleep()``dadoudou()`,表示 Person 这个对象可以做什么,也就是吃饭睡觉打豆豆。
方法 3 个,分别是 `eat()``sleep()``dadoudou()`,表示 Person 这个对象可以做什么,也就是吃饭睡觉打豆豆。
那三妹是不是要问,“怎么没有构造方法呢?”
......@@ -118,7 +120,7 @@ public class Person {
`public Person(){}` 就是默认的构造方法,因为是空的构造方法(方法体中没有内容),所以可以缺省。Java 聪明就聪明在这,有些很死板的代码不需要开发人员添加,它会偷偷地做了。
## 03、new 一个对象
### 03、new 一个对象
创建 Java 对象时,需要用到 `new` 关键字。
......@@ -188,7 +190,7 @@ class Person {
}
```
## 04、初始化对象
### 04、初始化对象
在之前的例子中,程序输出结果为:
......@@ -202,7 +204,7 @@ null
那怎么初始化 Person 对象(对字段赋值)呢?
第一种:通过对象的引用变量。
#### 第一种:通过对象的引用变量。
```java
public class Person {
......@@ -235,7 +237,7 @@ person 被称为对象 Person 的引用变量,见下图:
1
```
第二种:通过方法初始化。
#### 第二种:通过方法初始化。
```java
/**
......@@ -265,7 +267,7 @@ public class Person {
在 Person 类中新增方法 `initialize()`,然后在新建对象后传参进行初始化(`person.initialize("沉默王二", 18, 1)`)。
第三种:通过构造方法初始化。
#### 第三种:通过构造方法初始化。
```java
/**
......@@ -306,9 +308,9 @@ new Person();
new Person().initialize("沉默王二", 18, 1);
```
## 05、关于对象
### 05、关于对象
**1)抽象的历程**
#### **1)抽象的历程**
所有编程语言都是一种抽象,甚至可以说,我们能够解决的问题的复杂程度取决于抽象的类型和质量。
......@@ -324,7 +326,7 @@ Smalltalk 是历史上第一门获得成功的面向对象语言,也为 Java
>状态+行为+标识=对象,每个对象在内存中都会有一个唯一的地址。
**2)对象具有接口**
#### **2)对象具有接口**
所有的对象,都可以被归为一类,并且同一类对象拥有一些共同的行为和特征。在 Java 中,class 关键字用来定义一个类型。
......@@ -336,7 +338,7 @@ Smalltalk 是历史上第一门获得成功的面向对象语言,也为 Java
对象能够接收什么样的请求是由它的接口定义的。具体是怎么做到的,就由它的实现方法来实现。
**3)访问权限修饰符**
#### **3)访问权限修饰符**
类的创建者有时候也被称为 API 提供者,对应的,类的使用者就被称为 API 调用者。
......@@ -356,11 +358,11 @@ API 创建者在创建新的类的时候,只暴露必要的接口,而隐藏
还有一种“默认”的权限修饰符,是缺省的,它修饰的类可以访问同一个包下面的其他类。
**4)组合**
#### **4)组合**
我们可以把一个创建好的类作为另外一个类的成员变量来使用,利用已有的类组成成一个新的类,被称为“复用”,组合代表的关系是 has-a 的关系。
**5)继承**
#### **5)继承**
继承是 Java 中非常重要的一个概念,子类继承父类,也就拥有了父类中 protected 和 public 修饰的方法和字段,同时,子类还可以扩展一些自己的方法和字段,也可以重写继承过来方法。
......@@ -368,7 +370,7 @@ API 创建者在创建新的类的时候,只暴露必要的接口,而隐藏
如果子类只是重写了父类的方法,那么它们之间的关系就是 is-a 的关系,但如果子类增加了新的方法,那么它们之间的关系就变成了 is-like-a 的关系。
**6)多态**
#### **6)多态**
比如说有一个父类Shape
......@@ -426,6 +428,14 @@ public class Test {
其实就是 Java 中的多态。
### 06、小结
“怎么样,三妹,是不是对 Java 有了更深入更清晰的理解?”终于讲完了,我深呼了一口气,好舒畅啊!
“是的,哥,感觉 Java 也就那么回事嘛。”哎呀,三妹有点狂了起来,“万物皆对象,除了基本数据类型。”
“哇,三妹,你可以啊,都会自己梳理总结了。”我倍感欣慰,觉得果然是劳有所获,你讲的认真,听众就能理解和 get,满足了。
----
......
---
title: Java 包,优雅地解决类名冲突
shortTitle: Java包可以优雅地解决类名冲突
title: 简单过了一下 Java 中的包
shortTitle: Java中的包
description: Java程序员进阶之路,小白的零基础Java教程,Java包可以优雅地解决类名冲突
category:
- Java 核心
......@@ -12,9 +12,15 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,包,import,package
---
## package
# 5.2 Java中的包
在前面的代码中,我们把类和接口命名为`Person``Student``Hello`等简单名字。
“三妹,这一节,我们简单过一下 Java 中的包,也就是 package,这个一点就透,很好掌握。”我放下手中的雪碧,翻开笔记本,登上 GitHub,点开《二哥的 Java 进阶之路》,找到这篇「Java 中的包」,开始滔滔不绝起来。
“二哥,你等一下。”让我打开思维导图做一下笔记📒。
### 关于包
在前面的代码中,我们把类和接口命名为`Person``Student``Hello`等简单的名字。
在团队开发中,如果小明写了一个`Person`类,小红也写了一个`Person`类,现在,小白既想用小明的`Person`,也想用小红的`Person`,怎么办?
......@@ -38,7 +44,7 @@ JDK 的`Arrays`类存放在包`java.util`下面,因此,完整类名是`java.
小明的`Person.java`文件:
```
```java
package ming; // 申明包名ming
public class Person {
......@@ -47,7 +53,7 @@ public class Person {
小军的`Arrays.java`文件:
```
```java
package mr.jun; // 申明包名mr.jun
public class Arrays {
......@@ -102,13 +108,13 @@ javac -d ../bin ming/Person.java hong/Person.java mr/jun/Arrays.java
在 IDE 中,会自动根据包结构编译所有 Java 源码,所以不必担心使用命令行编译的复杂命令。
##作用域
### 包的作用域
位于同一个包的类,可以访问包作用域的字段和方法。
不用`public``protected``private`修饰的字段和方法就是包作用域。例如,`Person`类定义在`hello`包下面:
```
```java
package hello;
public class Person {
......@@ -121,7 +127,7 @@ public class Person {
`Main`类也定义在`hello`包下面,就可以直接访问 Person 类:
```
```java
package hello;
public class Main {
......@@ -132,13 +138,13 @@ public class Main {
}
```
## import
### 导入包
在一个`class`中,我们总会引用其他的`class`。例如,小明的`ming.Person`类,如果要引用小军的`mr.jun.Arrays`类,他有三种写法:
第一种,直接写出完整类名,例如:
```
```java
// Person.java
package ming;
......@@ -149,11 +155,11 @@ public class Person {
}
```
很显然,每次写完整类名比较痛苦。
很显然,每次都要写完整的类名比较痛苦。
因此,第二种写法是用`import`语句,导入小军的`Arrays`,然后写简单类名:
```
```java
// Person.java
package ming;
......@@ -169,7 +175,7 @@ public class Person {
在写`import`的时候,可以使用`*`,表示把这个包下面的所有`class`都导入进来(但不包括子包的`class`):
```
```java
// Person.java
package ming;
......@@ -187,7 +193,7 @@ public class Person {
还有一种`import static`的语法,它可以导入一个类的静态字段和静态方法:
```
```java
package main;
// 导入System类的所有静态字段和静态方法:
......@@ -215,7 +221,7 @@ Java 编译器最终编译出的`.class`文件只使用 *完整类名*,因此
我们来看一个例子:
```
```java
// Main.java
package test;
......@@ -243,7 +249,7 @@ public class Main {
如果有两个`class`名称相同,例如,`mr.jun.Arrays``java.util.Arrays`,那么只能`import`其中一个,另一个必须写完整类名。
## 最佳实践
### 包的最佳实践
为了避免名字冲突,我们需要确定唯一的包名。推荐的做法是使用倒置的域名来确保唯一性。例如:
......@@ -268,7 +274,7 @@ public class Main {
- ...
## 小结
### 小结
Java 内建的`package`机制是为了避免`class`命名冲突;
......
---
title: 几句话,直观解释清楚 Java 多态(三大特征之一)
shortTitle: 几句话直观解释Java多态
title: 聊聊 Java 多态
shortTitle: Java多态
description: Java程序员进阶之路,小白的零基础Java教程,认真聊聊 Java的三大特征:多态
category:
- Java 核心
......@@ -12,15 +12,21 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java多态,多态
---
**多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编译时并不确定,而是在程序运行期间才确定。**
# 5.16 Java多态
**即一个引用变量倒底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在由程序运行期间才能决定。**
“三妹啊,前面聊完了 Java 的[封装](https://tobebetterjavaer.com/oo/encapsulation.html)[继承](https://tobebetterjavaer.com/oo/extends-bigsai.html),今天我们来继续聊多态,也是 Java 三大特性的最后一个特性,搞懂它,Java 面向对象编程基本上就能轻松拿捏了。”我对三妹说。
**因为在程序运行时才确定具体的类,这样,不用修改源程序代码,就可以让引用变量绑定到各种不同的类实现上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。**
“哥,你继续。”
再具体的分析一下
Java 多态是指在面向对象编程中,同一个类的对象在不同情况下表现出不同的行为和状态
## 01、多态是什么
- 子类可以继承父类的属性和方法,子类对象可以直接使用父类中的方法和变量。
- 子类可以对从父类继承的方法进行重新实现,使得子类对象调用这个方法时表现出不同的行为。
- 可以将子类对象赋给父类类型的变量,这样就可以通过父类类型的变量调用子类中重写的方法,实现多态。
“很枯燥,有没有?再具体的分析一下。”
### 01、多态是什么
在我刻板的印象里,西游记里的那段孙悟空和二郎神的精彩对战就能很好的解释“多态”这个词:一个孙悟空,能七十二变;一个二郎神,也能七十二变;他们都可以变成不同的形态,但只需要悄悄地喊一声“变”。
......@@ -60,7 +66,7 @@ class Wanger {
}
```
## 02、多态与后期绑定
### 02、多态与后期绑定
现在,我们来思考一个问题:程序清单1-1在执行 `wanger.write()` 时,由于编译器只有一个 Wanger 引用,它怎么知道究竟该调用父类 Wanger 的 `write()` 方法,还是子类 Wangxiaoer 的 `write()` 方法呢?
......@@ -106,9 +112,9 @@ class Wanger {
多态的这个优秀的特性,让我们在修改代码的时候不必过于紧张,因为多态是一项让程序员“将改变的与未改变的分离开来”的重要特性。
## 03、多态与构造器
### 03、多态与构造方法
在构造中调用多态方法,会产生一个奇妙的结果,我们来看程序清单3-1:
在构造方法中调用多态方法,会产生一个奇妙的结果,我们来看程序清单3-1:
```java
public class Wangxiaosan extends Wangsan {
......@@ -147,15 +153,15 @@ class Wangsan {
为什么?
因为在创建子类对象时,会先去调用父类的构造器,而父类构造器中又调用了被子类覆盖的多态方法,由于父类并不清楚子类对象中的属性值是什么,于是把int类型的属性暂时初始化为 0,然后再调用子类的构造器(子类构造器知道王小二的年龄是 4)。
因为在创建子类对象时,会先去调用父类的构造方法,而父类构造方法中又调用了被子类覆盖的多态方法,由于父类并不清楚子类对象中的属性值是什么,于是把int类型的属性暂时初始化为 0,然后再调用子类的构造方法(子类构造方法知道王小二的年龄是 4)。
## 04、多态与向下转型
### 04、多态与向下转型
向下转型是指将父类引用强转为子类类型;这是不安全的,因为有的时候,父类引用指向的是父类对象,向下转型就会抛出 ClassCastException,表示类型转换失败;但如果父类引用指向的是子类对象,那么向下转型就是成功的。
来看程序清单4-1:
```text
```java
public class Wangxiaosi extends Wangsi {
public void write() {
System.out.println("记住仇恨,表明我们要奋发图强的心智");
......@@ -186,6 +192,10 @@ class Wangsi {
}
```
“好了,三妹,到此为止,我们就将 Java 的三大特性,封装继承多态全部讲完了,希望你能重新把他们梳理一下。”
“好的,二哥,遵命。”三妹顽皮地笑了。
----
最近整理了一份牛逼的学习资料,包括但不限于Java基础部分(JVM、Java集合框架、多线程),还囊括了 **数据库、计算机网络、算法与数据结构、设计模式、框架类Spring、Netty、微服务(Dubbo,消息队列) 网关** 等等等等……详情戳:[可以说是2022年全网最全的学习和找工作的PDF资源了](https://tobebetterjavaer.com/pdf/programmer-111.html)
......
---
title: 一文彻底搞懂 Java static 关键字:静态变量、静态方法、静态代码块、静态内部类
shortTitle: 一文彻底搞懂Java static关键字
title: 详解 static 关键字的作用:静态变量、静态方法、静态代码块、静态内部类
shortTitle: static关键字
description: Java程序员进阶之路,小白的零基础Java教程,一文彻底搞懂 Java static 关键字:静态变量、静态方法、静态代码块、静态内部类
category:
- Java 核心
......@@ -9,10 +9,12 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,static,java静态变量,java静态方法,java静态代码块,java静态内部类
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,static,java静态变量,java静态方法,java静态代码块,java静态内部类,java static
---
“哥,你牙龈肿痛轻点没?周一的《教妹学 Java》(Java程序员进阶之路的前身)你都没有更新,偷懒了呀!”三妹关心地问我。
# 5.17 static关键字
“哥,你牙龈肿痛轻点没?周一的《教妹学 Java》(二哥的Java进阶之路前身)你都没有更新,偷懒了呀!”三妹关心地问我。
“今天周四了,吃了三天的药,疼痛已经减轻不少,咱妈还给我打了电话,让我买点牛黄解毒片下下火。”我面带着微笑对三妹说,“学习可不能落下,今天我们来学 Java 中 `static` 关键字吧。”
......@@ -22,7 +24,7 @@ head:
“static 关键字的作用可以用一句话来描述:‘**方便在没有创建对象的情况下进行调用**,包括变量和方法’。也就是说,只要类被加载了,就可以通过类名进行访问。”我扶了扶沉重眼镜,继续说到,“static 可以用来修饰类的成员变量,以及成员方法。我们一个个来看。”
## 01、静态变量
### 01、静态变量
“如果在声明变量的时候使用了 static 关键字,那么这个变量就被称为静态变量。静态变量只在类加载的时候获取一次内存空间,这使得静态变量很节省内存空间。”家里的暖气有点足,我跑去开了一点窗户后继续说道。
......@@ -150,7 +152,7 @@ public class StaticCounter {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/keywords/19-03.png)
## 02、静态方法
### 02、静态方法
“说完静态变量,我们来说静态方法。”说完,我准备点一支华子来抽,三妹阻止了我,她指一指烟盒上的「吸烟有害身体健康」,我笑了。
......@@ -226,7 +228,7 @@ public class StaticMethodStudent {
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/keywords/19-06.png)
## 03、静态代码块
### 03、静态代码块
“三妹,站起来活动一下,我的脖子都有点僵硬了。”
......@@ -307,7 +309,7 @@ public class StaticBlockDemo {
“静态代码块在初始集合的时候,真的非常有用。在实际的项目开发中,通常使用静态代码块来加载配置文件到内存当中。”
## 04、静态内部类
### 04、静态内部类
“三妹啊,除了以上只写,static 还有一个不太常用的功能——静态内部类。”
......
---
title: Java中this和super的用法总结
shortTitle: Java中this和super的用法总结
title: Java中this和super关键字的用法总结
shortTitle: this和super
description: Java程序员进阶之路,小白的零基础Java教程,Java中this和super的用法总结
category:
- Java 核心
......@@ -9,9 +9,10 @@ tag:
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,this,super
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,this,super,java this super,java this,java super,this super
---
# 5.17 this和super
“哥,被喊大舅子的感觉怎么样啊?”三妹不怀好意地对我说,她眼睛里充满着不屑。
......@@ -29,7 +30,7 @@ head:
- this 可以作为参数在构造方法中传递;
- this 可以作为方法的返回值,返回当前类的对象。
## 01、 指向当前对象
### 01、 指向当前对象
“三妹,来看下面这段代码。”话音刚落,我就在键盘上噼里啪啦一阵敲。
......@@ -113,9 +114,7 @@ public class WithThisStudent {
“这次,实例变量有值了,在构造方法中,`this.xxx` 指向的就是实例变量,而不再是参数本身了。”我慢吞吞地说着,“当然了,如果参数名和实例变量名不同的话,就不必使用 this 关键字,但我建议使用 this 关键字,这样的代码更有意义。”
## 02、调用当前类的方法
### 02、调用当前类的方法
“仔细听,三妹,看我敲键盘的速度是不是够快。”
......@@ -164,7 +163,7 @@ public class InvokeCurrentClassMethod {
“我们可以在一个类中使用 this 关键字来调用另外一个方法,如果没有使用的话,编译器会自动帮我们加上。”我对自己深厚的编程功底充满自信,“在源代码中,`method2()` 在调用 `method1()` 的时候并没有使用 this 关键字,但通过反编译后的字节码可以看得到。”
## 03、调用当前类的构造方法
### 03、调用当前类的构造方法
“再来看下面这段代码。”
......@@ -226,7 +225,7 @@ hello
![](https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/keywords/20-01.png)
## 04、作为参数在方法中传递
### 04、作为参数在方法中传递
“来看下面这段代码。”
......@@ -259,7 +258,7 @@ com.itwanger.twentyseven.ThisAsParam@77459877
`method2()` 调用了 `method1()`,并传递了参数 this,`method1()` 中打印了当前对象的字符串。 `main()` 方法中打印了 thisAsParam 对象的字符串。从输出结果中可以看得出来,两者是同一个对象。”
## 05、作为参数在构造方法中传递
### 05、作为参数在构造方法中传递
“继续来看代码。”
......@@ -299,7 +298,7 @@ class Data {
10
```
## 06、作为方法的返回值
### 06、作为方法的返回值
“需要休息会吗?三妹”
......@@ -345,7 +344,7 @@ hello
“噢噢噢噢。”三妹意味深长地笑了。
## 07、super 关键字
### 07、super 关键字
“super 关键字的用法主要有三种。”
......
---
title: Java变量:局部变量、成员变量、静态变量、常量
shortTitle: Java 中的变量
shortTitle: Java中的变量
description: Java程序员进阶之路,小白的零基础Java教程,Java变量:局部变量、成员变量、静态变量、常量
category:
- Java 核心
......@@ -12,18 +12,18 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,Java变量,局部变量,成员变量,静态变量,常量,变量
---
# 5.3 Java中的变量
“二哥,听说 Java 变量在以后的日子里经常用,能不能提前给我透露透露?”三妹咪了一口麦香可可奶茶后对我说。
“三妹啊,搬个凳子坐我旁边,听二哥来给你慢慢说啊。”
Java 变量就好像一个容器,可以保存程序在运行过程中的值,它在声明的时候会定义对应的数据类型(Java 分为两种数据类型:基本数据类型和引用数据类型)。变量按照作用域的范围又可分为三种类型:局部变量,成员变量和静态变量。
Java 变量就好像一个容器,可以保存程序在运行过程中的值,它在声明的时候会定义对应的[数据类型](https://tobebetterjavaer.com/basic-grammar/basic-data-type.html)(Java 分为两种数据类型:基本数据类型和引用数据类型)。变量按照作用域的范围又可分为三种类型:局部变量,成员变量和静态变量。
比如说,`int data = 88;`,其中 data 就是一个变量,它的值为 88,类型为整型(int)。
## 01、局部变量
### 01、局部变量
在方法体内声明的变量被称为局部变量,该变量只能在该方法内使用,类中的其他方法并不知道该变量。来看下面这个示例:
......@@ -52,7 +52,7 @@ public class LocalVariable {
- 局部变量是在栈上分配的。
- 局部变量没有默认值,所以局部变量被声明后,必须经过初始化,才可以使用。
## 02、成员变量
### 02、成员变量
在类内部但在方法体外声明的变量称为成员变量,或者实例变量。之所以称为实例变量,是因为该变量只能通过类的实例(对象)来访问。来看下面这个示例:
......@@ -81,7 +81,7 @@ public class InstanceVariable {
- 访问修饰符可以修饰成员变量。
- 成员变量对于类中的方法、构造方法或者语句块是可见的。一般情况下应该把成员变量设为私有。通过使用访问修饰符可以使成员变量对子类可见;成员变量具有默认值。数值型变量的默认值是 0,布尔型变量的默认值是 false,引用类型变量的默认值是 null。变量的值可以在声明时指定,也可以在构造方法中指定。
## 03、静态变量
### 03、静态变量
通过 static 关键字声明的变量被称为静态变量(类变量),它可以直接被类访问,来看下面这个示例:
......@@ -110,7 +110,7 @@ public class StaticVariable {
- 静态变量的默认值和实例变量相似。
- 静态变量还可以在静态语句块中初始化。
## 04、常量
### 04、常量
在 Java 中,有些数据的值是不会发生改变的,这些数据被叫做常量——使用 final 关键字修饰的成员变量。常量的值一旦给定就无法改变!
......@@ -132,7 +132,6 @@ public class FinalVariable {
FinalVariable fv = new FinalVariable();
System.out.println(fv.CHEN);
System.out.println(MO);
}
}
```
......
# 第一章:小册简介
![](https://cdn.tobebetterjavaer.com/paicoding/adbd4b9992d0656dfe743da0b4adc63e.png)
![](https://files.mdnice.com/user/3903/ac95f39b-aeff-4fd0-be95-0f0020c36b4a.jpg)
> PS:为了增加这份小册的趣味性,我特意为此追加了两个虚拟角色,一个二哥,一个三妹,二哥负责教,三妹负责学。这样大家在学习 Java 的时候代入感会更强烈一些,希望这样的设定能博得大家的欢心。
......
......@@ -12,7 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,Java简介
---
# 2.1 Java简介,什么是 Java?
# 2.1 Java简介
“二哥,到底什么是 Java?给我说说呗。”
......
......@@ -12,7 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,StringBuilder,StringBuffer,string stringbuilder,string stringbuffer,string stringbuilder stringbuffer
---
# 4.7 聊聊String、StringBuilder、StringBuffer 三兄弟
# 4.7 String、StringBuilder、StringBuffer
“哥,[上一篇深入理解 String.intern()](https://tobebetterjavaer.com/string/intern.html) 讲到了 StringBuilder,这一节我们就来聊聊吧!”三妹很期待。
......
......@@ -12,7 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,equals,java equals,java string 比较,java字符串比较
---
# 4.8 Java如何判断两个字符串是否相等?
# 4.8 如何判断两个字符串是否相等?
“二哥,如何比较两个字符串相等啊?”三妹问。
......
......@@ -12,7 +12,7 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,不可变
---
# 4.4 聊聊Java字符串,以及为什么String是不可变的?
# 4.4 Java字符串及不可变性
我正坐在沙发上津津有味地读刘欣大佬的《码农翻身》——Java 帝国这一章,门铃响了。起身打开门一看,是三妹,她从学校回来了。
......
......@@ -9,15 +9,18 @@ description: Java程序员进阶之路,小白的零基础Java教程,从入
head:
- - meta
- name: keywords
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,字符串拼接
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,字符串拼接,java字符串拼接,java string拼接
---
# 4.9 字符串拼接
“哥,你让我看的《[Java 开发手册](https://tobebetterjavaer.com/nice-article/weixin/sulwgalcpdssbjavakfsc.html)》上有这么一段内容:循环体内,拼接字符串最好使用 StringBuilder 的 `append()` 方法,而不是 + 号操作符。这是为什么呀?”三妹疑惑地问。
“哥,你让我看的《[Java 开发手册](https://tobebetterjavaer.com/pdf/ali-java-shouce.html)》上有这么一段内容:循环体内,拼接字符串最好使用 StringBuilder 的 `append()` 方法,而不是 + 号操作符。这是为什么呀?”三妹疑惑地问。
好的,三妹,哥来慢慢给你讲。”我回答。
其实这个问题,我们之前已经[聊过](https://tobebetterjavaer.com/string/builder-buffer.html)。”我慢吞吞地回答道,“不过,三妹,哥今天来给你深入地讲讲。”
三妹能在学习的过程中不断地发现问题,让我感到非常的开心。其实很多时候,我们不应该只是把知识点记在心里,还应该问一问自己,到底是为什么,只有迈出去这一步,才能真正的成长起来。
PS:三妹能在学习的过程中不断地发现问题,让我感到非常的开心。其实很多时候,我们不应该只是把知识点记在心里,还应该问一问自己,到底是为什么,只有迈出去这一步,才能真正的成长起来。
### javap 探究+号操作符拼接字符串的本质
“+ 号操作符其实被 Java 在编译的时候重新解释了,换一种说法就是,+ 号操作符是一种语法糖,让字符串的拼接变得更简便了。”一边给三妹解释,我一边在 Intellij IDEA 中敲出了下面这段代码。
......@@ -66,9 +69,9 @@ class Demo {
“然后看标号为 17 的这行,是一个 invokevirtual 指令,用于调用对象的方法,也就是 StringBuilder 对象的 `append()` 方法。”
“也就意味着把 chenmo 这个字符串添加到 StringBuilder 对象中了。”
“也就意味着把 chenmo("沉默")这个字符串添加到 StringBuilder 对象中了。”
“再往下看,标号为 21 的这行,又调用了一次 `append()` 方法,意味着把 wanger 这个字符串添加到 StringBuilder 对象中了。”
“再往下看,标号为 21 的这行,又调用了一次 `append()` 方法,意味着把 wanger("王二")这个字符串添加到 StringBuilder 对象中了。”
换成 Java 代码来表示的话,大概是这个样子:
......@@ -77,14 +80,14 @@ class Demo {
public static void main(String[] args) {
String chenmo = "沉默";
String wanger = "王二";
System.out.println((new StringBuilder(String.valueOf(chenmo))).append(wanger).toString());
System.out.println((new StringBuilder(chenmo)).append(wanger).toString());
}
}
```
“哦,原来编译的时候把“+”号操作符替换成了 StringBuilder 的 `append()` 方法啊。”三妹恍然大悟。
“是的,不过到了 Java 9,情况发生了一些改变,同样的代码,字节码指令完全不同了。”我说。
“是的,不过到了 Java 9(不是长期支持版本,所以我会拿 Java 11 来演示),情况发生了一些改变,同样的代码,字节码指令完全不同了。”我说。
同样的代码,在 Java 11 的环境下,字节码指令是这样的:
......@@ -130,6 +133,8 @@ public class com.itwanger.thirtyseven.Demo {
“好吧,总之就是 Java 9 以后,JDK 用了另外一种方法来动态解释 + 号操作符,具体的实现方式在字节码指令层面已经看不到了,所以我就以 Java 8 来继续讲解吧。”
### 为什么要编译为 StringBuilder.append
“再回到《Java 开发手册》上的那段内容:循环体内,拼接字符串最好使用 StringBuilder 的 `append()` 方法,而不是 + 号操作符。原因就在于循环体内如果用 + 号操作符的话,就会产生大量的 StringBuilder 对象,不仅占用了更多的内存空间,还会让 Java 虚拟机不停的进行垃圾回收,从而降低了程序的性能。”
更好的写法就是在循环的外部新建一个 StringBuilder 对象,然后使用 `append()` 方法将循环体内的字符串添加进来:
......@@ -177,6 +182,8 @@ for (int i = 0; i < 100000; i++) {
“是的,哥,原来如此。”
### append方法源码解析
“好了,三妹,来看一下 StringBuilder 类的 `append()` 方法的源码吧!”
```java
......@@ -240,17 +247,9 @@ str.getChars(0, len, value, count)
5)更新数组的长度 count。
“说到 StringBuilder 就必须得提一嘴 StringBuffer,两者就像是孪生双胞胎,该有的都有,只不过大哥 StringBuffer 因为多呼吸两口新鲜空气,所以是线程安全的。”我说,“它里面的方法基本上都加了 synchronized 关键字来做同步。”
### String.concat 拼接字符串
```java
public synchronized StringBuffer append(String str) {
toStringCache = null;
super.append(str);
return this;
}
```
“除了可以使用 + 号操作符,StringBuilder 和 StringBuilder 的 `append()` 方法,还有其他的字符串拼接方法吗?”三妹问。
“除了可以使用 + 号操作符,StringBuilder 的 `append()` 方法,还有其他的字符串拼接方法吗?”三妹问。
“有啊,比如说 String 类的 `concat()` 方法,有点像 StringBuilder 类的 `append()` 方法。”
......@@ -285,7 +284,7 @@ public String concat(String str) {
“和 `+` 号操作符相比,`concat()` 方法在遇到字符串为 null 的时候,会抛出 NullPointerException,而“+”号操作符会把 null 当做是“null”字符串来处理。”
如果拼接的字符串是一个空字符串(""),那么 concat 的效率要更高一点,毕竟不需要 `new StringBuilder` 对象。
如果拼接的字符串是一个空字符串(""),那么 concat 的效率要更高一点,毕竟不需要 `new StringBuilder` 对象。
如果拼接的字符串非常多,`concat()` 的效率就会下降,因为创建的字符串对象越来越多。
......@@ -293,6 +292,8 @@ public String concat(String str) {
“有,当然有。”
### String.join 拼接字符串
String 类有一个静态方法 `join()`,可以这样来使用。
```java
......@@ -327,6 +328,8 @@ public static String join(CharSequence delimiter, CharSequence... elements) {
里面新建了一个叫 StringJoiner 的对象,然后通过 for-each 循环把可变参数添加了进来,最后调用 `toString()` 方法返回 String。
### StringUtils.join 拼接字符串
“实际的工作中,`org.apache.commons.lang3.StringUtils``join()` 方法也经常用来进行字符串拼接。”
```java
......@@ -372,7 +375,7 @@ public static String join(final Object[] array, String separator, final int star
内部使用的仍然是 StringBuilder。
“好了,三妹,关于字符串拼接的知识点我们就讲到这吧。注意 Java 9 以后,对 + 号操作符的解释和之前发生了变化,字节码指令已经不同了,等后面你学了字节码指令后我们再详细地讲一次。”我说。
“好了,三妹,关于字符串拼接的知识点我们就讲到这吧。注意 Java 9 以后,对 + 号操作符的解释和之前发生了变化,字节码指令已经不同了,等后面你学了[字节码指令](https://tobebetterjavaer.com/jvm/zijiema-zhiling.html)后我们再详细地讲一次。”我说。
“嗯,哥,你休息吧,我把这些例子再重新跑一遍。”三妹说。
......
......@@ -12,6 +12,8 @@ head:
content: Java,Java SE,Java基础,Java教程,Java程序员进阶之路,Java入门,教程,java字符串,String,拆分字符串
---
# 4.10 字符串分割
“哥,我感觉字符串拆分没什么可讲的呀,直接上 String 类的 `split()` 方法不就可以了!”三妹毫不客气地说。
“假如你真的这么觉得,那可要注意了,事情远没这么简单。”我微笑着说。
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册