Java的基础语法

news2024/10/6 12:25:06

叠甲:以下文章主要是依靠我的实际编码学习中总结出来的经验之谈,求逻辑自洽,不能百分百保证正确,有错误、未定义、不合适的内容请尽情指出!

文章目录

  • 1.第一份程序
    • 1.1.代码编写
    • 1.2.代码运行
      • 1.2.1.命令行编译
      • 1.2.2.IEDA 编译
    • 1.3.代码文档
  • 2.运行过程
  • 3.关键字
  • 4.标识符
  • 5.常量与变量
    • 5.1.数据类型
      • 5.1.1.基本类型
      • 5.1.2.引用类型
    • 5.2.数据的量
      • 5.2.1.字面常量
      • 5.2.2.数据变量
  • 6.类型转化
    • 6.1.隐式类型转换
    • 6.2.显式类型转换
    • 6.3.数据类型提升
  • 7.运算符
  • 8.控制语句
    • 8.1.分支语句
      • 8.1.1.if 语句
      • 8.1.2.switch 语句
    • 8.2.循环语句
      • 8.2.1.for 语句
      • 8.2.2.while 语句
      • 8.2.3.do-while 语句
  • 9.输入输出
    • 9.1.输出数据
    • 9.2.输入数据
  • 10.随机数
  • 11.方法
    • 11.1.方法的定义
    • 11.2.方法的参数
    • 11.3.方法的递归
    • 11.4.方法的重载
  • 12.数组
    • 12.1.数组的使用
    • 12.2.数组的引用
    • 12.3.数组的传递
    • 12.4.数组的拷贝
  • 13.字符串
  • 14.IDEA 快捷键

概要:…

资料:…


1.第一份程序

1.1.代码编写

/* (块注释)
HelloWord.java 内部
*/

/** (文档注释)
* 作者:limou3434
*/

public class HelloWord {
    public static void main(String[] args){
        System.out.println("Hello Word!"); // (普通注释)打印“Hello Word!”
    }
}

直接上代码,上面就是一段 Java 代码,我们先来观察一下这段代码的细节:

  1. 首先看到的是一个 main() 函数(每一个类只能有一个 main()),主函数没有所谓的返回值,因此返回类型是 void,在 main() 的内部有一个字符数组类型的 args 变量,用来接收命令行参数

  2. 在一个 Java 文件中只能有一个 public 类,并且 pubilc 类的名字必须和 .java 文件名字相同。而 main() 函数被包含在这个类中,不允许被写在类外

  3. main() 内部,有一个调用,调用了打印函数 println(),这个函数后面的 ln 指的是换行,打印函数内部包含了需要被打印的内容

  4. Java0 中有三种注释:行注释、段注释、文档注释,这里故意都使用了一遍

1.2.代码运行

那么如何编译这一份代码呢?我将带您用两种方式进行运行,一种是脱离 IDE 环境的命令行运行,另一种就是在 IDEA 中运行。这两种方法您都需要掌握…

1.2.1.命令行编译

  1. 在最原始的情况下只需要将上述代码写入 HelloWord.java 文件中(注意文件名一定要使用大驼峰,实际上在 Java 中一个文件就对应一个类,一般直接使用类名来命名文件)

  2. 然后通过使用 Java 的编译器 javac.exe 这个可执行程序,使用命令 javac ./HelloWord.java(注意需要正确写好 Hellow.java 的相对路径或者绝对路劲)

  3. 此时在 HelloWord.java 的同级目录中就存在一个经过编译的字节码文件 HelloWord.class

  4. 运行 Java 代码代码直接使用 Java HelloWord 即可

  5. 需要注意的是,Java 不是单个文件就生成单个字节码的文件,而是有多少个类就有多少个字节码文件,并且字节码文件名和类相同,这点和很多编程语言有很大的不同。

注意:这里如果因为添加了中文注释导致无法通过编译,则可以尝试在编译的时候设置某个编码运行,例如 javac -encoding utf-8 HellowWord.java 就可以使用 utf-8 来进行编码。而关于命令行中的其他操作,可以查阅其他资料…

1.2.2.IEDA 编译

在这里插入图片描述

1.3.代码文档

Java 有一个非常独特的功能,给代码生成文档,使用 javadoc -d [存放文档的目录路径] -sourcepath [存放源代码的目录路径] [-docencoding UTF-8 -charset UTF-8] [指定需要生成文档的 .java 文件]> 即可生成一个 html 帮助文档。

不过这种注释需要搭配一些特殊的注释,这些注释的使用和意义有点类似 C/CppDoxygen 注释,主要有以下特殊注释(这里只举例常用的)。

  1. 类和接口文档:使用 /** ... */ 放在类或接口声明之前,描述类或接口的用途和功能
  2. 成员变量文档:使用 /** ... */ 放在成员变量声明之前,描述变量的用途
  3. 成员方法文档:使用 /** ... */ 放在方法声明之前,描述方法的功能、参数、返回值和可能抛出的异常
  4. 参数文档:使用 @param 标记在方法文档中,为每个参数提供描述
  5. 返回值文档:使用 @return 标记在方法文档中,描述方法的返回值
  6. 异常文档:使用 @throws 标记在方法文档中,描述方法可能抛出的异常及其条件
  7. 版本和作者文档:使用 @version 标记来记录类或接口的版本信息,使用 @author 标记来记录代码的作者
  8. 自描述:使用 @see 标记来引用其他主题或 URL,在最后文档生成中会达到跳转的目的
  9. 弃用文档:使用 @deprecated 标记来标明某个 API 成员(类、方法、字段等)已过时,一般添加到整个注释文档的最后即可
  10. 序列化文档:使用 @serial 标记来描述序列化字段

以下是一些示例 javadoc 的注释,以后遇到我也会使用上其他的注释。

// 使用 javadoc 注释
/**
 * 表示一个简单的计算器类。
 */
public class Calculator {

    /**
     * 计算两个整数的和。
     *
     * @param a 第一个加数。
     * @param b 第二个加数。
     * @return 两个数的和。
     */
    public int add(int a, int b) {
        return a + b;
    }

    /**
     * 这个字段表示计算器的版本。
     * 
     * @version 1.0
     * @author John Doe
     */
    private String version;
}

这也可以根据需要使用不同的注释标记组合来生成详细的 API 文档。

2.运行过程

在我们安装 JDKJava 开发开发工具包)的时候

  • JDK 里包含 JREJava 运行时环境)
  • JRE 里包含 JVMJava 所需虚拟机)

.java 后缀的 Java 文件使用 javac 编译成 .class 后缀的字节码文件,字节码文件再通过不同操作系统实现的具体 JVM 虚拟机转化为机器码运行起来(因此 Java 是半解释半编译的语言)。

