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.forSystem.out.print(i + "\t");}System.out.println();// 使用基本for循环for (int i = 0; i < a.length; i++) { // 正序int x = a[i]; // a.foriSystem.out.print(x + "\t");}System.out.println();for (int i = a.length - 1; i >= 0; i--) { // 倒序int x = a[i]; // a.forrSystem.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基础:面向对象(二)
赞

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

maven部署到私服

方法一:网页上传 1、账号登录 用户名/密码 2、地址 http://自己的ip:自己的端口/nexus 3、查看Repositories列表&#xff0c;选择Public Repositories&#xff0c;确定待上传jar包不在私服中 4、选择3rd party仓库&#xff0c;点击Artifact Upload页签 5、GAV Definition选…

SQL面试题练习 —— 连续登录超过N天用户(一)

题目 现有用户登录日志表 t_login_log,包含用户ID(user_id),登录日期(login_date)。数据已经按照用户日期去重&#xff0c;请查出连续登录超过4天的用户ID。 样例数据 样例输出 建表语句 CREATE TABLE t_login_log (user_id VARCHAR(255) COMMENT 用户ID,login_date DATE CO…

08.tomcat多实例

在加两个tomcat实例 [rootweb01 ~]# ll apache-tomcat-8.0.27.tar.gz -rw-r--r-- 1 root root 9128610 10月 5 2015 apache-tomcat-8.0.27.tar.gz [rootweb01 ~]# tar xf apache-tomcat-8.0.27.tar.gz [rootweb01 ~]# cp -a apache-tomcat-8.0.27 tomcat_8081 [rootweb01 ~…

大模型中的Tokenizer

在使用GPT 、BERT模型输入词语常常会先进行tokenize 。 tokenize的目标是把输入的文本流&#xff0c;切分成一个个子串&#xff0c;每个子串相对有完整的语义&#xff0c;便于学习embedding表达和后续模型的使用。 一、粒度 三种粒度&#xff1a;word/subword/char word词&a…

qt把虚拟键盘部署到arm开发板上(imx6ull)

分为了qt官方配置的虚拟键盘以及各路大神自己开源的第三方键盘&#xff0c;我本来想尝试利用官方键盘结果一直失败&#xff0c;最后放弃了&#xff0c;后面我用的第三方键盘参考了如下文章&#xff1a; https://blog.csdn.net/2301_76250105/article/details/136441243 https…

代码随想录——找树左下角的值(Leetcode513)

题目链接 层序遍历 思路&#xff1a;使用层序遍历&#xff0c;记录每一行 i 0 的元素&#xff0c;就可以找到树左下角的值 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}*…

深入理解深度学习中的激活层:Sigmoid和Softmax作为非终结层的应用

深入理解深度学习中的激活层&#xff1a;Sigmoid和Softmax作为非终结层的应用Sigmoid 和 Softmax 激活函数简介Sigmoid函数Softmax函数 Sigmoid 和 Softmax 作为非终结层多任务学习特征变换增加网络的非线性实际案例 注意事项结论 深入理解深度学习中的激活层&#xff1a;Sigmo…

使用Ollama和Open WebUI管理本地开源大模型的完整指南

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f916;AI大模型部署与应用专栏&#xff1a;点击&#xff01; ⏰️创作时间&#xff1a;2024年5月27日12点20分 &#x1f004;️文章质量&#xff1a;96分 目录 ✨️Open-WebUI介绍 优点 &#x1f4a5;部署教程…

软件需求分析和软件原型开发是一会事情吗?

软件需求分析和软件原型开发是软件开发过程中的两个重要环节&#xff0c;它们各自承担着不同的任务&#xff0c;但又紧密相连&#xff0c;共同影响着软件项目的成功。下面将详细解释这两个环节的定义、目的以及它们之间的关系。 一、软件需求分析 定义&#xff1a;软件需求分析…

JAVA系列:NIO

NIO学习 一、前言 先来看一下NIO的工作流程图&#xff1a; NIO三大核心组件&#xff0c;channel&#xff08;通道&#xff09;、Buffer&#xff08;缓冲区&#xff09;、selector&#xff08;选择器&#xff09;。NIO利用的是多路复用模型&#xff0c;一个线程处理多个IO的读…

