Java基础:基本语法(一)

Java基础:基本语法(一)


文章目录

  • Java基础:基本语法(一)
    • 1. 前言
    • 2. 开发环境搭建
      • 2.1 Java开发工具包下载
      • 2.2 环境变量配置
      • 2.3 Java程序的运行过程
    • 3. 数据类型
      • 3.1 基本数据类型
      • 3.2 引用数据类型
    • 4. 常量与变量
      • 4.1 常量
        • 4.1.1 常量的概念
        • 4.1.2 常量的使用
      • 4.2 变量
        • 4.2.1 变量的概念
        • 4.2.2 变量的使用
    • 5. 运算符
      • 5.1 算术运算符
      • 5.2 关系运算符(比较运算符)
      • 5.3 位运算符
      • 5.4 逻辑运算符
      • 5.5 赋值运算符
      • 5.6 条件运算符(三元运算符)
      • 5.7 类型转换运算符
      • 5.8 其他运算符
    • 6. 流量控制
      • 6.1 顺序结构
      • 6.2 分支结构(选择结构)
        • 6.2.1 if语句
        • 6.2.2 if-else语句
        • 6.2.3 if-else if-else语句
        • 6.2.4 嵌套使用
        • 6.2.5 switch语句
      • 6.3 循环结构
        • 6.3.1 while循环
        • 6.3.2 do-while循环
        • 6.3.3 for循环
        • 6.3.4 循环嵌套
        • 6.3.5 continue与break
    • 7. 数组
      • 7.1 数组的概念
      • 7.2 数组的声明
      • 7.3 数组的创建
        • 7.3.1 静态创建数组
        • 7.3.2 动态创建数组
      • 7.4 数组的打印
      • 7.5 数组的排序
        • 7.5.1 选择排序
        • 7.5.2 冒泡排序
        • 7.5.3 快速排序
      • 7.6 Arrays工具
        • 7.6.1 排序方法
        • 7.6.2 toString方法
        • 7.6.3 fill方法
        • 7.6.4 binarySearch二分查找
        • 7.6.5 copyOf和copyOfRange方法
        • 7.6.6 equals和compare方法
        • 7.6.7 数组的数组(二维数组)
    • 8. 方法
      • 8.1 方法的好处
      • 8.2 方法的定义
      • 8.3 方法的调用
      • 8.4 方法返回值
      • 8.5 方法调用和内存结构
      • 8.7 方法参数传递
      • 8.8 方法的重载
      • 8.9 可变参数(不定长参数)
      • 8.10 return的用法
    • 9. 命名规范


1. 前言

  • Java SE是Java平台标准版(Java Platform, Standard Edition)的简称,用于开发和部署桌面、服务器以及嵌入设备和实时环境中的Java应用程序。
  • Java SE包括用于开发Java Web服务的类库,同时,Java SE为Java EEJava Platform, Enterprise Edition)企业版和Java MEJava Platform, Micro Edition)微型版提供了基础。
  • Java SE就是基于JDKJava开发工具包,Java Development Kit)和JREJava运行环境,Java Runtime Environment),包含支持Java Web服务开发的类,并为Java 企业级开发提供基础。

2. 开发环境搭建

2.1 Java开发工具包下载

JDK官网下载

2.2 环境变量配置

  1. 新建一个环境变量JAVA_HOME
变量名:JAVA_HOME
变量值:D:\Program Files\Java\jdk-11

JDK环境配置

  1. 修改Path,加入JAVA_HOME下的bin目录。
变量名:Path
变量值:%JAVA_HOME%\bin

JDK环境配置2

  1. win+R打开cmd(命令提示符,Command Prompt),查看安装的JDK版本。
 java -version

JDK版本信息

2.3 Java程序的运行过程

Java程序的运行过程通常包括编译和执行两个主要阶段。

  1. 编译阶段javac是Java编译器的命令行工具,它用于将Java源代码文件(.java)编译成Java字节码文件(.class)。
javac HelloWorld.java // 编译源代码
  1. 执行阶段:JVM加载字节码文件,解释执行或者将其编译成机器码,并执行。这个阶段需要JVM处于运行状态。
java HelloWorld // 运行程序

代码运行

📌

  1. 设置Java文件编码格式为ANSI,解决中文乱码问题。
  2. Java虚拟机(JVM)是运行Java字节码的虚拟机。JVM的运行流程可以分为几个阶段:加载Loading)、验证Verification)、准备Preparation)、解析Resolution)、初始化Initialization)、使用Using)和卸载Unloading)。JVM类加载机制
  3. JVM运行时,主要通过类加载器Class Loader)、执行引擎Execution Engine)、运行时数据区Runtime Data Area)以及本地库接口Native Interface)协同工作来完成任务。JVM运行流程

3. 数据类型

Java中的数据类型总体可以分为两大类,分别是基本数据类型引用数据类型

3.1 基本数据类型

Java基本类型共有八种,基本类型可以分为三类,字符类型char,布尔类型boolean以及数值类型byteshortintlongfloatdouble。数值类型又可以分为整数类型byteshortintlong和浮点数类型floatdouble
Java中的数值类型不存在无符号的,它们的取值范围是固定的,不会随着机器硬件环境或者操作系统的改变而改变。Java中还存在另外一种基本类型void,它也有对应的包装类 java.lang.Void,用于声明方法不返回任何值。八种基本类型表示范围如下:

大类类型说明长度最小值最大值备注
整数类型byte字节型8位(1字节)-128(-2^7)127(2^7-1)最大数据存储量是255
short短整型16位(2字节)-32768(-2^15)32767(2^15-1)最大数据存储量是65536
int整型32位(4字节)-2,147,483,648(-2^31)2,147,483,647(2^31-1)最大数据存储量是2^32-1
long长整型64位(8字节)-9,223,372,036,854,775,808(-2^63)9,223,372,036,854,775,807(2^63 -1)最大数据存储量是2^64-1,通常以Ll作为后缀来表示长整型字面量,如123L
浮点数类型float单精度32位(4字节)1.4e-453.4028235e38通常以Ff作为后缀来表示浮点数字面量,如3.14F
double双精度64位(8字节)4.9e-3241.7976931348623157e308双精度是默认的浮点数类型,所以通常不需要添加后缀,但如果需要明确指定,可以使用Dd作为后缀,如3.14D
布尔类型boolean布尔型8位(1字节)falsetrue表示逻辑值,只有truefalse两种取值
字符类型char字符型16位(2字节)'\u0000'(即0)'\uffff'(即65,535)存储Unicode码,字符字面量通常用单引号括起来,如'a'