因此哪怕是其他语言,如果能被转化成字节码并且运行的操作系统上实现了对应的 JVM,也同样可以在虚拟机上运行。通过中间层来达到 一次编译到处运行 的目的,使得 Java 在跨平台能力要优于 C/Cpp

3.关键字

有些关键字被 Java 所保留,不可以给用户创建标识符来使用,这些关键字的类别有很多,例如:intclasscatch 等等,我们后面再来一一介绍。

4.标识符

Java 中可以将类名、对象名、变量名、方法名称为“标识符”。Java 的标识符可以包含:字母、数字、下划线、$ 符号等。

不过需要注意的是不可以使用数字作为标识符的起始字符,但是可以把 $ 作为标识符的开头(但是不建议)。

在命名的时候,不仅要注意命名合法,还要注意合理。在本系列文章中我统一采用:

  1. 类名:大驼峰

  2. 方法名:小驼峰

  3. 变量名:小驼峰

吐槽:从编译原理的角度来看,实际上关键字就是一种特殊的标识符。

5.常量与变量

在提及常量和变量的时候,就需要先提及数据类型,注意这里和 C/Cpp 有很大的不同之处。

5.1.数据类型

Java 的数据类型分为两种:基本类型和引用类型。

  • 其中基本数据类型有四类八种
  • 引用类型通常指类(class)、接口(interface)、数组(array)等

5.1.1.基本类型

四类即:

  1. 整型(整数)

  2. 浮点型(小数)

  3. 字符型(一个字符)

  4. 布尔类型(truefalse,对应对和错,和整型没关系)

八种即:

数据类型关键字内存占用范围
字节型byte1 字节 [ − 128 , 127 ] [-128,127] [128,127]
字符型char2 字节 [ 0 , 65535 ] [0,65535] [0,65535]
短整型short2 字节 [ − 32768 , 32767 ] [-32768,32767] [32768,32767]
整型int4 字节 [ − 2 31 , 2 31 − 1 ] [-2^{31},2^{31-1}] [231,2311]
长整型long8 字节 [ − 2 63 , 2 63 − 1 ] [-2^{63},2^{63}-1] [263,2631]
单精度浮点数float4 字节有,但是不关注
双精度浮点数double8 字节有,但是不关注
布尔型boolean无说明truefalse

Java 的数据类型是固定的不会受平台影响,因此很方便做代码移植。

吐槽:C/Cpp 在不同平台,甚至在同平台的不同编译器上,对于类型的限定都可能会不一样,尤其是在 32/64 平台上有两种解释,因为标准只规定了大致范围和限定,剩下的几乎都交给了编译器来实现。

5.1.2.引用类型

引用类型主要依赖引用这一区别于 C/Cpp 指针的机制,后面再来详细解释,您先简单看作类(class)、接口(interface)、数组(array)等创建的类型即可。

5.2.数据的量

有了数据类型,就可以创建出对应的容器来指代某些量,这些量可以被分为字面常量和数据变量。

5.2.1.字面常量

数据类型可以给字面常量(数据)做出分类。

类似 1003.14"abcdef"false 等这种一眼就能看出数据的都是字面常量,字面常量的类别也是根据数据类型来分类的。

其中 100 就是整型常量、3.14 就是浮点数常量、"abcdef" 就是字符串常量、构成字符串的每一个字符 abc…就是字符常量、falsetrue 就是布尔常量。

5.2.2.数据变量

变量可以理解为一个容器,可以用来存储一个常量,不同类别的常量需要靠不同类别的变量来存储。
而我们需要用一些关键字(也就是前面在数据类型中提到的),使得变量变成只存储某一字面常量类型的变量。

// 定义变量的语法形式
int a = 10; // int 是关键字, a 是标识符, 标记一个变量, 10 为字面常量
// 此时变量 a 存储了 10 这个字面量

补充:在数据变量上,JavaC/Cpp 有很大的不同。

  • Java 没有全局变量这个术语的,但有类似的。
  • Java 编程中如果没有对变量初始化就使用的话,很多编译器直接就会报错,编译也不会通过。
  • 如果赋值给变量过大或者过小的值,Java 也是不会通过编译的。

补充:Java 的字符串类型是包装类型,不是基本数据类型。为了方便后续一些代码的使用,这里提前讲解一下字符类的相关概念。

C 没有字符类型,但是 Java 利用类的优势,使用 String 类定义字符串类型。

// 使用 String 类
public static viod main() {
     String s1 = "Hello";
     String s2 = "I am limou3434";
       String s3 = "100";
       System.out.prinln(s1 + s2);
       //String 转 int
       int number = Inreger.parseInt(str);
       //int 转 String
       String s = String.valueOf(number);
   }

如果您学过 Cpp 其实您能很快理解什么是包装类,您可以简单理解为基本数据类型被包装为一个类类型,这么做的好处是统一参数。而由于 Java 是纯粹的面向对象语言,因此传递参数的时候,大部分使用的是类的实例化对象,将基本数据类型就被包装为包装类,供程序传递参数使用时就会更加方便。

6.类型转化

需要注意的是,Java 是强类型语言,有些不合适的类型转化将会直接报错(C/Cpp 语言是弱类型语言,在这方面会宽松很多)。

6.1.隐式类型转换

代码不需要经过处理,编译器会进行处理不同类型的转换,但是 Java 在这一方面检查得比较严格,不允许溢出和不相关类型转化。

// 使用隐式类型转化
public class Main {
    public static void main(String[] args) {
        int a = 10;
        long b = 100L;
        b = a;// 可以,发生了隐式类型转化, a 从 int 变成 long
        // a = b; // 不可以, 不够存

        float f = 3.14F;
        double d = 5.12;
        d = f; // 可以, f 从 float 转化为 double
        // f = d; // 不可以, 不够存
    }
}

6.2.显式类型转换

这方面类似 C 语言,也是使用 () 来转换,但并不总是能成功,小范围可以转化为大范围的,赋值的数值一定不能溢出,且强制转换的类型要相关且合理。

// 使用显示类型转化
public class Main {
    public static void main(String[] args) {
        int a = 10;
        long b = 100L;
        b = a; // 可以, 发生了隐式类型转化, a 从 int 变成 long
        a = (int)b; // 可以, 将 b 从 long 强制转化为 int

        float f = 3.14F;
        double d = 5.12;
        d = f; // 可以, f 从 float 转化为 double
        f = (float)d; // 可以, 将 d 从 double 前置转化为 float
    }
}

6.3.数据类型提升

