多catch子句访问父类方法报错,Maven编译失败javac正常
编译异常问题解析:多捕获包保护抽象类子类时的访问性错误
当捕获多个继承自同一包保护抽象类的异常时,会触发编译错误:java.lang.Throwable.getMessage() is defined in an inaccessible class or interface。Maven 3.8.x在Windows/Mac/Unix系统下构建均失败,但直接使用javac编译可成功。
存在两种可编译的场景:
- 仅捕获单个该类型异常
- 捕获多个上述异常的同时,额外添加一个其他异常(比如
RuntimeException)
代码示例
Main.java
package com.foo.service; import com.foo.utils.ExceptionA; import com.foo.utils.ExceptionB; public class Main { public static void main(String[] args) { try { if (true) { throw new RuntimeException("RuntimeException"); } if(true) { throw new ExceptionA("ExceptionA"); } if (true) { throw new ExceptionB("ExceptionA"); } } catch (ExceptionA | ExceptionB e) { // <- 无法编译: "Cannot access 'getMessage()' in 'java.lang.Throwable'" e.getMessage(); } // catch (ExceptionA e) { // <- 可编译 // e.getMessage(); // } // catch (ExceptionA | ExceptionB | RuntimeException e) { // <- 可编译 // e.getMessage(); // } } }
AbstractException.java
package com.foo.utils; class AbstractException extends Exception { protected AbstractException(final String message){ super(message); } }
ExceptionA.java
package com.foo.utils; public class ExceptionA extends AbstractException { public ExceptionA(String message) { super(message); } }
ExceptionB.java
package com.foo.utils; public class ExceptionB extends AbstractException { public ExceptionB(String message) { super(message); } }
pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>foo</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> </project>
问题原因解析
这是Java类型系统中联合捕获类型的公共超类型推导规则导致的权限校验问题:
- 联合捕获的类型推导:当使用
catch (ExceptionA | ExceptionB e)时,编译器会推导变量e的类型为两个异常的最具体公共超类型。这里ExceptionA和ExceptionB的直接公共超类是包保护的AbstractException(默认访问权限,仅com.foo.utils包内可见),而Main类位于com.foo.service包,无法访问该抽象类。 - 方法访问权限连锁校验:调用
e.getMessage()时,编译器会认为你是通过不可访问的AbstractException来访问Throwable的方法——尽管getMessage()是Throwable的公共方法,但由于推导的变量类型不可访问,导致权限检查失败。
两种可编译场景的逻辑:
- 仅捕获单个异常:此时
e的类型是公共的ExceptionA(或ExceptionB),Main类可直接访问该类,调用getMessage()时通过公共类访问父类Throwable的方法,无权限问题。 - 添加RuntimeException联合捕获:三个异常的最具体公共超类型变为公共类
Exception,Main类可正常访问,因此调用getMessage()无权限障碍。
Maven与javac编译差异
Maven的maven-compiler-plugin默认启用更严格的编译检查(如-Xlint相关选项),而直接使用javac编译时若未添加严格校验参数,会绕过推导类型的权限校验,导致编译通过。
内容的提问来源于stack exchange,提问作者user871611
相关产品推荐
相关产品推荐