📌

  1. 自动类型转换(隐式转换):小的数据类型向大的数据类型转换(byte—>short—>int—>longchar—>int),或者整数类型转换成浮点数类型,都可以实现自动转换的。
  2. 强制类型转换(显式转换):大的数据类型向小的数据类型转换,或者浮点数类型转换成整数类型,需要使用强制转换。要在转换类型加括号,如果是浮点数转整数,直接去掉小数点,只保留整数(不考虑四舍五入情况)。

3.2 引用数据类型

引用数据类型是Java中的非基本数据类型,它们在内存中通过引用来访问实际的对象。引用数据类型包括类(Class)、接口(Interface)、数组(Array)、枚举(Enum)和注解(Annotation)。

  • :是一种面向对象编程的基本概念,它是具有相同属性和行为的实体的集合或模板。类定义了对象的数据结构,包括对象的属性(变量)和方法(行为)。
  • 接口:接口定义了一个类必须实现的方法,但接口本身不提供这些方法的实现,一个类可以实现多个接口。
  • 数组:数组是一种引用数据类型,用于存储多个相同类型的元素。
  • 枚举:枚举是一种特殊的引用数据类型,用于表示一组命名的常量。
  • 注解:注解是一种用于为程序提供元数据信息的引用数据类型。

对象引用的强度或可达性级别被分为四种,它们由高到低依次为:强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)和虚引用(Phantom Reference)。

  • 强引用:这是最常见的引用类型。当创建一个对象并将其赋值给一个变量时,就创建了一个强引用。只要强引用存在,垃圾回收器(GC)就永远不会回收掉被引用的对象。
  • 软引用:需要通过SoftReference类来实现,对于只有软引用的对象来说,当系统内存足够时,它不会被回收,当系统内存空间不足时,它会被回收。软引用通常用于对内存敏感的程序中,如缓存数据。
  • 弱引用:弱引用需要用WeakReference类来实现,它比软引用生存期更短,对于只有弱引用的对象来说,只要垃圾回收机制一运行,不管JVM内存空间是否足够,总会回收该对象占用的内存。
  • 虚引用:虚引用需要PhantomReference类来实现,它不能单独使用,必须和引用队列(ReferenceQueue)联合使用。虚引用的主要作用是跟踪对象被垃圾回收的状态,无法通过虚引用获取对象实例(get方法总是返回null),存在的唯一目的就是能在这个对象被回收时收到一个系统通知。
级别例子回收时机用途生存时间
强引用Object obj = new Object();从来不会强引用用于表示程序正在使用的对象,如局部变量、实例变量等JVM停止运行时终止
软引用SoftReference a = new SoftReference(new A());在内存不足时联合ReferenceQueue构造有效期短/占内存大/生命周期长的对象的二级高速缓冲器(内存不足时才清空)内存不足时终止
弱引用WeakReference a = new WeakReference(new A());在垃圾回收时联合ReferenceQueue构造有效期短/占内存大/生命周期长的对象的二级高速缓冲器(系统发生GC则清空)GC运行后终止
虚引用PhantomReference a = new PhantomReference(new A(), referenceQueue);在垃圾回收时联合ReferenceQueue来跟踪对象被垃圾回收器回收的活动GC运行后终止

4. 常量与变量

4.1 常量

4.1.1 常量的概念
  • 不可变性:常量的值在初始化后不能被修改。
  • 命名规范:常量名通常使用大写字母,单词之间使用下划线_分隔,以区别变量名,例如PIMAX_VALUE
  • 声明方式:使用final关键字来声明一个常量,并且如果它是静态的(即属于类而不是实例),则还会使用static关键字。
4.1.2 常量的使用
  • 使用final关键字声明常量,并在声明时初始化其值。
  • 对于静态常量,可以通过类名直接访问;对于非静态常量,需要通过对象实例来访问;但由于常量通常设计为不可变的,并且与具体的对象实例无关,因此大多数常量都是静态的。
  • 常量可以是任何数据类型,包括基本数据类型常量、引用类型常量、枚举常量、自定义常量。
  • 在Java接口中,所有字段(即常量)都隐式地是staticfinal的,因此不需要显式声明这两个关键字。
  • 枚举类型enum在Java中经常用做常量,因为它们提供了一种类型安全的方式来表示一组固定的常量值。

4.2 变量

4.2.1 变量的概念

变量是程序里最基本的存储单元,它由数据类型变量名变量值组成。从本质上来说,变量其实就是内存里的一小块存储区域,该区域只能存储声明变量时指定类型的数据。我们创建使用每个变量前,必须先声明,在内存中申请空间,然后对其进行初始化赋值,接着就可以通过变量名来访问和使用这块内存区域了。语法格式如下:

// 先声明,再赋值
数据类型 变量名;
变量名 = 变量值;
// 声明的同时并赋值
数据类型 变量名 = 变量值;
// 同时定义多个类型相同的变量
数据类型 变量名1 = 变量值1,变量名2 = 变量值2,变量名3……;
4.2.2 变量的使用

在使用变量的过程中,还有一些事项需要我们注意:

  • 变量必须要先声明,才能使用;
  • 声明变量时,要指定变量的类型(基本数据类型、引用数据类型);
  • 变量的作用域:其定义所在的一对{}内;
  • 变量只有在其作用域内才有效;
  • 同一个作用域(代码块)中,变量名不能相同;
  • 变量在声明时可以没有值,使用时必须要有值的;
  • JDK 10可以使用var作为局部变量类型推断标识符(Local-Variable Type Inference),仅适用于局部变量,使用var声明时,必须要赋初始值。

5. 运算符

Java运算符主要分为以下几类:算术运算符、关系运算符(比较运算符)、位运算符、逻辑运算符、赋值运算符、条件运算符(三元运算符)、类型转换运算符等。