在不同变量的运算的运算中,Java 也存在整型提升,和 C 基本差不多。需要注意是 Java 对溢出极其敏感(C 对待溢出十分迟钝),提升后需要赋给对应的容器,除非进行强转,否则会报错。

//查看整型提升现象
public class Main {
    public static void main(String[] args) {
        byte a = 127;
        byte b = 127;
        // byte c = (byte)(a + b); // a 和 b 提升为 int 进行计算,结果也为 int, 虽然可以强转为 byte, 但很危险
        int d = a + b; // 这样才比较好
    }
}

7.运算符

这里我们只挑出几个比较特殊的运算符,其余的运算符和 C 基本差不多(包括“结合性”和“优先级”),这里就不再赘述。

  1. Java 的除法和 C 类似,会向下取整,并且除以 0 会抛出异常 ArithmeticException(算数异常)

    // 使用除法的示例
    public class Main {
        public static void main(String[] args) {
            System.out.println(5 / 2); // 2
            System.out.println(5.0 / 2); // 2.5
            System.out.println(5 / 2.0); // 2.5
            System.out.println((float)5 / 2); // 2.5
            System.out.println(5 / (float)2); // 2.5
            System.out.println((float)(5 / 2)); // 2.0
        }
    }
    
  2. 由于除法一样,所以 % 运算也是一样的,需要注意的是,该运算符也可以对小数进行操作(就是很少用)

    // 使用取模的示例
    public class Main {
        public static void main(String[] args) {
            System.out.println(10 % 3); // 1
            System.out.println(-10 % 3); // -1
            System.out.println(10 % -3); // 1
            System.out.println(-10 % -3); // -1
    
            System.out.println(-10.3 % 3); // -1.3000000000000007
        }
    }
    
  3. 在增量运算符中有的时候会发生类型转化,等价于强转

    // 使用增量运算符发生隐式强转
    public class Main {
        public static void main(String[] args) {
            int num1 = 10;
            double num2 = 3.14;
    
            int add1 = 0;
            double add2 = 0.0;
    
            // 方式一
            // add1 = num1 + num2; // 4 字节和 8 字节相加,发生整形提升, 只用 4 个字节是放不下去的
            // System.out.println(add1);
            add2 = num1 + num2;
            System.out.println(add2);
            System.out.println();
    
            // 方式二
            add1 = (int) (num1 + num2);
            System.out.println(add1);
            add2 = (double) (num1 + num2);
            System.out.println(add2);
            System.out.println();
    
            // 方式三
            num1 += num2; // 等价于 a = (int)(a + b)
            System.out.println(num1);
        }
    }
    

    而自增、自减运算符还有一种特殊的情况需要您注意,您应该避免出现下面这样的代码…

    // 有关于加加和减减的一个很坑的点
    public class Main {
        public static void main(String[] args) {
            int a = 10;
            a = a++;
            System.out.println(a);
            // 结果为 10,而不是 11,这个原因涉及底层
            // 以后我有机会再来填坑,这里充分体现了 Java 和 C/C++ 不一样!
        }
    }
    
  4. 关系运算符、逻辑运算符(也具有短路效应)的操作表达式必须为布尔表达式,其运算结果为 trueflase,不是 非00。而 iffor 判断的环节中使用的也是布尔表达式

  5. Java 的移位操作符有三个 <<>>>>>>> 是左补符号位,>>> 是左补 0

  6. 也有一个唯一的三目操作符:条件运算符 表达式1 ? 表达式2 : 表达式3。并且该表达式必须是被使用的(其结果必须被使用),不能单独存在

  7. 对于位操作,建议还是使用括号引导表达式的逻辑,避免出现意想不到的后果(在 C 中也最好一样)

注意:如果摒弃掉 C 的“非零为真”的概念在接下来的编码中会轻松很多…

8.控制语句

和大部分编程语言类似,Java 也有自己的控制语句,和 C 也有些类似,但是在入口判断有很大的不同,不同的根源来自于:C 使用整数的非零和 0 来判断真假,而 Java 完全使用布尔类型来判断真假,而 Java 的布尔类型和整数是无法进行比较的,这就导致 Java 写出来的入口判断会更加清晰(也可以说没有 C/C++ 那样整洁,至于是清晰好还是简洁好,看您喜好而定)

8.1.分支语句

8.1.1.if 语句

Javaif 语句,几乎和 C/C++ 的使用一样,并且也有类似的悬挂 else 的问题,真要说有哪些点不同,就是 C/C++Java 的代码缩进风格不太一样。

//使用 if 语句
public class Main {
    public static void main(String[] args) {
        int a = 1;
        if (a == 1) { //这里只能是整型
            System.out.println(a);
        } else {
            System.out.println("a != 1");
        }
    }
}

8.1.2.switch 语句

同样,几乎和 C 一样,就是需要注意的是:switch 的入口只能使用 charbyteshortintCharacterByteShortIntegerStringenum 类型,其他类型一概不支持(比如 long 就不行),这点很重要。

//使用 switch 语句
public class Main {
    public static void main(String[] args) {
        int a = 1;
        switch (a) { //这里只能是整型
            case 1:
                System.out.println(a);
                break;
            case 2:
                System.out.println(a);
                break;
            default:
                System.out.println("default");
        }
    }
}

8.2.循环语句

8.2.1.for 语句

//使用 for 语句
public class Main {
    public static void main(String[] args) {
        for (int a = 1; a < 10; a++) {
            System.out.println(a);
        }
    }
}

8.2.2.while 语句

//使用 while 语句
public class Main {
    public static void main(String[] args) {
        int a = 1;
        while (a < 10) {
            System.out.println(a);
            a++;
        }
    }
}

8.2.3.do-while 语句

//使用 do-while 语句
public class Main {
    public static void main(String[] args) {
        int a = 1;
        do {
            System.out.println(a);
            a++;
        } while (a < 10);
    }
}

让我们借助循环语句,顺便来讲解一下在 IDEA 中如何调试代码:

在这里插入图片描述

9.输入输出

9.1.输出数据

Java 有三种常用的输出,均体现在下述代码中:

// 使用三种输出语句
public class Main {
    public static void main(String[] args) {
        System.out.print("limou"); //输出,但不换行(无需关注类型)
        System.out.println("limou"); //输出,但是换行(无需关注类型)
        System.out.printf("%s", "limou"); //格式化输出输出
    }
}

您可能会好奇格式化输出是否和 C 一样,实际上有些类似,也有些不同:

  • %o%d%x:整数的八进制、十进制、十六进制输出
  • %f%e%g%a:定点浮点数、指数浮点数、通用浮点数、十六进制浮点数输出
  • %s%c:字符串、字符输出
  • %b:布尔值输出
  • %h:散列码输出
  • %%:百分号输出

