惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

WordPress大学
WordPress大学
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Hacker News: Ask HN
Hacker News: Ask HN
N
News and Events Feed by Topic
Forbes - Security
Forbes - Security
The Last Watchdog
The Last Watchdog
TaoSecurity Blog
TaoSecurity Blog
Schneier on Security
Schneier on Security
SecWiki News
SecWiki News
V
Vulnerabilities – Threatpost
Project Zero
Project Zero
O
OpenAI News
W
WeLiveSecurity
Security Archives - TechRepublic
Security Archives - TechRepublic
Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
H
Hacker News: Front Page
Cisco Talos Blog
Cisco Talos Blog
Spread Privacy
Spread Privacy
Help Net Security
Help Net Security
P
Privacy & Cybersecurity Law Blog
K
Kaspersky official blog
S
Security @ Cisco Blogs
Latest news
Latest news
AWS News Blog
AWS News Blog
U
Unit 42
Martin Fowler
Martin Fowler
阮一峰的网络日志
阮一峰的网络日志
S
Secure Thoughts
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Know Your Adversary
Know Your Adversary
Scott Helme
Scott Helme
博客园 - 司徒正美
B
Blog RSS Feed
C
Check Point Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
D
Docker
Google Online Security Blog
Google Online Security Blog
Jina AI
Jina AI
aimingoo的专栏
aimingoo的专栏
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Last Week in AI
Last Week in AI
月光博客
月光博客
C
CXSECURITY Database RSS Feed - CXSecurity.com
S
SegmentFault 最新的问题
NISL@THU
NISL@THU
T
The Blog of Author Tim Ferriss
C
Cisco Blogs
Attack and Defense Labs
Attack and Defense Labs
小众软件
小众软件

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12) Snack JSONPath 项目架构分析 Claude Code Buddy 小析:一个非核心功能,如何体现产品的细节完成度 AI新时代下的图床管理方案-Cloudflare图床+MCP+Skills方案指南 化繁为简:顺丰速运App如何通过 HarmonyOS SDK实现专业级空间测量 从零实现富文本编辑器#13-React非编辑节点的内容渲染 AI开发-python-langchain框架(3-23-OpenAI Functions风格Tool Calling智能助手) .NET + AI 进阶实战:基于类的技能开发 - 打造可治理的 Agent 能力模块 【从0到1构建一个ClaudeAgent】规划与协调-技能 上周热点回顾(4.6-4.12) 电子小白的工具三件套:面包板、杜邦线、万能板 单表五亿数据的查询优化 | Mysql、StarRocks 2. WorkBuddy:从“我是谁”到“帮我干活” C# 如何减少代码运行时间:7 个实战技巧 基于HelixToolkit.SharpDX 渲染3D模型 - 笺上知微 从零开始的双臂具身VLA起源及现阶段发展综述 - SkyXZ 记对 xonsh shell 的使用, 脚本编写, 迁移及调优 - pluvium27 受够了Vibe Coding的失控?换个起点,让AI事半功倍 从开始配置漏洞环境到漏洞复现流程 - 難しい 关于10年工作经验的程序员对OpenClaw的实战经验分享以及看法 - 虚无境 Any metadata 的内存布局 C# .NET 周刊|2026年3月2期 - InCerry 我帮你测过了,测试圈排名第二的 Skill 依然很牛逼 Skill Discovery | 无监督技能发现的经典工作总结 - MoonOut PbootCMS 网站内容数量多导致访问慢?这些实用优化方案帮你提速! - 家兴网络技术工作室 上下文工程是什么?过时了么?一文讲明白! - 一枫说码 网站漏洞怎么发现并修复?一篇实用指南(附完整流程) - 家兴网络技术工作室 开了 TUN 模式还是直连?90% 的人都踩过这个坑 Github日报|2026年04月12日 - AI一族 AScript扩展多种脚本语言 - rockey627 AI 学习笔记:Agent 的记忆机制 你能被装进一个文件里吗?——7 万人把同事"蒸馏"成了 AI - 我没有三颗心脏 Claude Code 通关手册(七):给 AI 装上技能包——Skills 完全指南 - 暮色之狐 在浏览器中快速编辑代码:VSCode Web 集成实践 - Newbe36524 蒸馏自己 skill?基于 Deepseek 的蒸馏器,丐版蒸馏方式,简单便捷 - To_Carpe_Diem Spring AI Aliababa和AgentScope,哪个更好? - 苏三说技术 Etsy 把 1000 个 MySQL 分片迁进 Vitess:425TB 数据背后的真正问题不是性能,而是运维规模 MicroPython LVGL基础知识和概念:底层渲染与性能优化 - FreakStudio 数据库草图算法 Python 潮流周刊#146:CPython 引入 Rust 的进展 - 豌豆花下猫 最小生成树 - mofei1116 红日靶场七:从外网入口、容器逃逸到 AD 接管的完整利用链复盘 - YouDiscovered1t 分享四款开源且实用的 Kafka 管理工具 - 追逐时光者 vLLM 权重加载机制全解析:从挑战到理想架构 LCT 学习笔记 - ACehomoxue Avalonia UI 12.0.0 正式发布:架构演进和性能飞跃 - 张善友 当 AI Agent 把调用链拉长,延迟开始成为一门生意 conhost.exe 无法显示 U+2717 - 145a 太秀了,我把自己蒸馏成了 Skill!已开源 - 程序员鱼皮 ASP.NET Core 内存缓存实战:一篇搞懂该怎么配、怎么避坑 基于 Ghostty 带有分割标签页和为 Claude 编程设计的通知终端 - BugShare AI 焊死入口:教育的“操作系统级”重塑 - 郝hai 初级Java开发工程师使用sql脚本编写代码的过程是简单而且不糊涂 - CoderOilStation Claude Code通关手册(六):MCP协议完全指南 - 暮色之狐 边框灯光环绕动画特效实现指南 - Newbe36524 开源:子木蒸馏版的 SEO 审计工具 seo-audit-skill v1.0 我所理解的Python元模型 【从0到1构建一个ClaudeAgent】规划与协调-TodoWrite - 程序员Seven Claude 和 Codex 在审计 Skill 上性能差异探究 - ACai_sec AScript如何实现中文脚本引擎 - rockey627 【渗透测试】HTB Season10 Garfield 全过程wp - dynasty_chenzi Android 开发者为什么必须掌握 AI 能力?端侧视角下的技术变革 树状数组正确性证明 - AC-wyr 你的 AI 焦虑,可能比 AI 本身更危险——ATM 机没有消灭银行柜员,但恐慌消灭了你的判断力 - 我没有三颗心脏 一个拉胯的分库分表方案有多绝望?整个部门都在救火! - 冰河团队 动态规划入门必学之走方格问题 - Ofnoname PostgREST 与 PostgreSQL 角色权限配置全解析(生产级实践) - SheepDog1998 使用 UEFI 图形输出协议 GOP 在屏幕上显示图像的方法 - 阿源- Claude Code通关手册(五):组建你的AI专家团队,子代理系统 - 暮色之狐 一个程序员到架构师的催婚路之感悟(整整10年后的催婚相亲感悟) - MisterLip 用 Agent Skill 自动生成工作周报 - 赵康
OOP2:数组
Fish4174 · 2026-05-13 · via 博客园_首页