5.1 算术运算符

  • +:加法(当操作数是字符串时,用作连接符)
  • -:减法
  • *:乘法
  • /:除法
  • %:取余(模运算)
  • ++:自增(自身加1)
  • --:自减(自身减1)

5.2 关系运算符(比较运算符)

所有计算的结果,会返回boolean类型的值。

  • ==:等于
  • !=:不等于
  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于
  • instanceof:判断其左边对象是否为其右边类的实例

5.3 位运算符

  • <<:左移(右边用0填充,即低位补0)
  • >>:右移(有符号,左边用符号位填充,即高位补符号位)
  • >>>:无符号右移(无符号,左边用0填充,即高位补0)
  • &:按位与(两边同是1,才为1,不然为0)
  • |:按位或(两边有一边为1,则结果为1,否则为0)
  • ^:按位异或(两边相同,则结果为0,两边不同,则结果为1)
  • ~:按位非(取反,如果是0,则取值为1,如果是1,则取值为0)

5.4 逻辑运算符

  • &&:逻辑与(短路与)
  • ||:逻辑或(短路或)
  • !:逻辑非

5.5 赋值运算符

  • =:赋值
  • +=:加法赋值
  • -=:减法赋值
  • *=:乘法赋值
  • /=:除法赋值
  • %=:取余赋值
  • <<=:左移赋值
  • >>=:右移赋值
  • >>>=:无符号右移赋值
  • &=:按位与赋值
  • |=:按位或赋值
  • ^=:按位异或赋值

5.6 条件运算符(三元运算符)

  • ?::该运算符有3个操作符,并且需要判断布尔表达式的值,主要是决定哪个值应该赋值给变量。例如:var c = (a > b) ? a : b;

5.7 类型转换运算符

  • (type):强制类型转换,用于显式地将一种类型的值转换为另一种类型。例如:int a = (int) 3.14;

5.8 其他运算符

  • .:成员运算符,用于访问对象的成员(属性和方法)。
  • []:索引运算符,用于访问数组或集合的元素。
  • ():方法调用运算符,用于调用方法。
  • new:实例化运算符,用于创建对象的实例。
  • instanceof:用于测试对象是否是一个类的实例。
  • ->:Lambda运算符(箭头运算符),是Java 8引入的的一个新特性,它分隔了参数列表和Lambda体,用于定义Lambda表达式。
  • :::方法引用运算符,是Java 8引入的一个新特性,用于引用现有方法或构造函数,通常与Lambda表达式一起使用。

6. 流量控制

在Java中,流程控制主要包括顺序、分支(选择)、循环三大结构。

6.1 顺序结构

代码自上而下顺序执行。

6.2 分支结构(选择结构)

使用if-else语句和switch语句实现条件分支。

6.2.1 if语句

语法格式如下:

if (condition) {
    // 条件成立true,执行这里的代码
    // 如果只有一行或一组代码,大括号可以省略
}
6.2.2 if-else语句

语法格式如下:

if (condition) {
    // 条件成立true,执行这里的代码
} else {
    // 必须和对应的if一起出现,不能单独出现
    // 条件不成立false,执行这里的代码
}
6.2.3 if-else if-else语句

语法格式如下:

if (condition1) {  
    // 如果condition1为true,执行这里的代码  
} else if (condition2) {  
    // 如果condition1为false但condition2为true,执行这里的代码  
} else if (condition3) {  
    // 如果前两个条件都为false但condition3为true,执行这里的代码  
    // 可以继续添加更多的else if子句  
} else {  
    // 如果所有条件都为false,执行这里的代码  
}
6.2.4 嵌套使用

if-else语句可以嵌套使用,即一个ifelse语句块内部可以包含另一个完整的if-else语句。这样可以根据多个条件进行更复杂的判断。

6.2.5 switch语句

语法格式如下:

switch (variable) {  
    case value1:  
        // 当variable的值等于value1时执行  
        break;  
    case value2:  
        // 当variable的值等于value2时执行  
        break;  
    // 可以添加更多的case  
    default:  
        // 当variable的值不匹配任何case时执行  
        break;  
}

6.3 循环结构

使用whiledo-whilefor循环。

6.3.1 while循环

当型循环,语法格式如下:

while (condition) {
    // 当条件成立,反复执行这段代码(循环体)
}
6.3.2 do-while循环

直到型循环,先执行一次循环体,后面根据while条件是否为真,如果为真继续执行。语法格式如下:

do {
    // 循环体
} while (condition); // 后面有分号
6.3.3 for循环

语法格式如下:

for (表达式1; 表达式2; 表达式3) {
    // 循环体
}

for循环执行的过程:

  1. 执行表达式1,赋初始值;
  2. 执行表达式2,条件判定(boolean类型值),如果条件不成立,退出循环;
  3. 如果表达式2条件成立,执行循环体;
  4. 执行表达式3,让循环条件变动;
  5. 从第2步开始循环。

for循环的特殊用法:

  • 增强的for循环(for-each循环),用于遍历数组或集合中的元素,而不需要通过索引来访问每个元素。
int[] numbers = {1, 2, 3, 4, 5};  
for (int number : numbers) {  
    System.out.println(number);  
}  
  
List<String> list = Arrays.asList("a", "b", "c");  
for (String item : list) {  
    System.out.println(item);  
}
  • 无限循环,通常用于需要一直运行直到某个条件被外部触发的场景(如服务器监听)。
for (;;) {  
    // 循环体内的代码将无限执行,直到遇到break语句或程序被终止  
}
  • 可以在for循环的初始化部分声明多个变量。
for (int i = 0, j = 10; i < j; i++, j--) { // 如果控制两种不同类型的变量,需要在外面做声明处理
    System.out.println("i: " + i + ", j: " + j);  
}
  • for循环中声明并初始化数组。
int[] numbers = new int[5];  
for (int i = 0; i < numbers.length; i++) {  
    numbers[i] = i * 2;  
}
  • for循环中嵌套switch语句。
for (int i = 0; i < 5; i++) {  
    switch (i) {  
        case 0:  
            System.out.println("Zero");  
            break;  
        case 1:  
            System.out.println("One");  
            break;  
        // ... 其他case  
        default:  
            System.out.println("Default");  
    }  
}
  • for循环中使用Lambda表达式。
