写了一段时间的 Java 程序,SpringBoot 项目也做了好几个,但感觉自己对 Java 的了解还是特别少,所以决定从零开始重新学习,下面是学习的笔记。【学习素材:韩顺平老师】
我会把我的学习过程分为六个阶段:
① Java 和基于 Java 的编程基础(包括 Java 的基本介绍、变量和运算符、程序控制结构、数组、排序、查找)
② Java 的面向对象编程详解
③ 枚举注解、异常、常用类
④ 集合、泛型、多线程
⑤ IO 流和网络编程
⑥ 反射和正则表达式
⛄️ 在【官方教程解释类和对象】这篇文章中说到:就像现实世界的对象中有状态和行为一样,Java 编程中的对象也有【行为】,在 Java 编程中对象的行为被叫做【成员方法(简称方法)】。
需求:创建 Person 类,提供【做自我介绍】的方法
public class Person {
private String name;
/**
* 做自我介绍(成员方法)
*/
public void selfIntroduce() {
System.out.println("你好, 我叫杨嘉立。杨树的杨, 嘉奖的嘉, 立正的立。");
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
// 你好, 我叫杨嘉立。杨树的杨, 嘉奖的嘉, 立正的立
person.selfIntroduce();
}
}
创建 Calculator 类, 提供以下3个方法:
(1) 计算 [1, 100] 的累加和
(2) 计算 [start, end] 的累加和
(3) 计算任意个整数的累加和
/**
* 计算类(用于做各种计算)
*/
public class Calculator {
/**
* 计算 [1, 100] 的累加和
*/
public int sumOne2Hundred() {
int start = 1;
int end = 100;
int sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
}
return sum;
}
/**
* 计算 [start, end] 的累加和
*/
public int sumStart2End(int start, int end) {
int sum = 0;
for (int i = start; i <= end; i++) {
sum += i;
}
return sum;
}
/**
* 计算提供的多个整数的累加和
*
* @param ints 提供的多个整数
* @return 累加和
*/
public int sumGivenInt(int... ints) {
int sum = 0;
for (int i = 0; i < ints.length; i++) {
sum += ints[i];
}
return sum;
}
}
public class Main {
public static void main(String[] args) {
Calculator calculator = new Calculator();
// [1, 100] 累加和: 5050
System.out.println("[1, 100] 累加和: " + calculator.sumOne2Hundred());
// [1, 1000] 累加和: 500500
System.out.println("[1, 1000] 累加和: " + calculator.sumStart2End(1, 1000));
// 任意多个整数累加: 979
System.out.println("任意多个整数累加: " + calculator.sumGivenInt(66, 888, 25));
}
}
Person 和 Calculator 两个类中一共定义了 4 个方法:
❄️public void selfIntroduce()
❄️public int sumOne2Hundred()
❄️public int sumStart2End(int start, int end)
❄️public int sumGivenInt(int... ints)
四个方法定义的最前面都有 public,它是访问修饰符(限制方法可以被访问的范围)。public 表示公共的,可访问范围最广。访问修饰符共有四个:① public、② protected、③ default、④ private
第一个方法(selfIntroduce)的 void 表示该方法没有返回值,而其他方法都有返回值(返回值类型是 int)
第一和第二个方法(selfIntroduce 和 sumOne2Hundred)都没有方法参数;sumStart2End 方法有2个方法参数,sumGivenInt 方法的方法参数是未知的(可能没有、可能1个、可能两个 …)
在前面的文章中博主分享过对象的内存布局和栈帧等概念,不知道的童鞋去看看吧,顺便支持一下博主:http://t.csdn.cn/moZa3
通过下面的代码分析方法的调用机制:
public class Person {
/**
* 计算两个整数的和
*/
public int sumOfTwo(int n1, int n2) {
return n1 + n2;
}
}
public class Main {
public static void main(String[] args) {
Person person = new Person();
// 520
System.out.println(person.sumOfTwo(500, 20));
}
}
提高代码的复用性(不用重复编写相同的代码)
将实现的细节封装起来,其他工程师调用方法即可,无需知道底层实现细节
成员方法提高代码复用性的代码体现:
打印下面的二维数组:
int[][] twoArray = {{5, 2, 0}, {6, 7, 8}, {1, 3, 9}};
public class MemberMethodAdvantage {
public static void main(String[] args) {
int[][] twoArray = {{5, 2, 0}, {6, 7, 8}, {1, 3, 9}};
// 1. 打印 twoArray 数组
System.out.print("\n");
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(" " + twoArray[i][j]);
}
System.out.println();
}
System.out.println();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(" " + twoArray[i][j]);
}
System.out.println();
}
System.out.println();
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
System.out.print(" " + twoArray[i][j]);
}
System.out.println();
}
}
}
上面的代码,把打印二维数组的代码复制了三份,从而实现【打印二维数组】功能重复使用。但若是需要修改代码实现逻辑的话,则需要修改三处,这很不高效。
类的成员方法的实现逻辑被存放在 jvm 的方法区(且每个类的成员方法只在方法区保存一份),每个该类的对象都可调用方法区的成员方法,即使有一千个对象,成员方法也只有一个,真正是实现了代码的复用。
看下面的代码,思考打印的值是什么?
public class ArgumentsPassingTest {
public static void main(String[] args) {
ArgumentsPassingTest passing = new ArgumentsPassingTest();
int a = 66;
int b = 88;
passing.swap(a, b);
// main の a = 66
System.out.println("main の a = " + a);
// main の b = 88
System.out.println("main の b = " + b);
}
public void swap(int a, int b) {
int temp = a; // temp = 66
a = b; // a = 88
b = temp; // b = 66
// a = 88
System.out.println("a = " + a);
// b = 66
System.out.println("b = " + b);
}
}
基本数据类型传参是【值】传递
形参的任何改变不会影响实参
看下面的代码,思考打印的值是什么?
public class ArgumentsPassingTest {
public static void main(String[] args) {
int[] nums = new int[]{1, 2, 3};
ArgumentsPassingTest test = new ArgumentsPassingTest();
// call test 之前: nums = [1, 2, 3]
System.out.println("call test 之前: nums = " + Arrays.toString(nums));
test.arrTest(nums);
// call test 之后: nums = [1, 5, 3]
System.out.println("call test 之后: nums = " + Arrays.toString(nums));
}
private void arrTest(int[] nums) {
nums[1] = nums[1] * 2 + 1;
}
}
引用类型传参是引用(地址值)传递(通过地址值可以修改引用类型的值)
public class ArgumentsPassingTest {
public static void main(String[] args) {
ArgumentsPassingTest test = new ArgumentsPassingTest();
Handsome handsome = new Handsome();
// 1: 鹿晗
System.out.println("1: " + handsome.name);
test.handsomeTest2(handsome);
// 2: 周杰伦
System.out.println("2: " + handsome.name);
test.handsomeTest1(handsome);
// 3: 王俊凯
System.out.println("3: " + handsome.name);
test.handsomeTest3(handsome);
// 4: 壹诺
System.out.println("4: " + handsome.name);
test.handsomeTest4(handsome);
// 5: 潘忠举
System.out.println("5: " + handsome.name);
// Handsome.name = 潘忠举
handsome.printName();
}
private void handsomeTest1(Handsome handsome1) {
handsome1.name = "王俊凯";
}
private void handsomeTest2(Handsome handsome2) {
handsome2.name = "周杰伦";
}
private void handsomeTest3(Handsome handsome3) {
handsome3.name = "壹诺";
}
private void handsomeTest4(Handsome handsome3) {
handsome3.name = "潘忠举";
}
}
class Handsome {
String name = "鹿晗";
void printName() {
System.out.println("Handsome.name = " + name);
}
}
❄️ 引用类型传参的时候,形参的改变会影响实参
❄️ 方法返回值是引用类型,实际返回的是对象的地址值
public class ArgumentsPassingTest {
public static void main(String[] args) {
Flower flower = new Flower();
flower.name = "兰花";
flower.price = 61;
// flower.name = 兰花
System.out.println("flower.name = " + flower.name);
// flower.price = 61
System.out.println("flower.price = " + flower.price);
Flower copyFlower = copyFlower(flower);
// copyFlower.name = 兰花
System.out.println("copyFlower.name = " + copyFlower.name);
// copyFlower.price = 61
System.out.println("copyFlower.price = " + copyFlower.price);
// false【false 表示 flower 和 copyFlower 不是同一个对象】
System.out.println(flower == copyFlower);
}
private static Flower copyFlower(Flower flower) {
Flower flowerCopy = new Flower();
flowerCopy.name = flower.name;
flowerCopy.price = flower.price;
return flowerCopy;
}
}
class Flower {
String name;
int price;
}
好困啊,今天就写到这儿吧!