此外,也有一些修饰符,您稍微了解一下即可。

9.2.输入数据

// 使用输入语句
// 导入相关的包(可以将光标停在对应关键字上,使用快捷键 [alt+enter] 来快速导入)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        // 创建一个 scan 对象, 且 System.in 代表设置为“从键盘输入”
        Scanner scan = new Scanner(System.in);

        System.out.println("请输入您的年龄"); // 提示用户输入
        int age = scan.nextInt(); // 通过方法获取输入

        System.out.println("请输入您的名字"); // 提示用户输入
        String name = scan.next(); // 通过方法获取输入(会忽略一开始的空白字符, 再次遇到空白字符就会停下)

        // 使用 nextLine() 则会获取空白字符, 但是有可能有失效的问题, 也就是多余空白字符被误输入的问题
        String ch = scan.nextLine(); // 先除去上述输入得最后产生得换行符
        System.out.println("输入您的爱好");
        String hobby = scan.nextLine(); // 忽略一开始的空白字符(除了换行字符), 获取连续的字符串, 包括空白字符(除了换行字符)

        System.out.println("请输入您的体重"); // 提示用户输入
        float weight = scan.nextFloat(); // 通过方法获取输入(会忽略空白字符)

        System.out.println("年龄:" + age); // 输出信息
        System.out.println("名字:" + name); // 输出信息
        System.out.println("爱好:" + hobby); // 输出信息
        System.out.println("体重:" + weight); // 输出信息

        scan.close(); //类似 C 语言的文件关闭
    }
}

/* 输出结果
请输入您的年龄
18
请输入您的名字
limou 3434
输入您的爱好
game and programme
请输入您的体重
51.2
年龄: 18
名字: limou
爱好: game and programme
体重: 51.2
*/

注意:关于 Scanner 还有很多的知识,我将会在 IO 详细讲解。

当然,一般建议文本输入最好放在最前面处理(尤其是多数据类型输入的时候)。还有一个循环输入的代码也值得您一看。

// 多组输入
// 导入相关的包(可以将光标停在对应关键字上,使用快捷键 [alt+enter] 来快速导入)
import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scan = new Scanner(System.in);
        System.out.print("请输入一个数字 ");
        while (scan.hasNextInt()) {
            int number = scan.nextInt();
            System.out.println("您输入的数字是:" + number);
            System.out.print("请输入一个数字 ");
        }
        // 在终端中使用 [ctrl+d] 会终止循环
    }
}

/* 输出结果
请输入一个数字 18
您输入的数字是: 18
请输入一个数字 20
您输入的数字是: 20
请输入一个数字 35
您输入的数字是: 35
请输入一个数字 5
您输入的数字是: 5
请输入一个数字 100
您输入的数字是: 100
请输入一个数字
...
*/

10.随机数

Java 的随机数生成也比较简单,使用如下代码即可:

// 随机数生成
// 导入相关的包(可以将光标停在对应关键字上,使用快捷键 [alt+enter] 来快速导入)
import java.util.Random;

public class Main {
    public static void main(String[] args) {
        int count = 0;

        Random random1 = new Random();
        while (count < 10) { // 循环打印 10 次查看随机数
            int n = random1.nextInt();
            System.out.println(n);
            count++;
        }

        Random random2 = new Random();
        while (count > 0) { // 循环打印 10 次查看随机数
            int n = random2.nextInt(100); // 限定 [0, 100) 的随机数
            System.out.println(n);
            count--;
        }
    }
}

/* 输出结果(随机的)
1341966210
210008845
453512808
804932370
28871118
-913616368
469568144
-904536397
190689066
-546299782
69
65
21
54
6
83
0
1
81
41
*/

还有一个数学库的随机数,您也可以去了解一下…

11.方法

11.1.方法的定义

方法和 C 中的函数是否类似(因为它们的工作是差不多的,都是通过调用来达到简化代码的目的),而为什么不继续延用“函数”这个术语,而使用“方法”呢?

简单来说就是类的出现导致的,Java 使用类来创建一个又一个的对象,这些对象很类似普通的变量,而类内写入的对象可以执行的方法,这样创建出一个对象就可以使用配套的对象方法,这些内容我将会在下一节的类中重新阐述(现在您把方法简单视为函数)。

// 方法的使用
public class Main {
    public static void main(String[] args) {
        System.out.println(add(1, 2));
    }
    public static int Add(int a, int b) {
        return a + b;
    }
}

/* 输出结果
3
*/

另外,方法不能嵌套定义,一个方法的内部是不能定义另外一个方法的。

方法在类内是全局的,也就是说无论把 Add() 写到类的哪里,类内的 main() 都可以执行该方法。

11.2.方法的参数

Java 的方法也有和 C 函数类似的形参和实参的问题,但由于 Java 没有 C/C++ 的指针,如果传递一个参数过来,该怎么进行修改呢?

//形参和实参的一个问题
public class Main {
    public static void main(String[] args) {
            int num1 = 5, num2 = 10;

            System.out.println("交换方法一");
            System.out.println("交换前 num1:" + num1 + " " + "num2:" + num2);
            int tmp = num1;
            num1 = num2;
            num2 = tmp;
            System.out.println("交换后 num1:" + num1 + " " + "num2:" + num2);

            System.out.println("交换方法二");
            System.out.println("交换前 num1:" + num1 + " " + "num2:" + num2);
            Swap(num1, num2);//使用方法交换(交换失败)
            System.out.println("交换后 num1:" + num1 + " " + "num2:" + num2);
    }
    public static void Swap(int num1, int num2) {
        int tmp = num1;
        num1 = num2;
        num2 = tmp;
    }
}
/*
交换方法一
交换前 num1: 5 num2: 10
交换后 num1: 10 num2: 5
交换方法二
交换前 num1: 10 num2: 5
交换后 num1: 10 num2: 5
*/

可以采用数组的方法来规避这一问题。

// 使用数组的引用达到目的
public class Main {
    public static void main(String[] args) {
        int[] nums = {5, 10};

        System.out.println("交换前 num1:" + nums[0] + " " + "num2:" + nums[1]);
        swap(nums, 0, 1);
        System.out.println("交换后 num1:" + nums[0] + " " + "num2:" + nums[1]);
    }

    public static void swap(int[] nums, int i, int j) {
        int tmp = nums[i];
        nums[i] = nums[j];
        nums[j] = tmp;
    }
}

11.3.方法的递归

除此之外,Java 也支持递归调用方法。