OOP2:数组

总结了定义数组的方式、访问数组元素和数组长度的方法、用 for 循环遍历数组的方式、数组作为方法参数和方法返回值的用法、数组作为成员变量如何构造、如何复制数组、如何对数组进行排序和查找、Arrays 类和二维数组的相关知识点。

一、数组的定义

使用数组一般需要两个步骤:①声明数组:向编译器声明数组名称和元素的数据类型。②创建数组:为数组元素分配存储空间。

1. 声明数组

java 语言的数组是一种引用数据类型,即数组是对象,而数组名就是对象名(或引用名,即对象的引用,是一个引用变量)。数组的声明实际上是声明一个引用变量,形如:

元素类型 []数组名;
元素类型 数组名[];
元素类型[] 数组名;//三种形式等价,推荐用第一种

下面代码声明了两个数组:

double []marks;
Account []accounts;

数组元素类型可以是基本数据类型(如 int 或 double 类型),也可以是引用数据类型(如 String 或 Account 类型)。如果数组元素为引用类型,则该数组称为对象数组。上面的 accounts 就是对象数组。声明数组不能指定数组元素的个数

2. 创建数组

声明数组仅仅声明一个数组对象的引用,而创建数组才会为数组的每个元素分配存储空间。创建数组用 new 运算符,形如:

数组名 = new 元素类型[size];//size 指定大小

下面代码创建了 marks 数组和 accounts 数组:

marks = new double[5];
accounts = new Account[3];

Java 数组可以动态创建,也就是它的大小可以在运行时指定,可以以变量作为数组的大小

数组的声明与创建可以写在一个语句中,如下所示:

double[] marks = new double[5];
Account[] accounts = new Account[3];

创建数组时会为每个元素指定默认值,对于引用类型数组(对象数组),它的每个元素初值为 null ,因此,还需要创建数组元素对象。

accounts[0] = new Account(101, "Fish Yu", 3000.0);
accounts[1] = new Account(102, "Tina Wang", 5000.0);
accounts[2] = new Account(103, "Tear", 8000.0);

也可以用下面这种形式完成对象数组的声明-创建-初始化:

Account[] accounts = new Account[]
{
	new Account(101, "Fish Yu", 3000.0);
	new Account(102, "Tina Wang", 5000.0);
	new Account(103, "Tear", 8000.0);
}

3. 数组初始化器

初始化器是在一对花括号中给出数组的每个元素值,这种方式称为静态初始化。用这种方法创建数组不能指定大小,系统会根据元素个数确定数组大小。如下所示:

double[] marks = {11, 45, 14, 1919, 810};
Account[] accounts = {new Account(101, "Fish Yu", 3000.0), new Account(102, "Tina Wang", 5000.0), new Account(103, "Tear", 8000.0)};

可以用 var 类型推断符声明数组,减少代码冗余:

var marks = {11, 45, 14, 1919, 810};
var accounts = {new Account(101, "Fish Yu", 3000.0), new Account(102, "Tina Wang", 5000.0), new Account(103, "Tear", 8000.0)};

“声明-创建-初始化”的多种形式

下面两种”声明-创建“写法均合法:

double[] marks = new double[5];
var marks = new double[5];

下面三种”声明-创建-初始化“写法均合法:

double[] marks = {11, 45, 14, 1919, 810};
double[] marks = new double[]{11, 45, 14, 1919, 810};
var marks = new double[]{11, 45, 14, 1919, 810};

下面的写法不合法,因为没有充分的依据进行类型推断:

var marks = {11, 45, 14, 1919, 810};

二、访问数组

1. 访问数组元素

数组元素的使用方式如下:

数组名[下标]

数组元素下标从0开始,到数组长度减1。数组一经创建,大小不能改变。Java 运行时会对数组元素的范围进行越界检查,若数组元素的下标超出范围,会抛出 ArrayIndexOutOfBoundsException 运行时异常。

2. 访问数组长度

数组作为对象提供一个 length 成员变量,它的值是数组元素的个数,访问方法如下:

数组名.length

3. 增强的 for 循环

增强的 for 循环能按顺序访问数组元素,可以用来迭代数组和集合对象的每个元素。因此这种循环也称为 for each 循环。形如:

for(type identifier : expression)
{
	//循环体
}

type 是元素类型,expression 必须是一个数组或集合对象,identifier 是元素本身,后面不需要再加中括号和下标

下面代码求数组 marks 中各元素的和:

double sum = 0;
for(var score : marks)
{
	sum = sum + score;
}
System.out.println("总成绩 = " + sum);

注意:增强的 for 循环只能按顺序访问数组元素,并且只能使用元素而不能对元素进行修改,不能获取当前元素的索引(下标)。

三、数组的应用

1. 数组元素的复制

数组元素的复制,是将一个数组中的所有元素复制到另一个同类型的数组中,得到的是两个彼此独立但又一模一样的数组。设有一个数组 source ,其中有4个元素,现在定义一个数组 target ,与原来数组的类型相同,元素个数相同。

区分:元素复制引用赋值

类似于对象名是对象的引用,数组名也是数组的引用。如果直接用赋值号连接两个数组名,实际上是使前者指向后者所引用的数组对象,即令两个数组引用指向同一个数组对象。如下所示:

int[] source = {10, 30, 20, 40};
int[] target = source;

上述代码无法将数组 source 中的每个元素复制到 target 数组中。

数组元素复制的方法

方法一:使用循环结构,将数组元素一个一个复制到目标数组中。