List<String> list = Arrays.asList("a", "b", "c", "a", "b");  
list.stream()  
    .filter(item -> !item.equals("a")) // 过滤掉所有"a"  
    .forEach(System.out::println); // 打印剩下的元素
  • 使用for循环进行字符串迭代。
String str = "Hello";  
for (char c : str.toCharArray()) { // toCharArray()方法将字符串转换为字符数组
    System.out.print(c + " ");  
}

快速生成for循环的处理方式:

  • fori从0到指定值循环。
  • 100.fori从0-100循环。
  • 100.forr从100-0循环。

📌

  1. for循环变量的初值,最好在for循环中声明,因为它有助于减少变量的作用域并提高代码的可读性。
  2. 迪米特法则(Law of Demeter,LOD),也称为最少知识原则(Least Knowledge Principle,LKP),是一种面向对象编程(OOP)和面向对象设计(OOD)的原则。通过降低类之间的耦合度、提高内聚性和简化依赖关系,可以创建出更加可维护、可扩展和可复用的软件系统。
6.3.4 循环嵌套

我国传统数学名著《九章算术》记载:今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何?使用循环解决计算鸡兔同笼问题。代码示例如下:

public class ChiRabCage {
    public static void main(String[] args) {
        for (int i = 0; i <= 35; i++) { // 鸡的数量
            for (int j = 1; j <= 35 - i; j++) { // 兔的数量
                if (i * 2 + j * 4 == 94 && i + j == 35) {
                    System.out.println("鸡的数量:" + i + ",兔的数量:" + j);
                }
            }
        }
    }
}

🆚🆚运行结果:

鸡的数量:23,兔的数量:12
6.3.5 continue与break
  • break:退出当前循环,break后面的语句都不执行。
  • continue:结束本次循环,continue后的语句本次不再执行,从循环的下一次开始执行。

7. 数组

7.1 数组的概念

数组(Array)是一种引用数据类型,用于存储相同类型数据的有序集合。数组中的每个元素都有一个唯一的索引,该索引用于访问和修改数组中的元素。数组在内存中占用一段连续的存储空间,因此通过索引访问数组元素的速度非常快。

7.2 数组的声明

数组的声明用于定义数组的类型和名称,但并不会为数组分配内存空间。数组声明的基本语法如下:

int[] array; // 推荐使用
int array[];

7.3 数组的创建

7.3.1 静态创建数组

在声明数组的同时直接指定数组的元素值,也称为字面量初始化。

int[] intArray = {1, 2, 3, 4, 5}; // 静态初始化整数数组  
double[] doubleArray  = {1.2, 3.4, 5.6, 7.8}; // 静态初始化双精度浮点数数组
String[] stringArray = {"apple", "banana", "cherry"}; // 静态初始化字符串数组
7.3.2 动态创建数组

先声明数组变量,然后为其分配内存空间并指定长度,但不立即为数组元素赋值。

// 数组类型[] 数组名 = new 数组类型[长度(数组中存储元素的个数)]
int[] x = new int[3]; // 动态初始化,指定长度为3
x[0] = 1; // 为数组的元素赋值
x[1] = 2;
x[2] = 3;
System.out.println(x[0]);
System.out.println(x[1]);
System.out.println(x[2]);

📌

  1. 数组一旦创建,其长度就不能改变。
  2. 在声明数组变量后,必须对其进行初始化(即分配内存空间)才能使用。
  3. 数组在内存中占用连续的空间,可以通过索引来访问数组中的元素。
  4. 访问数组元素时,索引从0开始,到数组长度减1结束。如果越界访问数组元素,将会抛出ArrayIndexOutOfBoundsException异常。

7.4 数组的打印

可以使用循环来遍历数组并逐个打印元素。代码示例如下:

public class TestPrint {
    public static void main(String[] args) {
        int[] a = {1, 3, 5, 7, 9};
        // 使用增强的for循环(for-each循环)
        for (int i : a) { // a.for
            System.out.print(i + "\t");
        }
        System.out.println();
        // 使用基本for循环
        for (int i = 0; i < a.length; i++) { // 正序
            int x = a[i]; // a.fori
            System.out.print(x + "\t");
        }
        System.out.println();
        for (int i = a.length - 1; i >= 0; i--) { // 倒序
            int x = a[i]; // a.forr
            System.out.print(x + "\t");
        }
    }
}

🆚🆚运行结果:

1	3	5	7	9	
1	3	5	7	9	
9	7	5	3	1

📌

  1. 使用Arrays类的toString方法(适用于所有类型的数组);
  2. 对于更复杂的数组处理或函数式编程风格,可以使用Java 8的Stream API(java.util.stream);
  3. 对于大型数组或需要频繁拼接字符串的情况,使用StringBuilder可以提高性能。

7.5 数组的排序

7.5.1 选择排序

选择排序(Selection Sort)是一种简单直观的排序算法,其基本思想是每一次从待排序的数据元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数据元素排完。选择排序的主要步骤如下:

  1. 初始化:首先,在未排序序列中找到最小(或最大)元素,存放到排序序列的起始位置。
  2. 继续选择:然后,再从剩余未排序元素中继续寻找最小(或最大)元素,然后放到已排序序列的末尾。
  3. 重复执行:重复步骤2,直到所有元素均排序完毕。

选择排序的特点:时间复杂度O(n^2) ,空间复杂度O(1) ,原地排序算法,不需要额外的存储空间,不稳定排序。代码示例如下:

/* 选择排序 */
public class SelectionSort {
    public static void main(String[] args) {
        int[] x = {56, 12, 78, 90, 34};
        for (int i = 0; i < x.length - 1; i++) { // 控制外层循环
            int minIndex = i; // 假设当前位置是最小的
            for (int j = i + 1; j < x.length; j++) { // 在剩余未排序的元素中找最小元素
                if (x[j] < x[minIndex]) { // 如果找到更小的元素,更新最小元素的索引
                    minIndex = j;
                }
            }
            if (minIndex != i) { // 将找到的最小元素与第一个未排序的元素交换位置
                int tmp = x[i];
                x[i] = x[minIndex];
                x[minIndex] = tmp;
            }
            System.out.println("第" + (i + 1) + "轮:");
            for (int a : x) {
                System.out.print(a + "\t");
            }
            System.out.println();
        }
    }
}