//使用方法递归计算阶乘
public class Main {
    public static void main(String[] args) {
        int number = 5;
        System.out.println(Test(number));
    }
    public static int Test(int number) {
        if (number == 0 || number == 1) {
            return 1;
        } else if (number < 0) {
            return -1;
        }
        return Test(number - 1) * number;
    }
}

/* 输出结果
120
*/

11.4.方法的重载

函数重载和 C++ 的重载类似,也就是说 Java 允许类内一个方法可以有多种实现。这些方法实现的方法名字是一样的,并且都 在同一个类内,但参数列表是不一样的(体系在 参数个数参数顺序 不一样,但是不包括返回值不一样)。

// 需要使用方法重载的例子
public class Main {
    public static void main(String[] args) {
        int number1 = 5;
        System.out.println(Test(number1));
        double number2 = 5.0;
        System.out.println(Test(number2)); // 无法调用 Test()
    }

    public static int Test(int number) {
        if (number == 0 || number == 1) {
            return 1;
        } else if (number < 0) {
            return -1;
        }
        return Test(number - 1) * number;
    }
}
// 为 Test() 提供重载版本
public class Main {
    public static void main(String[] args) {
        int number1 = 5;
        System.out.println(Test(number1));

        double number2 = 5.0;
        System.out.println(Test(number2)); // 成功调用 Test() 的重载版本
    }

    public static int Test(int number) {
        if (number == 0 || number == 1) {
            return 1;
        } else if (number < 0) {
            return -1;
        }
        return Test(number - 1) * number;
    }

    public static double Test(double number) {
        if (number == 0 || number == 1) {
            return 1;
        } else if (number < 0) {
            return -1;
        }
        return Test(number - 1) * number;
    }
}

/* 输出结果
120
120.0 
*/

12.数组

12.1.数组的使用

C/C++ 诡异的数组、指针创建风格曾折磨过不少初入门的家伙们,而 Java 的数组创建在这里和 C/C++ 有很大的不同,并且有更加便捷的操作。

// 尝试使用数组
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        // 1.创建数组
        // 创建静态数组: 数组类型 数组名 = { 元素列表 };
        // 创建动态数组: 数组类型 数组名 = new 数组类型 { 元素列表 }
        // 无论是静态创建还是动态创建, 其实最终数组元素都会存储到堆上

        // (1)创建一维数组
        int[] arr1 = { 3, 2, 1 };
        int[] arr2 = new int[]{ 3, 2, 1 };
        int[] arr3 = new int[3]; /* 空数组默认元素都为 0 */

        // (2)创建二维数组
        int[][] arr4 = { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12} };
        int[][] arr5 = new int[][] { {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, {10, 11, 12} };
        int[][] arr6 = new int[4][3]; /* 空数组默认元素都为 0 */

        // 初始化的元素列表只有在定义阶段使用, 不能先定义然后另起一行进行初始化元素列表
        // 如果希望定义出一个空数组, 那么需要携带部分值供编译器识别
        // 数组类型 数组名 = new 数组类型[量][...]
        // 这里的量可以是常量也可以是变量


        // 2.遍历数组
        // (1)使用普通 for 循环
        for (int i = 0; i < arr1.length; i++) { // 属性 array.length 用来获取数组的长度
            System.out.print(arr1[i] + ", ");
        }
        System.out.println();

        // (2)使用增强 for 循环 foreach(Cpp 中的范围 for)
        for (int index : arr2) {
            System.out.print(index + ", ");
        }
        System.out.println();

        // (3)使用数组类打印
        System.out.println(Arrays.toString(arr4)); // 关于 Arrays 后续再来提及
        System.out.println(Arrays.deepToString(arr5));


        // 3.排序数组
        System.out.println("排序后");
        // (1)全局排序
        Arrays.sort(arr1);
        System.out.println(Arrays.toString(arr1));
        // (2)局部排序
        Arrays.sort(arr2, 0, 2); // 排序范围是 [0, 2)
        System.out.println(Arrays.toString(arr2));
        /* 逆向排序有些麻烦, 后面再提及 */


        // 4.填充数组
        System.out.println("填充前" + Arrays.toString(arr3)); // 填充前
        Arrays.fill(arr3, 1, 3, -1); // 从 [1, 3) 的范围中填充 -1 这个数字
        System.out.println("填充后" + Arrays.toString(arr3)); // 填充后


        // 5.查找数组
        System.out.println("在数组 arr5[3] 中, 存在元素 12, 其对应的索引为 " + Arrays.binarySearch(arr5[3], 12)); // 使用二分查找来查找


        // 6.比较数组
        if(Arrays.equals(arr1, arr1)) {
            System.out.println("arr1 自己和自己等价");
        }

        if(Arrays.deepEquals(arr4, arr5)) { // 深度等价
            System.out.println("arr4 和 arr5 是等价的");
        }

        if(!Arrays.equals(arr1, arr3)) {
            System.out.println("arr1 和 arr3 是不等价的");
        }
    }
}

警告:无论是静态创建还是动态创建,最终数组元素都会存储到堆上,而数组名作为引用变量指向/引用堆空间里的数组元素,并且使用下标/索引来进行访问。

警告:对于基本类型的数组,默认初始化为 0

补充:数组被创建时,如果类型时基本数据类型会自动进行初始化,如果时自定义类类型,也会调用构造函数进行初始化,这点在和 Cpp 是一样的。

补充:Java 的数组可以使用索引来查找和修改对应元素,并且索引也是从 0 开始的,Java 的数组越界会抛出异常,这比 C/C++ 的基本数组要安全得多。

补充:当 Java 数组发生索引越界时会发生异常。

12.2.数组的引用

首先您需要注意,数组是一个引用类型,什么是引用类型呢?首先您需要了解一下 Java 的内存分布。首先内存是连续分布的存储空间,程序中运行所需要的数据就存储在内存空间中,而 JVM 虚拟机对内存的划分大致如下:

flowchart TD
subgraph "运行时数据区"
	subgraph "所有线程共享的数据区"
        a["方法区"]
        b["堆区"]
    end
	subgraph "线程隔离的数据区"
		c["虚拟机栈"] ~~~ d["本地方法栈"] ~~~ e["程序计数器"]
    end