int[] source = {10, 30, 20, 40};
int[] target = new int[source.length];
for(var i = 0; i < source.length; i++)
	target[i] = source[i];

方法二:使用 System 类的 arraycopy() 方法,格式如下:

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

src 为原数组,srcPos 为原数组的起始下标,dest 为目标数组,destPos 为目标数组的下标,length 为复制的数组元素个数。下面代码实现将 source 中每个元素复制到数组 target 中:

int[] source = {10, 30, 20, 40};
int[] target = new int[source.length];
System.arraycopy(source, 0, target, 0, 4);

使用 arraycopy() 方法也可以将源数组的一部分复制到目标数组中。注意,如果目标数组不足以容纳原数组元素,会抛出异常。

2. 数组冒泡排序

算法与写法和 C 语言中大同小异,直接展示代码:

public static void bubbleSort(int[] array)
    {
        for(int i = array.length - 1; i > 0; i--)
        {
            boolean flag = true;
            for(int j = 0; j < i; j++)
            {
                if(array[j] > array[j + 1])
                {
                    int t = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = t;
                    flag = false;
                }
            }
            if(flag) break;
        }
    }

将该静态方法和主方法放在同一个类,然后即可在主方法中调用该方法。

3. java.util.Arrays 类

java.util.Arrays 类定义了若干静态方法对数组操作,下面介绍实用的几个。

  • public static int binarySearch(int[] a, int key)

    对于一个已升序排序的数组,通过二分查找快速定位 key 值位置。找到则返回下标,找不到则返回(插入点-1)。插入点为指定的值在数组中应该插入的位置。

  • public static void sort(int[] a)

    对数组 a 按升序排序。

  • public static void sort(int[] a, int fromIndex, int toIndex)

    对数组 a 中从起始下标 fromIndex (包含)到终止下标 toIndex (不包含)之间的元素排序。

  • public static void fill(int[] a, int val)

    用指定的 val 值填充数组 a 中的每个元素。

  • public static double[] copyOf(double[] original, int newLength)

    对原数组 original 进行复制,返回值为接收复制的新数组。新数组的长度可用参数 newLength 定义,若不想改变原数组长度,可填成 original.length。

4. 数组与方法

(1)数组作方法参数

数组对象可以作用参数传递给方法,下面代码定义了一个求数组元素和的方法:

public static double sumArray(double array[])
{
	var sum = 0;
	for(var i = 0; i < array.length; i++)
		sum += array[i];
	return sum;
}

注意:由于数组是对象,因此将其传递给方法是按引用传递。如果在方法体中修改了数组元素的值,则该修改反映到返回的数组对象。

(2)方法返回数组

一个方法可以返回一个数组对象,下面的方法返回参数数组的元素反转后的一个数组:

public static int[] reverse(int[] list)
{
	var result = new int[list.length];
	for(int i = 0, j = result.length - 1; i < list.length; i++, j--)
		result[j] = list[i];
	return result;
}

有了上述方法,可以使用如下语句实现数组的反转:

int[] list = {6, 7, 8, 9, 10};
int[] list2 = reverse(list);

(3)可变参数方法

Java 允许定义方法(包括构造方法)带可变数量的参数,这种方法称为可变参数方法。具体做法是在方法参数列表的最后一个参数的类型名之后、参数名之前使用省略号,如下所示:

public static int average(int ... array)
{
	//方法体
}

带可变参数的方法中也可以有一般的参数,但可变参数必须是方法的最后一个参数。如下所示:

public static int average(String name, int ... array)
{
	//方法体
}

这里,参数 values 被声明为一个 double 型值的序列,其中参数的类型可以是引用类型。对可变参数的方法,调用时可以为其传递任意数量的指定类型的实际参数

在方法体中,编译器将为可变参数创建一个数组,并将传递来的实际参数值作为数组元素的值,相当于为方法传递一个指定类型、长度不定的数组。

下面程序使用可变参数方法求和,加数个数不定。

程序 2-1 VarargsDemo.java

public class VarargsDemo
{
    //可变参数方法,可变参数类型定义成:类型...argName,它必须是方法的最后一个参数
    public static int getSum(int ... array)
    {
        var sum = 0;
        for(var i : array)
        {
            sum += i;
        }
        return sum;
    }
    public static void main(String[] args)
    {
        int result = getSum(2, 3, 4);
        System.out.println("2+3+4 = " + result);
        result = getSum(3, 5, 8, 9, 10);
        System.out.println("3+5+8+9+10 = " + result);

        int[] a = {1,2,3,4};
        result = getSum(a);
        System.out.println("a数组元素之和为 " + result);
    }
}