学习笔记——STM32F103的V3版本——3*3矩阵键盘控制数码管

一.硬件 1.数码管 2.3*3的矩阵键盘&#xff08;自己做的模块&#xff08;手残党一枚&#xff09;&#xff09; 3.总体连接 二.在Keil5中的部分软代码 test.c中&#xff1a; #include "sys.h" #include "usart.h" #include "delay.h" #include …

面试问题小结

说说你的项目&#xff0c;从里面学到啥了&#xff08;随便说&#xff09; CAS 线程池 的各个方面 线程咋创建&#xff08;4种方式&#xff09; 说一下聚集索引和非聚集索引 50w男 50w女 &#xff0c;在B树中咋存储的&#xff08;类似下面的图&#xff0c;变通一下就行了&a…

DOS学习-目录与文件应用操作经典案例-type

新书上架~&#x1f447;全国包邮奥~ python实用小工具开发教程http://pythontoolsteach.com/3 欢迎关注我&#x1f446;&#xff0c;收藏下次不迷路┗|&#xff40;O′|┛ 嗷~~ 目录 一.前言 二.使用 三.案例 1. 查看文本文件内容 2. 同时查看多个文本文件内容 3. 合并文…

股票量化交易上手,一个特别简单却长期可用的交易策略,官方接口

股票实现程序化自动化交易的三个基础&#xff1a;获取数据、执行交易、查询账户。 以后说到策略示例的时候就不介绍接口的基础使用方法了&#xff0c;随便一个策略把过程写出来都会很啰嗦&#xff0c;尽量压缩内容吧&#xff0c;这些内容是面向新手的&#xff0c;大佬们忽略细节…

为WPF的Grid添加网格边框线

在WPF中使用Grid绘制表格的时候&#xff0c;如果元素较多、排列复杂的话&#xff0c;界面会看起来很糟糕&#xff0c;没有层次&#xff0c;这时用网格或边框线分割各元素&#xff08;标签或单元格&#xff09;将会是页面看起来整齐有条理。 默认没有边框线的如下图所示&#xf…

Rviz 复选框插件

Rviz 复选框插件 0.引言1.实现效果 0.引言 参考1参考2参考3参考4 我想做的插件是类似于 pangolin 侧面的复选框&#xff0c;动态传递 bool 值给程序内部使用。查了一下只能是通过插件的方式进行实现。但是Display 的参数在编译阶段就写死了&#xff0c;我想要在运行期给定参数…

hadoop hdfs优势和缺点

hdfs优点 高容错性适合处理大数据可构建再廉价的机器上 hdfs缺点 不适合做低延迟数据访问 毫秒级的存储数据做不到 无法高效的对大量小文件进行存储不支持并发写入 文件随机修改 一个文件只能有一个writer 不允许多个线程同时写仅支持数据追加 不支持文件的随机修改 hdf…

四川汇聚荣聚荣科技有限公司好不好?

在当今科技飞速发展的时代&#xff0c;企业要想在激烈的市场竞争中脱颖而出&#xff0c;必须具备强大的技术实力和良好的市场口碑。那么&#xff0c;作为一家专注于科技创新的公司&#xff0c;四川汇聚荣聚荣科技有限公司究竟如何呢?接下来&#xff0c;我们将从四个方面进行详…

Nginx的配置与调试

目录 1、安装Nginx 2、Nginx的配置文件结构 2.1 Nginx的全局配置 2.2 HTTP服务器配置 2.3 HttpGzip模块配置 2.4 负载均衡配置 2.5 server虚拟主机配置 2.6 location URL匹配配置 2.7 StubStatus模块配置 1、安装Nginx 在安装Nginx之前&#xff0c;需确保系统已经安装…

C++数据结构之:链List

摘要&#xff1a; it人员无论是使用哪种高级语言开发东东&#xff0c;想要更高效有层次的开发程序的话都躲不开三件套&#xff1a;数据结构&#xff0c;算法和设计模式。数据结构是相互之间存在一种或多种特定关系的数据元素的集合&#xff0c;即带“结构”的数据元素的集合&am…