end
  1. 方法区(Method Area): 存储虚拟机加载的类信息、常量、静态变量等,即编译器编译后的代码数据。
  2. 堆区(Heap): JVM 所管理的最大内存区域,所有使用 new 创建的对象都是在堆上保存,堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有程序在使用,就不会被销毁。其中销毁数据的 GC,也是 Java 最重要的特征之一…
  3. 虚拟机栈(JVM stack):与方法调用相关的一些信息,每个方法在执行时,都会先创建一个栈帧,栈帧中包含有了局部变量表、操作数栈、动态链接、返回地址…保存的都是与方法执行时相关信息(例如局部变量,在方法运行结束后,栈帧就会被销毁,栈帧中保存的数据也跟着销毁了。
  4. 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似,只不过保存的内容是 Native 方法(即原生方法)的局部变员,在有些版本的 JVM 实现中(例如 HotSpot),本地方法栈和虚拟机栈是在一起使用的,这些原生方法很大程度上就是 C/Cpp 代码实现的。
  5. 程序计数器(PC Register):只是一个很小的空间,保存下一条执行的指令的地址

补充:此外还有个 jdk 1.8 的概念,即本地内存(元空间、运行时常量池以及直接内存)

这里简单看一下即可…我们主要焦距在堆和虚拟机栈上,让我们来分析下面这个代码的变量和数组的存储情况:

// 分析内存情况
public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        int[] arr = { 1, 2, 3, 4 };
    }
}
Stack
Heap
引用
a变量
b变量
arr的哈希地址(形式地址/引用)
存储数组元素[1][2][3][4]

可以看到 arr 这个标识符引用了数组,因此在 Stack 区域中不是直接存储数组的数据,只是存储了数组的一个“标记”。

注意:这里的形式地址不是 C/Cpp 中的地址,但概念有些类似。

因此我们在 Java 中就会遇到传递引用的情况,并且我还给出了图示:

// 分析传引用的情况
public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        int[] arr1 = { 1, 2, 3, 4 };
        for(int e : arr1) {
            System.out.print(e + " ");
        }
        System.out.println();

        int[] arr2 = arr1;
        for(int e : arr2) {
            System.out.print(e + " ");
        }
        System.out.println();

        arr2[2] = 100;
        for(int e : arr1) {
            System.out.print(e + " ");
        }
        System.out.println();
    }
}
/* 输出结果
1 2 3 4
1 2 3 4
1 2 100 4
*/
Stack
Heap
引用
通过 arr2 引用修改数组元素
a变量
b变量
arr1的哈希地址(形式地址/引用)
arr2的哈希地址(形式地址/引用)
存储数组元素[1][2][100][4]

注意:强调一下,从这里的引用就可以看出 Java 的引用和 C++ 的引用有很大的不同,我建议直接认为是两个不同的东西,以避免混淆…

还有一些特殊并且值得注意的传递引用情况:

// 改变引用
public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 5;
        int[] arr1 = { 1, 2, 3, 4 };
        for(int e : arr1) {
            System.out.print(e + " ");
        }
        System.out.println();

        int[] arr2 = { 4, 3, 2, 1 };
        for(int e : arr2) {
            System.out.print(e + " ");
        }
        System.out.println();

        arr1 = arr2;
        for(int e : arr1) {
            System.out.print(e + " ");
        }
        System.out.println();

        // 尝试修改并观察
        arr2[1] = 10000;
        for(int e : arr1) {
            System.out.print(e + " ");
        }
        System.out.println();
        for(int e : arr2) {
            System.out.print(e + " ");
        }
        System.out.println();
    }
}
/* 输出结果
1 2 3 4 
4 3 2 1 
4 3 2 1 
4 10000 2 1 
4 10000 2 1 
*/
Stack
Heap
取消引用
改变引用
引用
a变量
b变量
arr1的哈希地址(形式地址/引用)
arr2的哈希地址(形式地址/引用)
(由于没有引用指向该数组,此处将被自动销毁)存储数组元素[1][2][3][4]
存储数组元素[4][3][2][1]

也就是说,一个引用不能同时指向多个对象,但是一个对象能被多个引用指向。同时,如果堆中的数组没有任何“标记”存在于 Stack 中,也就是没有任何一个标识符引用这个数组,那么 Java GC 会根据自己的决策来释放该数组。

引用类型的初始化可以使用 null,代表引用不指向任何的对象(直接使用索引进行读写操作就会出现空指针异常)。因此JavanullC/C++ 不一样,它不是指内存上的 0 地址,只是代表不指向任何对象,两者没有直接关联。

12.3.数组的传递

下面这个代码您需要好好分析一下:

// 传递数组参数
import java.util.Arrays;
public class Main {
    public static void func1(int[] arr) { // 形参 arr
        arr = new int[] {0, 0, 0, 0};
    }
    public static void func2(int[] arr) { // 形参 arr 
        arr[1] = 100;
    }

    public static void main(String[] args) {
        int[] arr = { 1, 2, 3, 4 }; // 实参 arr
        func1(arr);
        func2(arr);
        System.out.println(Arrays.toString(arr));
    }
}
/* 输出结果
[1, 100, 3, 4]
*/

这份代码可能会让您吃惊,让我们来看看引用指向和内存分布的分析图,调用方法 func1() 且尚未执行 arr = new int[]{0, 0, 0, 0}; 时,发生以下事情。

Stack
Heap
引用
引用
形参 arr 的哈希地址(形式地址/引用)
实参 arr 的哈希地址(形式地址/引用)
存储数组元素[1][2][3][4]

执行 arr = new int[]{0, 0, 0, 0}; 后发生以下事情。

Stack
Heap
引用
取消引用
引用
形参 arr 的哈希地址(形式地址/引用)
实参 arr 的哈希地址(形式地址/引用)
存储数组元素[1][2][3][4]
存储数组元素[0][0][0][0]

func1() 调用结束后,形参 arr 被销毁,原本指向的对象没有被引用,就会被 Java 自动销毁。最终什么事情没有发生,实参 arr 没有发生任何改变。

Stack
Heap
引用
实参 arr 的哈希地址(形式地址/引用)
存储数组元素[1][2][3][4]

而调用 func2() 并且执行语句 arr[1] = 100; 就会导致实参指向的数组也会跟着变化。

Stack
Heap
引用(并且对数组做修改)
引用
形参 arr 的哈希地址(形式地址/引用)
实参 arr 的哈希地址(形式地址/引用)
存储数组元素[1][100][3][4]

利用数组的引用传递,我们可以使用数组引用的特性来完成两数交换的目的。

// 两数交换
import java.util.Arrays;
public class Main {
    public static int[] Swap(int[] arr) {
        int tmp = arr[0];
        arr[0] = arr[1];
        arr[1] = tmp;
        return arr;
    }

    public static void main(String[] args) {
        int[] arr = { 5, 10 };
        System.out.println(Arrays.toString(arr));

        int[] swapArr = Swap(arr);
        System.out.println(Arrays.toString(swapArr));
    }
}
/* 输出结果
[5, 10]
[10, 5]
*/