运行结果如下:

该程序调用了 getSum()方法并为其传递若干 int 型数,也可以传递一个 int 型数组。

5. 数组作成员变量

(1)设计构造方法

现有类 MyArray,带有私有成员数组 data。在类中进行代码设计。

public class MyArray
{
	private int []data;
	//构造方法
}
  • 浅拷贝(直接引用)
public MyArray(int[] inputArray)
{
	this.data = inputArray
}

通过传递的参数 inputArray 为 data 赋值,但由于是引用赋值,若 inputArray 改变,则对象内的 data 也会随之改变。

  • 深拷贝(创建副本)
public MyArray(int[] inputArray)
{
	this.data = Arrays.copyOf(intputArray, inputArray.length);
}

上述代码为传来的参数 inputArray 创建了副本,再赋值给 data ,因此 data 不会被外部篡改。这种写法无疑安全性更高,故下面主要使用这种写法。

(2)getter / setter

//getter 返回副本
public int[] getData()
{
	return Arrays.copyOf(data, data.length);
}
//setter 接收副本
public void setData(int[] newData)
{
	this.data = Arrays.copyOf(newData, newData.length);
}

(3)使用对象

在主方法中创建对象,并获取/修改对象成员的值。

  • 创建对象
//写法一:先另定义数组,再将其作为参数写入构造方法
int[] source = {1, 2, 3};
MyArray array1 = new MyArray(source)
//写法二:直接在构造方法参数列表中定义数组
MyArray array2 = new MyArray(new int[]{1, 2, 3});
  • 获取/修改对象
//获取数组
int[] got = array1.getData();
//修改数组
array1.setData(new int[]{4, 5, 6});

四、二维数组

Java 语言中数组元素还可以是一个数组,这样的数组称为数组的数组二维数组

1. 二维数组的定义

二维数组的使用也分声明、创建两个步骤。

(1)二维数组的声明

二维数组有下面3种等价的声明格式:

元素类型 [][]数组名;//推荐使用第一种格式
元素类型 数组名[][];
元素类型 []数组名[];

元素类型可以是基本类型,也可以是引用类型,示例:

int [][]matrix;
String [][]cities;

(2)二维数组的创建

创建二维数组即为每个元素分配存储空间。系统先为高维分配引用空间,然后顺次为低维分配空间。

  • 写法一:直接为每一维分配空间:
var matrix = new int[2][3];

适用于数组的低维具有相同个数的数组元素

二维数组是数组的数组,即数组元素也是一个数组。二维数组 matrix 有两个元素,matrix[0] 和 matrix[1] ,它们又都是数组,各有3个元素。matrix、matrix[0]、matrix[1]都是对象。每个元素在创建时会被指定默认值。

  • 写法二:先为第一维分配空间,再为第二维分配空间(反之不可):
var matrix = new int[2][];
matrix[0] = new int[3];
matrix[1] = new int[4];

适用于低维数组元素个数不同的情况。

第一维的每个元素(matrix[0]、matrix[1])可以指定不同的大小

对于引用类型的数组,除了为数组分配空间外,还要为每个数组元素分配空间:

cities[0][0] = new String("成都");
cities[0][1] = new String("绵阳");
cities[0][2] = new String("雅安");
cities[1][0] = new String("沈阳");
cities[1][1] = new String("锦州");

(3)数组初始化器

二维数组可使用初始化器在声明数组的同时为数组元素初始化,如下所示:

int[][] matrix = {{15, 56, 20, -2}, {10, 80, -9, 31}, {76, -3, 99, 21}};

2. 数组元素的使用

用下面的形式访问二维数组的元素:

数组名[下标1][下标2]

下标1和下标2可以是整型常数或表达式。每一维的下标是从0到该维长度减1.

  • 访问数组的长度

若有数组 matrix[3][4] ,则说明 matrix 数组是一个3行4列的数组。当我们讨论 matrix 的长度时,我们其实指的是它第一维的长度。多维数组每一维都有一个 length 成员表示数组的长度。matrix.length 的值是3,matrix[0].length 的值是4.