🆚🆚运行结果:

1轮:
12	56	78	90	342轮:
12	34	78	90	563轮:
12	34	56	90	784轮:
12	34	56	78	90
7.5.2 冒泡排序

冒泡排序(Bubble Sort)是一种交换排序的算法,其基本思想是两两比较,进行交换位置,得到一个有序的序列。冒泡排序的主要步骤如下:

  1. 比较相邻元素:从列表的第一个元素开始,比较每对相邻的项,如果它们的顺序错误就交换它们。
  2. 遍历数组:在列表的剩余部分(即未排序的部分)中,重复步骤1。
  3. 重复过程:在每次遍历后,数组中最大的元素就像气泡一样“浮”到数组的末尾。然后减少遍历的范围(因为最后一个元素已经是最大的,不需要再比较),并重复步骤1和2,直到没有元素需要交换为止。

冒泡排序的特点:时间复杂度O(n^2) ,空间复杂度O(1) ,原地排序算法,不需要额外的存储空间,稳定排序。代码示例如下:

/* 冒泡排序 */
public class BubbleSort {
    public static void main(String[] args) {
        int[] x = {56, 12, 78, 90, 34};
        for (int i = 0; i < x.length - 1; i++) { // 外循环
            for (int j = 0; j < x.length - i - 1; j++) { // 内循环
                if (x[j] > x[j + 1]) { // 交换值
                    int t = x[j];
                    x[j] = x[j + 1];
                    x[j + 1] = t;
                }
            }
            System.out.println("第" + (i + 1) + "轮:");
            for (int a : x) {
                System.out.print(a + "\t");
            }
            System.out.println();
        }
    }
}

🆚🆚运行结果:

1轮:
12	56	78	34	902轮:
12	56	34	78	903轮:
12	34	56	78	904轮:
12	34	56	78	90
7.5.3 快速排序

快速排序(Quick Sort)是一种非常高效的排序算法,它采用了分治(Divide and Conquer)的策略。快速排序的主要步骤如下:

  1. 选择基准(Pivot):从待排序序列中选取一个元素作为基准,通常选择序列的第一个或最后一个元素。
  2. 分区操作(Partition):将序列分成两个子序列,左边子序列的元素都小于或等于基准,右边子序列的元素都大于基准。
  3. 递归排序(Recursion):递归地对基准元素左右两边的子序列进行快速排序。

快速排序的特点:平均时间复杂度O(n log n) ,最坏时间复杂度O(n^2),平均空间复杂度O(log n) ,最坏空间复杂度O(n),原地排序算法,除了递归栈外不需要额外的存储空间,不稳定排序。代码示例如下:

public class QuickSort1 {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            // 获取分区后的枢纽位置
            int pivotIndex = partition(arr, low, high);
            // 分别对枢纽左右两边的子数组进行递归排序
            quickSort(arr, low, pivotIndex - 1);
            quickSort(arr, pivotIndex + 1, high);
        }
    }

    private static int partition(int[] arr, int low, int high) {
        // 选择数组的最后一个元素作为枢纽值
        int pivot = arr[high];
        int i = (low - 1);
        // 遍历数组,将小于枢纽值的元素放到左边,大于枢纽值的元素放到右边
        for (int j = low; j < high; j++) {
            if (arr[j] < pivot) {
                i++;
                // 交换 arr[i] 和 arr[j]
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        swap(arr, i + 1, high);
        return i + 1;
    }

    // 将基准元素交换到其最终位置
    private static void swap(int[] arr, int i, int j) {
        int temp = arr[i];
        arr[i] = arr[j];
        arr[j] = temp;
    }

    // 返回枢纽位置
    public static void main(String[] args) {
        int[] arr = {56, 12, 78, 90, 34};
        quickSort(arr, 0, arr.length - 1);
        // 输出排序后的数组
        System.out.println(java.util.Arrays.toString(arr));
    }
}
public class QuickSort2 {
    public static void quickSort(int[] arr, int low, int high) {
        if (low < high) {
            // 获取分区后基准元素的位置
            int pivotIndex = partition(arr, low, high);
            // 分别对基准元素左右两边的子数组进行快速排序
            quickSort(arr, low, pivotIndex - 1);
            quickSort(arr, pivotIndex + 1, high);
        }
    }

    private static int partition(int[] arr, int low, int high) {
        // 选择数组的第一个元素作为基准元素
        int pivot = arr[low];
        int i = low + 1;
        int j = high;
        // 进行迭代,直到i和j指向同一个位置
        while (i <= j) {
            // 从右向左找到第一个小于等于基准元素的元素
            while (i <= j && arr[j] > pivot) {
                j--;
            }
            // 从左向右找到第一个大于等于基准元素的元素
            while (i <= j && arr[i] <= pivot) {
                i++;
            }
            // 交换i和j指向的元素
            if (i < j) {
                int temp = arr[i];
                arr[i] = arr[j];
                arr[j] = temp;
            }
        }
        // 将基准元素放到正确的位置
        arr[low] = arr[j];
        arr[j] = pivot;
        // 返回基准元素的位置
        return j;
    }

    public static void main(String[] args) {
        int[] arr = {56, 12, 78, 90, 34};
        quickSort(arr, 0, arr.length - 1);
        System.out.println(java.util.Arrays.toString(arr));
    }
}

🆚🆚运行结果:

[12, 34, 56, 78, 90]

📌
效率:快速排序>选择排序>冒泡排序(冒泡排序在内循环交换,选择排序在外循环交换)

7.6 Arrays工具

7.6.1 排序方法

Arrays.sort()是Java中的数组排序,它是对一个数组的所有元素进行排序,并且是按从小到大的顺序。代码示例如下:

public class QuickSort3 { // 快速排序
    public static void main(String[] args) {
        int[] arr = {56, 12, 78, 90, 34};
        long t1 = System.currentTimeMillis(); // 返回当前时间的毫秒数
        Arrays.sort(arr); // 数组进行排序
        long t2 = System.currentTimeMillis(); // 返回当前时间的毫秒数
        System.out.println(Arrays.toString(arr));
        long t = t2 - t1;
        System.out.println("执行时间:" + t + "毫秒");
    }
}

🆚🆚运行结果:

[12, 34, 56, 78, 90]
执行时间:0毫秒
7.6.2 toString方法

Arrays.toString()用于将数组转换为字符串,可以快速的输出数组的内容。

7.6.3 fill方法

Arrays.fill()对数组元素进行填充。代码示例如下:

public class ArrayTest {
    public static void main(String[] args) {
        int x[] = new int[5];
        x[0] = 29;
        x[3] = 89;
        //起始位包含,结束位置不包含,对数组进行填充
        Arrays.fill(x, 1, 3, 100);
        System.out.println(Arrays.toString(x));
    }
}

🆚🆚运行结果:

[29, 100, 100, 89, 0]
7.6.4 binarySearch二分查找

数组必须经过排序再进行二分查找,返回数组中元素所在的下标位置,如果找不到,返回负值。

public class ArraysBinarySearch {
    public static void main(String[] args) {
        int[] y = {12, 56, 34, 88, 66};
        Arrays.sort(y);
        System.out.println(Arrays.toString(y));
        int n = Arrays.binarySearch(y, 66);
        System.out.println(n);
    }
}

🆚🆚运行结果:

[12, 34, 56, 66, 88]
3
7.6.5 copyOf和copyOfRange方法
public class ArraysTest {
    public static void main(String[] args) {
        int[] x = {66, 33, 44, 55, 11, 22};
        System.out.println(Arrays.toString(x));
        int[] y = Arrays.copyOf(x, 4);
        System.out.println(Arrays.toString(y));
        int[] z = Arrays.copyOfRange(x, 1, 3);
        System.out.println(Arrays.toString(z));
    }
}

🆚🆚运行结果:

[66, 33, 44, 55, 11, 22]
[66, 33, 44, 55]
[33, 44]
7.6.6 equals和compare方法
public class ArraysTest2 {
    public static void main(String[] args) {
        int[] x = {66, 33, 44, 55, 11, 22};
        int[] y = Arrays.copyOf(x, 4);
        System.out.println("x:" + Arrays.toString(x));
        System.out.println("y:" + Arrays.toString(y));
        int[] m = new int[5];
        // 参数1:源数组              参数2:从源数组哪个下标开始复制
        // 参数3:复制到的目标数组      参数4:从目标数组的哪个下标位置开始放入
        // 参数5:复制源数组多长
        System.arraycopy(x, 1, m, 0, 5);
        System.out.println("m:" + Arrays.toString(m));
        boolean b = Arrays.equals(x, y);
        System.out.println("两数组的值是否相同(相同为true,不同为false):" + b);
        int i = Arrays.compare(x, y);
        System.out.println("两数组按字典顺序比较(相同为0,前者大为正,后者大为负):" + i);
    }
}

🆚🆚运行结果:

x:[66, 33, 44, 55, 11, 22]
y:[66, 33, 44, 55]
m:[33, 44, 55, 11, 22]
两数组的值是否相同(相同为true,不同为false):false
两数组按字典顺序比较(相同为0,前者大为正,后者大为负):2
7.6.7 数组的数组(二维数组)

在Java中,二维数组被看作数组的数组,即二维数组为一个特殊的一维数组,其每个元素又是一个一维数组。Java并不直接支持二维数组,但是允许定义数组元素是一维数组的一维数组,以达到同样的效果。代码示例如下:

public class ArraysTest3 {
    public static void main(String[] args) {
        // 静态创建二维数组 数组的长度和元素都有
        int[][] a = {{12, 34}, {21, 43, 54}, {12, 53, 76}, {21, 54}};
        int[][] b = {{16, 34, 34}, {87, 96, 66}};
        // 动态创建二维数组
        int[][] c = new int[3][];
        int[] arr0 = {12, 34};
        int[] arr1 = {21, 43, 54};
        int[] arr2 = {12, 53, 76};
        c[0] = arr0;
        c[1] = arr1;
        c[2] = arr2;
        for (int[] x : c) {
            for (int y : x) {
                System.out.print(y + "\t");
            }
            System.out.println();
        }
        for (int i = 0; i < c.length; i++) {
            for (int j = 0; j < c[i].length; j++) {
                System.out.print(c[i][j] + "\t");
            }
        }
    }
}

🆚🆚运行结果:

12	34	
21	43	54	
12	53	76	
12	34	21	43	54	12	53	76

8. 方法

在Java中,方法(函数)是代码组织的基本单位,方法封装了一段特定的代码,这段代码执行某个特定的任务或操作。

8.1 方法的好处

  • 实现对相同代码的复用
    • 将重复的代码段封装成方法,就可以在整个程序中的任何位置调用它,而无需重复编写相同的代码。可以提高代码的复用性、可维护性和可读性。
  • 使程序逻辑清晰
    • 通过将程序逻辑分解为多个小方法,我们可以更容易地理解每个部分的职责和工作原理,从而使整个程序的结构更加清晰。
  • 实现细粒度设计
    • 细粒度设计是一种将程序拆分成多个小模块或组件的方法,每个模块或组件都具有明确的功能和接口。方法是实现细粒度设计的基本单元之一。
    • 细粒度设计还有助于提高代码的可测试性。由于每个方法都具有明确的输入和输出,我们可以更容易地为它们编写单元测试,以确保它们按预期工作。这有助于我们在开发过程中发现并修复错误,提高代码的质量和可靠性。

8.2 方法的定义

方法头(方法签名或方法声明)由五个部分组成。方法定义的语法格式如下:

[访问修饰符] <返回值类型> <方法名>([参数列表]) [异常列表] {
    // 方法体
    [return 语句(如果返回值类型不是void)];]
}
// 使用中括号[]包括的部分是可选项,使用尖角号<>包括的部分是必填项。

8.3 方法的调用

定义了一个方法之后,这个方法本身不会自动运行。它必须被另一个方法(通常是main方法或其他非静态方法)显式地调用才能执行。方法调用的基本语法如下:

方法名(参数1, 参数2, ..., 参数N);

调用一个方法时,需要遵循以下规则:

  • 方法名:必须使用定义该方法时所用的确切名称来调用它。
  • 参数列表:如果方法需要参数,必须在调用时提供与定义时相匹配的参数。这包括参数的个数、类型和顺序。如果参数类型不匹配,或者参数的个数不正确,编译器将报错。
  • 实参(Actual Parameters):当调用一个方法并传递参数时,提供的具体值被称为实参。这些实参将被用于方法内部的计算或操作。