12.4.数组的拷贝

但对于方法来说,传应用有时太过于危险,在不考虑拷贝开销的情况下,可以考虑对数组进行拷贝后再进行处理(可以是拷贝后传递给方法,也可以是方法获得数组后多一步拷贝,这样就有可能会有多次拷贝,这种情况以后补充…)。

使用 Arrays 的方法 copyOf() 可以拷贝数组的内容,并且可以带有拷贝长度的参数,长度小于源 s 数组就拷贝子数组,长度大于原数组则多余的部分默认初始为 0

// 数组拷贝
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        int[] arr = new int[] {1, 2, 3, 4, 5};
        int[] copy1 = Arrays.copyOf(arr, 3); // 只拷贝三个元素
        for (int e : copy1) {
            System.out.print(e + " ");
        }

        System.out.println();

        int[] copy2 = Arrays.copyOf(arr, arr.length * 2); // 拷贝数组所有元素, 不够拷贝就填零
        for (int e : copy2) {
            System.out.print(e + " ");
        }
    }
}

/* 输出结果
1 2 3 
1 2 3 4 5 0 0 0 0 0
*/

补充:实际上 copyOf() 的底层实现使用 arraycopy() ,其底层是使用 C/C++ 实现的,如果打开实现就会出现关键字 native,代表该实现不是使用 Java 代码实现的,而是使用 C/C++(这还是要看具体的实现需要看 JVM 的源码)。

// 另一种拷贝(比较底层)
public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1, 2, 3, 4, 5};
        int[] copy = new int[arr.length * 2];
        System.arraycopy(arr, 2, copy, 1, arr.length - 2); //底层使用 C/C++ 实现
        for (int e : copy) {
            System.out.print(e + " ");
        }
    }
}

/* 输出结果
0 3 4 5 0 0 0 0 0 0
*/

还有另外一个方法 copyOfRange() 可以拷贝局部的子数组。

//拷贝局部子数组
import java.util.Arrays;
public class Main {
    public static void main(String[] args) {
        int[] arr = new int[] {1, 2, 3, 4, 5};
        int[] copy = Arrays.copyOfRange(arr, 2, 4); // 拷贝 [2, 4) 的数组元素
        for (int e : copy) {
            System.out.print(e + " ");
        }
    }
}
/* 输出结果
3 4
*/

如果只是单纯想拷贝全部的数组,直接使用 clone() 会更加方便。

// 直接克隆数组整体
public class Main {
    public static void main(String[] args) {
        int[] arr = new int[] {1, 2, 3, 4, 5};
        int[] copy = arr.clone();
        for (int e : copy) {
            System.out.print(e + " ");
        }
    }
}

/* 输出结果
1 2 3 4 5 
*/

注意:目前我只讨论基本数据类型构成的数组,不涉及到深拷贝的问题,关于深浅拷贝我们以后再来提及。

13.字符串

在您学习了如何使用数组后,就能很快理解字符串,从另外一个角度上来说,字符串实际上是数组的一种特殊形式(虽然我不知道在 Java 内部 String 是否有进行复用,但理解终究是和数组一样的)。因此前面有关数组的使用我尽可能讲的详细,但有关字符串的部分我只提供一份代码和注释供您研究。

// 尝试使用字符串
import java.nio.charset.StandardCharsets;
import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        // 1.获取字符串中的单字符
        String str1 = new String("Hello, World!");
        String str2 = "你好,世界";
        String str3 = "limou3434.com/blog/login";
        String str4 = "23";
        System.out.println("str1.charAt(0): " + str1.charAt(0)); // 获取索引为 0 的字符, 不允许使用 str1[0] 进行访问
        System.out.println("str2.length(): " + str2.length()); // 获取字符串的长度, 可以看到汉字也和字母一样做处理


        // 2.比较字符串是否等价
        if (str1.equals("Hello, World!")) { // 比较两个字符串是否相等
            System.out.println("两个字符串相等");
        }
        if (str1.equalsIgnoreCase("hello, world!")) { // 忽略大小写比较字符串
            System.out.println("两个字符串相等");
        }


        // 3.字符串大小写转换
        System.out.println("大写: " + str1.toUpperCase()); // 将字符串转换为大写
        System.out.println("小写: " + str1.toLowerCase()); // 将字符串转换为小写


        // 4.截取子串
        System.out.println("子串: " + str1.substring(3, 6)); // 截取 str1 中 [3, 6) 的部分


        // 5.分割子串
        System.out.println("分割结果为: " + Arrays.toString(str3.split("/"))); // 根据指定的分隔符将此字符串分割成子字符串数组


        // 6.替换和搜索
        System.out.println(str1.indexOf("World")); // 返回指定子字符串在此字符串中第一次出现处的索引
        System.out.println(str1.replace('o', '0')); // 将字符串中所有的 'o' 替换为 '0'
        if (str1.matches(".*Hello.*")) {
            System.out.println("符合给定的匹配模式");
        }

        // 7.格式化字符串
        System.out.println("格式化结果: " + String.format("Hello, %s!", "World"));


        // 8.转为目标类型
        int number = Integer.parseInt(str4);
        System.out.println("转化结果: " + number);


        // 9.字符串编码和解码
        byte[] bytes = str1.getBytes(StandardCharsets.UTF_8); // 将字符串编码为字节序列
        System.out.println("编码后: " + Arrays.toString(bytes));
        System.out.println("解码后: " + new String(bytes, StandardCharsets.UTF_8)); // 将字节序列解码为字符串
    }
}

14.IDEA 快捷键

和其他编程语言有一个很大的不同在于 IDEA 几乎是每一个 Java 程序员必须要学会使用的软件,这里简单列出几个快捷键,在后续的章节中,我还会开启关于 IDEA 的详细使用。

  • [ctrl + /] 注释和取消注释
  • ctrl + alt + l 格式化
  • [psvm + tab]/[m + tab] 生成 main 方法
  • [sout + tab] 生成 println 语句

结语:…

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1903334.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

存储结构与管理磁盘

前言&#xff1a;本博客仅作记录学习使用&#xff0c;部分图片出自网络&#xff0c;如有侵犯您的权益&#xff0c;请联系删除 目录 一、一切从“/”开始 二、物理设备的命名规则 三、文件系统与数据资料 四、挂载硬件设备 五、添加硬盘设备 六、添加交换分区 七、磁盘容…

Linux系统的介绍和常用命令

文章目录 介绍常用命令文件和目录操作文件内容操作系统管理命令网络命令 &#x1f388;个人主页&#xff1a;程序员 小侯 &#x1f390;CSDN新晋作者 &#x1f389;欢迎 &#x1f44d;点赞✍评论⭐收藏 ✨收录专栏&#xff1a;Liunx系统 ✨文章内容&#xff1a;Liunx系统介绍 &…

