Maven和IDEA集成、导入Maven项目这件事,看起来是Java开发里最基础的一环,但真正操作起来,很多人都在"打开项目"之后栽过跟头。身边总是有人在导入Maven项目时遇到一连串奇怪现象:项目不识别、依赖全飘红、模块对不上,点刷新也没用。这篇文章我会从一个真正要落地开发的视角,把IDEA中导入Maven项目的完整过程拆开来讲:先认识标准Maven工程,再把本机Maven环境配置到位,然后逐步操作导入、处理导入后的高频异常,最后聊一下多模块Maven工程的正确姿势。内容不绕弯子,适合刚接触Maven的同学,也适合想把自己那套"靠运气导入"的流程固化成规范的开发者。
1. 导入前先认清:一份Maven项目在磁盘上到底长什么样
1.1 标准Maven工程目录结构,先看一眼再动手
一个典型的单模块Maven项目,目录结构其实非常固定:
my-project/ ├── pom.xml ├── src/ │ ├── main/ │ │ ├── java/ │ │ └── resources/ │ └── test/ │ ├── java/ │ └── resources/ └── target/src/main/java存放业务源码,src/main/resources放配置文件和模板资源;src/test/java是测试代码,编译时会一并进入classpath。target目录是Maven执行编译、打包后生成产物的地方,打开项目之前它可能根本不存在,构建一次之后才会生成,所以它不需要被纳入版本管理,拷贝工程时也可以直接忽略掉。很多人拿到压缩包里的项目后,先找一个有颜色的图标、找src目录,却忽略了pom.xml的位置,导致打开方式不对。确认一个目录是不是Maven工程,最简单的方法就是看根目录是否存在pom.xml,以及pom.xml里的坐标和依赖是否正常。
还有一点值得注意:IDEA识别Maven项目时,虽然也会看目录命名,但最终决策依据始终是pom.xml。只要根目录有pom.xml,IDEA就有机会把它导入成Maven工程;否则哪怕目录结构长得再像,也不会触发Maven导入流程。所以拿到一个陌生项目,第一步永远是确认pom.xml在哪,而不是急着点开IDEA。
1.2 pom.xml是门禁:IDEA靠它判断"这是不是一个Maven项目"
pom.xml是Maven项目的核心配置文件,IDEA导入Maven项目的过程,本质上是解析pom.xml并建立工程模型。一个pom文件里的信息很多,但日常导入项目时,最需要关注的只有几个节点。第一个是GAV坐标,也就是groupId、artifactId、version,这三个组合起来唯一标识一个构件;第二个是packaging,它决定构件是jar、war还是pom;第三个是properties,很多项目会把编译级别、源码编码、各种统一版本号放在这里;第四个是dependencies,也就是这个项目依赖了哪些外部构件。下面是一个最小可用的pom示例:
<project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>my-project</artifactId> <version>1.0.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>com.example</groupId> <artifactId>common-utils</artifactId> <version>1.0.0</version> </dependency> </dependencies> </project>我故意没有把build和plugins写全,因为导入项目阶段,你不需要立刻理解所有Maven插件。你只需要知道:pom里的每个依赖坐标都是"一个jar包的名字",Maven会根据坐标去本地仓库和远程仓库找对应的jar包。IDEA导入时,红色波浪线也好、代码爆红也好,大部分根源都在这些坐标找不到对应文件。
1.3 为什么要先分清目录结构再动手导入
很多人失败在根本没分清"项目根目录"和"普通目录"。假设你收到一个压缩包,解压后外面还有一层和项目名相同的文件夹,里面才是pom.xml,那你打开的时候应该选择里面那一层;如果你打开的是外层文件夹,IDEA看不到pom.xml,自然也就不会走Maven导入的流程。
还有一种常见情况是多人协作仓库里既有前端代码又有后端工程,后端Maven项目嵌在某个子目录下,这时候你直接打开整个仓库,IDEA虽然能识别出根目录下的pom.xml,但如果仓库根目录还有其他大型文件,索引会非常慢。先通过目录树找到pom.xml的位置,再决定打开范围,能省掉后面很多麻烦。这看起来像常识,但在实际操作中,至少有一半的"导入不出来"是因为选错了目录层级。
2. 在IDEA接管之前,先把本机Maven环境理顺
2.1 本机装Maven还是直接用IDEA内置的Maven?我的建议
IDEA通常会内置一份Maven,这是它能直接跑Maven命令的原因。对于只是临时学习、快速写demo的人来说,直接用内置Maven完全没问题,省去安装配置的步骤,最小成本验证项目能不能跑。
但在实际工作环境中,我更建议在机器上独立安装一份Maven,原因有三个。第一,命令行可用,有些项目脚本会直接调用mvn命令,比如CI环境、部署脚本,你本机没有独立Maven,很多排查工作做不了。第二,版本可控,IDEA内置的Maven版本和你们构建环境里的版本不一定一致,版本差异可能导致同一份代码在IDEA里正常、在打包机上失败,独立安装可以统一版本。第三,配置独立,独立Maven使用自己的一份settings.xml,镜像、本地仓库、仓库账号都能集中管理,不依赖IDEA的升级而变化。
独立安装Maven并不复杂,下载压缩包、解压、设置环境变量,命令行输入mvn -v能看到版本就算成功。安装后,IDEA里的Maven home path指向它就好。如果你已经用内置Maven跑通了很多项目,也不是一定要换,但至少要弄清楚:当前生效的settings.xml在哪、本地仓库落在哪个目录。
2.2 三个关键配置项:Maven home、settings.xml、Local repository
在IDEA中打开Settings,找到 Build, Execution, Deployment 下的 Build Tools -> Maven,你会看到三个最基础的配置项:Maven home path、User settings file、Local repository。
第一项Maven home path要指向Maven安装后的根目录,不是bin目录,很多人填错位置导致IDEA找不到Maven。第二项User settings file是用户级settings.xml的路径,这里如果留空,IDEA会去默认位置寻找;如果你在多个项目里使用不同仓库配置,这里可以把路径指定到某个具体文件,但要注意:Maven不会自动创建用户级settings.xml,你需要把文件放好。第三项Local repository是本地仓库路径,它通常受settings.xml里的localRepository控制,在IDEA这里你可以看到它最终的值。
这里的顺序是:IDEA读取Maven的全局配置和用户配置,合成一份有效的配置,然后在界面上显示本地仓库等关键结果。所以理论上你要修改的是settings.xml,而不是在这个界面直接改路径。搞清楚这个顺序,后面配置镜像和本地仓库时才不会改完没生效还不知道为什么。
2.3 settings.xml里的镜像和本地仓库,直接影响导入成功率
导入Maven项目时,最容易被网络因素卡住的环节就是依赖下载。Maven默认从公共中央仓库拉取jar包,但在一些网络环境下,访问公共仓库的速度非常慢甚至超时。这时候就需要通过settings.xml配置镜像(mirror)来加速。镜像的作用很简单:你告诉Maven,所有对中央仓库的请求都先走这个镜像地址,镜像服务器本身再缓存或从上游拉取。下面是一份精简的settings.xml参考:
<settings> <localRepository>/opt/maven/repository</localRepository> <mirrors> <mirror> <id>example-public</id> <name>example public mirror</name> <url>https://repo.example.com/maven-public/</url> <mirrorOf>central</mirrorOf> </mirror> </mirrors> </settings>其中的mirrorOf可以理解成"拦截规则":central表示只拦截中央仓库的请求;如果写成*,则表示所有远程仓库都走这个镜像。本地仓库路径建议放在一个稳定、不易被清理的位置,且路径中不要包含中文、空格和特殊符号,否则某些旧版本的Maven或IDEA可能解析异常。
配置完成后,在IDEA里重新打开项目前,先到命令行确认一下:mvn -v和mvn help:effective-settings能帮你看到当前生效的配置。我在处理导入问题时发现,很多依赖下载失败的根源根本不在项目本身,而是settings.xml没配对,比如把镜像地址写成了不可用但自己不知道,或者本地仓库指向了一个没有写权限的目录。这类问题IDE的错误提示往往不太明显,所以提前把settings.xml理顺,远比导入后再排查靠谱。
2.4 JDK与Maven版本的匹配,导入后能不能编译的底色
Maven本身是基于Java运行的构建工具,它需要JDK才能工作;工程代码的编译也会受Maven里编译器插件参数控制。导入项目后,很多人遇到Error: java: invalid source release: 17之类的报错,本质上就是当前模块使用的语言级别和JDK版本不一致。
一般建议的对应关系是:Maven 3.6.x常见于JDK 8/11的项目,Maven 3.8.x覆盖JDK 8/11/17,Maven 3.9.x则对JDK 17及更高版本支持更好。实际工作中不必背下这张表,只要记住一条准则:让IDEA的Project SDK、模块的Language level、pom.xml里compiler配置三方保持一致。比如pom里写了maven.compiler.source/target为11,但Project SDK选的却是17,那编译时会按17的javac去处理,部分老代码可能报错;反过来pom里写了17而SDK是11,必然出现invalid source release一类错误。
导入前先打开Project Structure确认模块的SDK,比导入后发现编译失败再回头改要高效得多。很多看起来是"依赖问题"的报错,最终查下来其实是JDK版本不一致。
3. 动手导入:Open vs Import Project,完整操作路径
3.1 Open和Import Project到底有什么区别
接触过不同版本IDEA的人,会对这两个入口有完全不同的认知。老版本的IDEA有专门的Import Project入口,在欢迎页或菜单里可以找到;新版本的IDEA把导入功能的入口合并到了Open里。
实际使用中,File -> Open 选中一个含pom.xml的目录时,如果IDEA识别出是Maven工程,会弹出"Open as Project";选择后以项目方式打开。而Import Project的旧流程本质上也是"选择外部项目 -> 识别构建工具 -> 生成IDE工程结构",两者在Maven项目导入这件事上没有本质区别。
真正重要的是你得理解:IDEA打开Maven项目,不是你手动拖入几个java文件,而是让它去读pom.xml,按pom描述的依赖关系建立模块结构。搞清楚了这一点,无论界面上按钮叫什么,你都不会慌。
3.2 实操步骤:选择项目根目录,直到看到Maven工具窗口
完整操作其实很简单,我按顺序写一遍。
第一步,在欢迎页或菜单里选择Open,定位到包含pom.xml的项目根目录。第二步,如果IDEA弹窗问你是打开还是信任项目,选择Open as Project并确认信任(Trust Project),这一步在多模块项目里尤其关键,因为有些构建脚本会执行额外操作,IDEA默认不信任,部分配置就不会生效。第三步,等待IDEA解析pom.xml,此时底部事件日志或状态栏会出现Maven相关的加载提示,首次打开外部项目通常需要几十秒到几分钟不等。第四步,打开右侧的Maven工具窗口,确认出现了模块列表和生命周期的节点。第五步,如果之前IDEA卡住过或没有触发导入,执行菜单里的Reload All Maven Projects。
看到Maven窗口里出现clean、compile、install这些生命周期节点时,导入才算是真正落地了。很多人导入完成后直接双击run,其实还要先确认模块加载完成,否则跑起来的可能是不完整的类路径。
提示:如果你的IDEA版本比较老,找不到Open as Project选项,可以直接选择 New -> Project from Existing Sources,在向导里指定pom.xml,效果一样。
3.3 打开后IDEA在后台究竟在做什么
这一步不需要你操作,但理解它有助于判断"卡住"到底是不是异常。导入Maven项目时,IDEA后台大概做了三件事。
第一,解析pom.xml,生成项目的Maven模型,把所有模块、依赖、插件读入内存。第二,根据依赖坐标检查本地仓库,如果本地没有,就按settings.xml里配置的镜像地址去下载jar包,下载过程中Maven工具窗口旁边可能有个转圈的小图标,事件日志里也会出现Downloading开头的记录。第三,把下载好的jar包关联到工程的External Libraries中,同时按pom里的modules节点注册子模块。
你看到的项目结构树,其实是这三步完成后的结果。如果第二步卡住,通常表现是项目一直转圈但代码已经能看到,这是下载慢或者镜像不可用;如果是第三步出问题,表现是jar包似乎都在,但模块树不完整。根据卡在哪一步去对症处理,比用"刷新大法"反复重来要快得多。
3.4 如果IDEA没有自动识别为Maven项目,手动补一刀
新版IDEA对Maven项目的自动识别已经相当智能,但偶尔还是会碰到不上不下的情况:项目能打开、javadoc和源码都看得见,可始终没有Maven工具窗口,也没有依赖管理。
这时候的补救办法是先找到项目根目录下的pom.xml,在编辑区右键,选择 Add as Maven Project,IDEA会立即把该pom加入Maven模型。另一种方式是从Maven工具窗口左上角的"+"号添加pom.xml路径。操作完成后,再点击Maven面板的刷新或Reload All Maven Projects,让IDEA重新解析一次。
这个手动入口在旧版本里尤其常用,因为某些JDK环境或IDEA配置下,自动检测可能失效。掌握了这个入口,即使在非标准的工作区布局里,你也能把Maven工程拉回正轨。
4. 导入后的"爆红"现象,按这个顺序排查
4.1 项目完全没被识别成Maven工程:先确认pom.xml是否加载
导入完成后最尴尬的状态是项目树看起来能打开,但右下角没有Maven标识,Maven工具窗口是空的。这种问题通常不是依赖的问题,而是pom.xml没有被加载进IDE的Maven模型。
先看项目结构树里有没有pom.xml这一项;再打开Maven工具窗口,如果列表为空,手动添加pom或使用Add as Maven Project即可。还要注意一种情况:你打开了一个多模块项目的子模块目录作为独立工程,但父pom的modules配置指向了其他模块,IDEA可能会把当前目录当成单模块处理。判断方法很简单:右键pom.xml,看菜单里有没有Maven相关的子菜单;没有的话,说明这个pom还没进入模型。把pom加载进去后,项目图标往往会带一个小的M标识,那时才算真正被识别。
4.2 依赖全部飘红:查本地仓库、.lastUpdated与强制更新
依赖飘红是最典型的导入后问题,而且它和"代码本身写错"是两回事。如果pom.xml里每个dependency都出现红色波浪线,甚至代码里大面积import错误,多半是依赖没下载成功。
这时候第一个动作不是去改代码,而是检查本地仓库对应路径下有没有生成.lastUpdated文件。这个文件是Maven记录"下载失败"用的标记文件,存在它意味着上次下载中断或没有成功。很多情况下,只点IDE的刷新按钮并不会重新下载,你需要先删除对应的.lastUpdated目录,再执行强制更新。IDEA里可以通过Maven工具窗口的刷新按钮,或者在命令行执行:
mvn -U clean install-U参数会强制检查快照和远程更新。如果删除.lastUpdated后仍然失败,再回头检查镜像地址是否可用、本地仓库是否有写权限、依赖坐标是否正确。
注意:删除.lastUpdated文件时,建议删除整个失败坐标的版本目录,而不只是单个文件,因为同一个构件下可能有多个.lastUpdated标记。
我遇到过不止一次,项目里引用的某个版本非常老旧,镜像仓库已经不存了,最后是通过切换仓库源解决的。所以排查依赖问题时,先确认"源对不对",再确认"网络通不通",最后才考虑坐标写错。
4.3 代码报错但依赖存在:检查SDK、语言级别、Maven Runner的JRE
依赖正常、jar包也出现在External Libraries里,但java文件依然大面积报"找不到符号""程序包不存在"之类错误,这种情况通常不是依赖缺失,而是编译环境对不上。
先在 Project Structure -> Modules 里看当前模块的Language level是否和pom.xml中的编译级别一致,再检查Project SDK是不是正确版本。还有一个容易被忽略的点:Settings -> Build Tools -> Maven -> Runner 里的JRE选项,IDEA在执行Maven命令时用的JRE和Project SDK不一定是同一个。如果Maven Runner的JRE路径指向一个不存在或者版本不对的JDK,导入后的编译就会出现莫名其妙的结果。把这三个地方统一起来,再执行一次Reload All Maven Projects,很多看似"缺依赖"的报错其实会自动消失。
4.4 多模块工程内部互相找不到:先install父模块
如果你导入的是多模块Maven项目,除了外部依赖,还会遇到模块之间互相引用的场景,比如module-service依赖module-api。这类问题在IDEA里常见的表现是:两边的java文件都正常,但service模块里import api的类时标红,提示找不到。
这时你要意识到Maven的模块间引用本质是"构件依赖":module-api要先被安装到本地仓库,module-service才能通过坐标找到它。所以第一次导入多模块工程后,建议先在父pom上执行一次mvn clean install -DskipTests,把公共模块发布到本地仓库,然后回到IDEA点击Reload All Maven Projects。这之后模块间的依赖一般就正常了。如果还是不行,需要检查父子pom的relativePath配置和modules列表是否写对,比如某个子模块的parent坐标写错,也会出现"找不到"的误导。
4.5 一张排查顺序速查表,贴在旁边不算亏
为了处理问题时不用每次都从头回忆,我把导入后最常见的问题整理成一张表。你不用全背,只要记住"现象 -> 先查模块是否加载 -> 再查依赖是否下载 -> 再查SDK是否对齐 -> 最后查子模块依赖顺序"这条主线就行。
| 现象 | 可能原因 | 处理顺序 |
|---|---|---|
| 项目没有Maven工具窗口 | pom.xml未加载 | 右键pom -> Add as Maven Project |
| pom里所有依赖红波浪线 | 依赖下载失败、镜像不可用 | 查.lastUpdated,删掉后强制更新 |
| 代码找不到外部jar包 | 本地仓库缺jar或坐标错误 | 看External Libraries是否有jar,没有则刷新下载 |
| 代码找不到同项目内模块 | 模块未install或modules配置错误 | 父pom执行install,再Reload |
| 所有测试代码都报错 | 缺少测试依赖 | 检查测试相关坐标是否在dependencies里 |
| 编译时报source release错误 | SDK或Language level不匹配 | 统一JDK、语言级别、pom compiler配置 |
这张表之所以把"模块加载"放最前,是因为IDEA的所有错误提示都建立在pom模型正确的假设上;模型都没建立,后面的一切排查都没有意义。
5. 多模块Maven项目:导入逻辑和单模块不太一样
5.1 先理解聚合pom与父子模块的目录结构
多模块工程在大型项目里非常常见,它的典型结构是这样:
parent-project/ ├── pom.xml ├── module-api/ │ ├── pom.xml │ └── src/ ├── module-service/ │ ├── pom.xml │ └── src/ └── module-web/ ├── pom.xml └── src/根目录的pom.xml通常只有两件事:一是通过modules节点声明哪些子目录属于这个工程;二是通过dependencyManagement统一管理子模块的依赖版本。子模块的pom.xml则通过parent节点声明自己的父pom是谁。
理解这点后,导入时要注意:应该打开根pom所在的目录,而不是逐个打开module-api、module-service。IDEA读取根pom后,会自动把modules里声明的子模块加进来,形成一棵完整的模块树;如果你一个个单独打开,虽然子模块各自能识别成Maven工程,但模块间的依赖关系、运行集成都会变得特别别扭,甚至出现多个窗口互相干扰。
5.2 导入多模块项目的两个关键动作,别一个个单独打开
第一个关键动作是:选择聚合根目录导入,等IDEA把modules列表全部加载进来。第二个关键动作:导入完成后先在父pom上执行一次install。
为什么叫关键?因为多模块项目里,子模块A依赖子模块B时,Maven解析时去的是本地仓库,而不是IDE的项目树。如果B还没有被install,A怎么刷新都找不到B。这个坑特别隐蔽,因为IDEA的智能提示有时候会临时给出正确结果,让人误以为配置好了,但一旦执行Maven命令就立刻暴露。
所以我的固定流程是:打开多模块工程 -> Reload All Maven Projects -> 命令行或IDEA里执行一次父pom的clean install -DskipTests -> 再Reload一次。这样虽然多了一步,但能避开绝大多数模块间找不到的问题。
5.3 Maven工具窗口里的常用命令,先把clean和install分清楚
Maven工具窗口展开后会看到一组生命周期节点:clean、validate、compile、test、package、install、deploy。它们不是互相独立的按钮,而是Maven生命周期中的不同阶段。简单理解:compile会编译项目,test会跑测试,package会打包jar/war,install会把产物安装到本地仓库,deploy会上传到远程仓库。
其中package和install的差别值得强调:package只是在target目录生成构建产物,install还会把这个产物放到本地仓库,供本机其他Maven工程引用。所以多模块项目里,你想让module-service引用最新的module-api,必须对module-api执行install,而不是只看它在IDEA里存在。
日常开发中最常用的一条命令是mvn clean install -DskipTests,它几乎覆盖了大多数场景。在IDEA里执行时,可以直接双击生命周期节点,也可以在Maven工具窗口的工具栏找到Execute Maven Goal,输入完整命令。
5.4 集成使用中值得打开的配置项:自动导入与运行器调优
Maven和IDEA配合得顺不顺,还取决于几个容易忽略的设置。
第一个是 Settings -> Build Tools -> Maven -> Importing 里的 Import Maven projects automatically,打开后pom.xml一有变化,IDEA会自动刷新依赖,省去每次手动Reload。第二个是Runner页面的JRE选择,确保它指向实际存在的JDK,避免Maven命令跑在错误环境。第三个是Importer的VM options,如果你的项目依赖特别多,解析时内存吃紧,可以把默认的堆内存调大,比如在VM options for importer里写:
-Xmx1024m这样处理大型Maven工程时,导入卡死的概率会明显下降。还有一个小习惯:pom.xml改完,与其疯狂点刷新,不如先用Maven命令行验证,再Reload,因为命令行输出比IDEA的图形提示更接近Maven底层逻辑。
6. 使用IDEA+Maven集成过程中,沉淀下来的几条边界经验
6.1 换电脑/换环境时,别直接拷贝整个工程目录
很多人迁移环境时会把整个项目目录原封不动打压缩包,连IDEA的.idea目录和target目录一起带走,到了新机器直接打开,结果项目识别异常、依赖全部失效。问题不在于代码,而在于IDEA的工程配置文件里记录的是旧机器的绝对路径和旧版SDK信息。
正确做法是:只拷贝pom.xml和src等源码相关文件,到了新环境后,先确认settings.xml的本地仓库指向,然后用Open重新导入,让IDEA重新生成工程文件。如果确实带了.idea目录,导入前把它删掉通常能解决大量"莫名其妙"的问题。
6.2 依赖版本冲突往往比缺依赖更难发现
导入Maven项目时,依赖缺失会被红色波浪线直接标出来,但版本冲突却经常静默出现。特征可能是:项目能构建,但运行时报某个类的NoSuchMethodError,或者大量类重复注册。
如果你遇到这类问题,不要只在IDEA里翻pom,可以在项目根目录执行:
mvn dependency:tree把整个依赖树拉出来,看看同一个groupId的jar是否出现了多个版本。多版本并存的根因,通常是传递性依赖:你直接依赖的A,内部又依赖了老版本的B,而项目里还有另一个地方直接依赖了新版本的B。Maven的依赖仲裁原则是"短路径优先"和"先声明优先",但最稳妥的解决办法是在父pom的dependencyManagement里显式锁定目标版本。读依赖树比在IDE里瞎猜有效得多。
6.3 命令行先行:导入问题先跑一遍mvn再调IDEA
IDEA很聪明,但它不是Maven本身。它展示的错误信息是经过二次加工和缓存处理的,有时候还会因为索引没更新而显示陈旧结果。
所以我处理Maven导入问题时的固定次序是:先在项目根目录打开终端,执行mvn clean install -DskipTests,看真实输出。命令行如果成功,说明工程本身没问题,IDEA的报错大多是缓存、SDK、模块注册问题,接下来重刷IDEA即可;命令行如果失败,输出里会明确告诉你缺少哪个依赖、哪个模块找不到,那才是问题的根源。
很多人在IDE里反复点刷新但问题依旧,其实只是没看到底层错误。命令行先行这一招,几乎能帮你过滤掉一半的无用操作。
6.4 一个小技巧:缓存失效这个动作,可以进入默认流程
最后再分享一个非常通用的小技巧。如果导入Maven项目后,代码里各种奇怪的红色提示持续存在,而且你已经确认依赖没问题、SDK没问题,那可以考虑让IDEA重建索引和清空缓存:菜单 File -> Invalidate Caches / Restart。这个动作会把IDE的本地索引清掉,重新扫描项目结构。
很多人只在系统卡顿时才用它,但我觉得它完全可以进入Maven导入异常的默认排查流程,排在前三步。它解决不了代码逻辑问题,但真的能解决很多"看起来是Maven问题、实际上是IDEA状态问题"的怪现象。