8.4 方法返回值

  • 返回值类型不是void:对于返回值类型不是void的方法,必须确保方法体内有一个与返回值类型相匹配的return语句来返回一个值。
  • 返回值类型是void:对于返回值类型是void的方法,return语句后面不需要跟任何表达式,但可以用来提前结束方法的执行。

8.5 方法调用和内存结构

  • 方法的存放位置
    • 在Java程序的源代码中,方法被定义在类中。
    • 当Java程序被编译后,方法的字节码被存储在.class文件中。
    • 当Java虚拟机(JVM)加载.class文件时,它会把类的信息(包括方法)加载到方法区(Method Area)中,也被称为永久代(PermGen,在Java 8之前)或元空间(Metaspace,在Java 8及以后)。方法区方法的调用和执行存储了类的元数据,包括方法信息、常量池等。
  • 方法的调用和执行
    • 当一个方法被调用时(无论是从主方法、其他方法还是通过事件等),JVM会在Java栈(Java Stack)中为该方法的执行创建一个新的栈帧(Stack Frame)。
    • 栈帧包含了方法的局部变量、操作数栈、指向当前方法所属类的常量池的引用等信息。
    • 方法在栈帧中执行,执行过程中可能会涉及到操作局部变量、调用其他方法等操作。
    • 如果方法A调用了方法B,而方法B又调用了方法A(没有合适的终止条件),这会导致无限递归,最终会因为栈空间耗尽而抛出StackOverflowError
  • 栈溢出和递归
    • 栈溢出(StackOverflowError)通常是由于递归调用过深、方法调用过多导致栈空间耗尽而引发的。
    • 在编写递归方法时,需要特别注意递归的终止条件,以确保递归调用能够正常结束。

8.7 方法参数传递

在Java中,方法参数的传递是通过值传递(pass-by-value)进行的。

  1. 基本数据类型传递:传递的是参数值的副本,在方法内部对参数值的修改不会影响原始变量。
  2. 引用数据类型传递:传递的是该对象在内存中的引用地址的副本,而不是对象本身。

8.8 方法的重载

方法的重载(Overloading)是指在同一个类中,使用相同的方法名,定义多个不同方法的机制。方法的重载有以下几个要点:

  1. 方法名必须相同。
  2. 参数列表必须不同(参数的类型、参数的个数或参数的顺序不同)。
  3. 返回类型可以相同,也可以不相同(返回类型不参与重载)。
  4. 访问修饰符和异常类型可以相同,也可以不相同(访问修饰符和异常类型不参与重载)。

8.9 可变参数(不定长参数)

可变参数(Varargs,即Variable-length Arguments)是一个允许在调用方法时传入任意数量参数的特性。这种特性使得方法可以接受可变数量的参数,而不需要为每种可能的参数数量重载方法。以下是可变参数定义的语法格式:

returnType methodName(type... parameters) {  
    // 方法体  
}

可变参数的规则如下:

  1. 如果方法中,有可变参数,还有其他参数,可变参数必须是最后出现,并且只能有一个可变参数。
  2. 可变参数是兼容数组类型参数的,但是数组类型参数不兼容可变参数。
  3. 能匹配定长的方法时,优先匹配定长方法,不定参数的方法是最后被选择的。
  4. 可变参数方法和数组方法不能重载。

8.10 return的用法

return语句的两种主要用法:

  • 在有返回值的方法中,返回方法指定类型的值,同时结束方法执行。
  • 在返回值为void的方法中,用来结束当前方法,回到主调方法,后面的语句都不会再执行。

9. 命名规范

Java中的命名规则主要包括以下几点:

  • 包名:全部小写,用点分隔符.来分隔各级目录,通常为反域名命名法,例如com.example.mypackage
  • 类和接口名:每个单词的首字母都大写(大驼峰式命名法,又称Pascal命名法),例如MyClassIMyInterface
  • 对象名:首字母小写,遇到单词就大写(小驼峰式命名法,又称camelCase命名法),例如objectmyObjectName
  • 方法名:首字母小写,遇到单词就大写(小驼峰),例如myMethod()getNumber()
  • 变量名:首字母小写,遇到单词就大写(小驼峰),例如summyVariable
  • 常量名:全部大写,单词间用下划线_分隔,例如PIMAX_VALUE

✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨

以上内容是关于Java基本语法的基础知识,希望对初学者或再次学习者有所帮助,基础打扎实,不怕风吹雨打!如果以上内容有错误或者内容不全,望大家提出!我也会继续写好每一篇博文!
👍👍👍

待续未完
🙊🙊🙊

欢迎观看和提问!!!
👏👏👏

下一篇:Java基础:面向对象(二)
赞

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

晓语台:基于大语言模型和深度学习技术的智能创作平台,高效、个性化地创作高质量内容。

晓语台 AI&#xff1a; 晓语台是由北京字里心间科技有限公司推出的一款智能AI写作工具。它基于百度的大语言模型和混合大模型以及AIGC技术研发而成&#xff0c;内置了多种风格和主题的AI创作模板&#xff0c;覆盖了20余类行业与职业&#xff0c;近30个海内外社交平台&#xff…

代码随想录——合并二叉树(Leetcode617)

题目链接 层序遍历 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, TreeNode left, TreeNode right) …

20240529代码沉思--------聊聊清单革命

以下内容取自百度&#xff1a; 清单革命 清单革命是一场观念革命&#xff0c;旨在通过列出清晰、明确的清单来避免犯错和提高效率。以下是关于清单革命的一些核心观点和原则&#xff1a; 核心观点&#xff1a; 人类的错误主要分为两类&#xff1a;“无知之错”和“无能之错…

java配置文件解析yml/xml/properties文件

XML 以mybatis.xml:获取所有Environment中的数据库并连接session为例 import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException;import javax.xml.parsers.DocumentBuilder; impo…

【软件设计师】网络与多媒体基础知识