C语言 | Leetcode C语言题解之第217题存在重复元素

题目&#xff1a; 题解&#xff1a; struct hashTable {int key;UT_hash_handle hh; };bool containsDuplicate(int* nums, int numsSize) {struct hashTable* set NULL;for (int i 0; i < numsSize; i) {struct hashTable* tmp;HASH_FIND_INT(set, nums i, tmp);if (tm…

css导航栏遮挡住垂直滚动条,以及100vw引起的横向滚动条出现

滚动条被导航栏遮住问题 解决前 解决过程 一开始想要body的宽度为整个视口的宽度 100vw view width 不过出现了横向滚动条 于是乎想着给所有元素增加 x轴溢出时隐藏 问题解决&#xff0c;不过顶部的导航栏由于设置了fixed 又把右边导航栏挡住了 可能因为 body 占100视口宽度…

简单且循序渐进地查找软件中Bug的实用方法

“Bug”这个词常常让许多开发者感到头疼。即使是经验丰富、技术娴熟的开发人员在开发过程中也难以避免遭遇到 Bug。 软件中的故障会让程序员感到挫败。我相信在你的软件开发生涯中&#xff0c;也曾遇到过一些难以排查的问题。软件中的错误可能会导致项目无法按时交付。因此&…

【python】python当当数据分析可视化聚类支持向量机预测(源码+数据集+论文)【独一无二】

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

【C++】map和set详解

目录 1. 关联式容器 2. 键值对pair 3. 树形结构的关联式容器 4. set 4.1 set的介绍 4.2 set的构造 4.3 set的迭代器 4.4 set的容量 4.5 set的常用函数 5. multiset 6. map 6.1 map的介绍 6.2 map的构造 6.3 map的迭代器 6.4 map的容量 6.5 map的operator[] 6.6…

【学习笔记】程序设计竞赛

程序设计竞赛 文章目录 程序设计竞赛0x00 基本操作指南0x01 算法分析0x02 STL和基本数据结构栈队列集合map 0x03 排序插入排序归并排序&#xff08;Merge Sort)快速排序 0x04 搜索技术BFSDFS回溯与剪枝 深度迭代ID A*A star双向广搜 0x05 递推方程0x06 高级数据结构并查集二叉树…

STM32快速复习(八)SPI通信

文章目录 前言一、SPI是什么&#xff1f;SPI的硬件电路&#xff1f;SPI发送的时序&#xff1f;二、库函数二、库函数示例代码总结 前言 SPI和IIC通信算是我在大学和面试中用的最多&#xff0c;问的最多的通信协议 IIC问到了&#xff0c;一般SPI也一定会问到。 SPI相对于IIC多了…

HTTP请求响应/与HTTPS区别

HTTP&#xff08;Hypertext Transfer Protocol&#xff09;和HTTPS&#xff08;Hypertext Transfer Protocol Secure&#xff09;是用于在计算机网络上传输信息的两种协议。 HTTP&#xff08;Hypertext Transfer Protocol&#xff09;: HTTP 是一种用于传输超文本的应用层协议…

Go 依赖注入设计模式

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

前后端分离系统

前后端分离是一种现代软件架构模式&#xff0c;特别适用于Web应用开发&#xff0c;它强调将用户界面&#xff08;前端&#xff09;与服务器端应用逻辑&#xff08;后端&#xff09;相分离。两者通过API接口进行数据交互。这种架构模式的主要优势在于提高开发效率、维护性和可扩…

安卓虚拟位置修改

随着安卓系统的不断更新&#xff0c;确保软件和应用与最新系统版本的兼容性变得日益重要。本文档旨在指导用户如何在安卓14/15系统上使用特定的功能。 2. 系统兼容性更新 2.1 支持安卓14/15&#xff1a;更新了对安卓14/15版本的支持&#xff0c;确保了软件的兼容性。 2.2 路…

《算法笔记》总结No.3——排序

基础算法之一&#xff0c;相当重要。在普通的机试中如果没有数据类型和时空限制&#xff0c;基本上选择自己最熟悉的就好。本篇只总结选择排序和插入排序&#xff0c;侧重应用&#xff0c;408中要求的种类更加繁多&#xff0c;此处先不扩展难度~总结最常用的两种排序。 一.选择…

HTML 【实用教程】(2024最新版)

核心思想 —— 语义化 【面试题】如何理解 HTML 语义化 ?仅通过标签便能判断内容的类型&#xff0c;特别是区分标题、段落、图片和表格 增加代码可读性&#xff0c;让人更容易读懂对SEO更加友好&#xff0c;让搜索引擎更容易读懂 html 文件的基本结构 html 文件的文件后缀为 …

VMware虚拟机配置桥接网络

转载&#xff1a;虚拟机桥接网络配置 一、VMware三种网络连接方式 VMware提供了三种网络连接方式&#xff0c;VMnet0, VMnet1, Vmnet8&#xff0c;分别代表桥接&#xff0c;Host-only及NAT模式。在VMware的编辑-虚拟网络编辑器可看到对应三种连接方式的设置&#xff08;如下图…

深度解析Ubuntu版本升级:LTS版本升级指南

深度解析Ubuntu版本升级&#xff1a;Ubuntu版本生命周期及LTS版本升级指南 Ubuntu是全球最受欢迎的Linux发行版之一&#xff0c;其版本升级与维护策略直接影响了无数用户的开发和生产环境。Canonical公司为Ubuntu制定了明确的生命周期和发布节奏&#xff0c;使得社区、企业和开…

viscode-插件

vue组件生成&#xff1a; vue.json {"Print to console": {"prefix": "vue", "body": ["<!-- $1 -->","<template>","<div>","</div>","</template>&q…

全面解析 TypeScript 泛型的二三事

2024年了相信大家都已经在日常开发的过程中使用上了 TypeScript 了。TypeScript 增强了代码可靠性和可维护性&#xff0c;确保减少运行时错误并提高开发人员的工作效率。 TypeScript 通过类型声明 使得 javascript 拥有了强类型校验。而泛型的是类型声明中最重要的一环&#x…

Git在多人开发中的常见用例

前言 作为从一个 svn 转过来的 git 前端开发&#xff0c;在经历过git的各种便捷好处后&#xff0c;想起当时懵懂使用git的胆颤心惊&#xff1a;总是害怕用错指令&#xff0c;又或者遇到报错就慌的场景&#xff0c;想起当时查资料一看git指令这么多&#xff0c;看的头晕眼花&am…