1.多媒体网络 JPEG累进&#xff08;或增量、渐进、递增&#xff09;编码模式&#xff0c;实现图像内容的方式传输&#xff0c;在浏览器上的直观效果就是无需过久等待即可看到模糊图像&#xff0c;然后图像显示和内容由模糊逐渐变得清晰 GIF图像文件格式以数据块为单位来存储图像…

前端路由 Hash 模式和 History 模式

在SPA单页面模式盛行&#xff0c;前后端分离的背景下&#xff0c;我们要弄清楚路由到底是个什么玩意&#xff0c;它可以帮助我们加深对于前端项目线上运作的理解。 而现在我们常见的路由实现方式&#xff0c;主要有两种&#xff0c;分别是history和hash模式。 理解 如何理解路…

uart_tty_驱动程序框架

UART子系统(四) TTY驱动程序框架_tty驱动框架-CSDN博客

【网络层】ICMP 因特网控制协议

文章目录 ICMP 含义以及作用ICMP协议解析结合ICMP协议和ping常见问题 ICMP 含义以及作用 ICMP&#xff1a;Internet control massage protocol 因特网控制协议 Internet控制报文协议ICMP是网络层的一个重要协议。 ICMP协议用来在网络设备间传递各种差错和控制信息&#xff0c;…

【优选算法】分治 {三分快排:三指针优化,随机选key,快速选择算法;归并排序:统计数组中的逆序对,统计数组中的翻转对;相关编程题解析}

一、经验总结 1.1 三分快排 优化一&#xff1a;三指针优化 之前学习的快速排序无法妥善处理相等或重复序列的排序问题&#xff08;有序且三数取中无效&#xff09;&#xff0c;使快速排序的效率无法达到最优。 为了解决重复序列的问题&#xff0c;我们将原先的双指针法&…

java项目之智能家居系统源码(springboot+vue+mysql)

风定落花生&#xff0c;歌声逐流水&#xff0c;大家好我是风歌&#xff0c;混迹在java圈的辛苦码农。今天要和大家聊的是一款基于springboot的智能家居系统。项目源码以及部署相关请联系风歌&#xff0c;文末附上联系信息 。 项目简介&#xff1a; 基于Springboot的智能家居系…

Redis:redis基础

Redis Remote Dictionary Service即远程字典服务 一个基于内存的key-value结构数据库,在开发中常常作为缓存存储不经常被改变的数据 基于内存存储,读写性能高 在企业中应用广泛 Redis介绍 用C语言开发的开源高性能键值对数据库,可以达到10w的qps,可以存储丰富的value类型…

IDEA中各种Maven相关问题(文件飘红、下载依赖和启动报错)

错误情况 包名、类名显示红色、红色波浪线&#xff0c;大量依赖提示不存在&#xff08;程序包xxx不存在&#xff09; 工程无法启动 一、前提条件 1、使用英文原版IDEA 汉化版的可能有各种奇怪的问题。建议用IDEA英文版&#xff0c;卸载重装。 2、下载maven&#xff0c;配置环…

评测 香橙派OrangePi在智能交通上的应用

1、OrangePi应用场景 关于 Orange Pi AI Pro 开发板是香橙派联合华为精心打造的高性能 AI 开发板&#xff0c;其搭载了昇腾 AI 处理器&#xff0c;可提供 8TOPS INT8 的计算能力&#xff0c;内存提供了 8GB 和 16GB两种版本。可以实现图像、视频等多种数据分析与推理计算&#…

12-常用类

1. 包装类 针对八种基本数据类型封装的相应的引用类型。 有了类的特点&#xff0c;就可以调用类中的方法。&#xff08;为什么要封装&#xff09; 基本数据类型包装类booleanBooleanchar CharacterbyteByteshortShortintIntegerlongLongfloatFloatdoubleDouble 1.1 …

seRsync + Rsync 实时同步

1&#xff0c;结构图 2&#xff0c;节点A 2.1 安装rsync yum install -y rsync2.2 安装seRsync 下载这个压缩包sersync2.5.4_64bit_binary_stable_final.tar.gz 解压后&#xff0c;将sersync2复制到系统可执行程序路径&#xff1a;/usr/local/bin/&#xff1b;创建sersync配…

Visual Studio 的使用

目录 1. 引言 2. 安装和配置 2.1 系统要求 2.2 安装步骤 2.3 初次配置 3. 界面介绍 3.1 菜单栏和工具栏 3.2 解决方案资源管理器 3.3 编辑器窗口 3.4 输出窗口 3.5 错误列表 3.6 属性窗口 4. 项目管理 4.1 创建新项目 4.2 导入现有项目 4.3 项目属性配置 5. 代…

SpringSecurity6从入门到实战之SpringSecurity快速入门

SpringSecurity6从入门到实战之SpringSecurity快速入门 环境准备 依赖版本号springsecurity6.0.8springboot3.0.12JDK17 这里尽量与我依赖一致,免得在学习过程中出现位置的bug等 创建工程 这里直接选择springboot初始化快速搭建工程,导入对应的jdk17进行创建 直接勾选一个web…

QtCreator调试运行工程报错,无法找到相关库的的解决方案

最新在使用国产化平台做qt应用开发时&#xff0c;总是遇到qtcreator内调试运行 找不到动态库的问题&#xff0c;为什么会出现这种问题呢&#xff1f;明明编译的时候能够正常通过&#xff0c;运行或者调试的时候找不到相关的库呢&#xff1f;先说结论&#xff0c;排除库本身的问…

计算机网络7——网络安全1 概述与加密

文章目录 一、网络安全问题概述1、计算机网络面临的安全性威胁2、安全的计算机网络3、数据加密模型 二、两类密码体制1、对称密钥密码体制2、公钥密码体制 随着计算机网络的发展&#xff0c;网络中的安全问题也日趋严重。当网络的用户来自社会各个阶层与部门时&#xff0c;大量…

Raven2掠夺者2渡鸦2账号怎么验证 注册怎么验证账号教程

《渡鸦2》作为韩国孕育的次世代MMORPG手游巨制&#xff0c;是《Raven》系列辉煌传奇的最新篇章&#xff0c;它在暗黑奇幻的广袤天地间再度挥洒创意&#xff0c;深度融合前所未有的游戏机制与海量新颖内容&#xff0c;为该类型游戏树立了崭新的里程碑。公测日期锁定在2024年5月2…