首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 綜合教學

Java 每日一題:跨包訪問默認修飾符類的編譯錯誤分析

     編輯:Java 綜合教學

【Java 每日一題】20161121:跨包訪問包私有類編譯失敗原因深度解析

題目代碼

// 文件:Nov2016/use01/Test.java
package Nov2016.use01;

class Test {  // 無修飾符 = package-private (包私有)
    public String getString() {
        return "123";
    }
}
// 文件:Nov2016/Ques1121.java
package Nov2016;

import Nov2016.use01.Test;  // 嘗試導入包私有類

public class Ques1121 {
    public static void main(String[] args) {
        Test test = new Test();  // 編譯錯誤!
        System.out.println(test.getString());
    }
}

問題

上述程式碼能否編譯通過?

答案

無法編譯通過,編譯器將報錯:

error: Test is not public in Nov2016.use01; cannot be accessed from outside package
import Nov2016.use01.Test;
                    ^

核心知識點:Java 訪問修飾符與包可見性

修飾符同類同包子類(異包)異包非子類
public✅✅✅✅
protected✅✅✅❌
無修飾符 (package-private)✅✅❌❌
private✅❌❌❌

詳細解析

  1. 類級別訪問控制:頂層類 (非內部類) 僅允許 public 或 無修飾符 (package-private)。Test 類無修飾符,故為包私有。
  2. 包私有類限制:僅在同一包內可見。Nov2016.use01 包外的代碼 (如 Nov2016.Ques1121) 無法導入、實例化、引用該類。
  3. 編譯期強制檢查:Java 編譯器在 編譯階段 即檢查訪問權限,而非運行時。因此 import Nov2016.use01.Test 直接報錯。
  4. 方法修飾符無關:即使 getString() 是 public,類本身不可見,方法也無法被外部調用。

修正方案

方案 1:將 Test 類聲明為 public (推薦)

// Nov2016/use01/Test.java
package Nov2016.use01;

public class Test {  // 添加 public
    public String getString() {
        return "123";
    }
}

方案 2:將調用類移入同一包

// Nov2016/use01/Ques1121.java
package Nov2016.use01;  // 同包

public class Ques1121 {
    public static void main(String[] args) {
        Test test = new Test();  // 同包可直接訪問,無需 import
        System.out.println(test.getString());
    }
}

方案 3:使用公共介面 + 工廠模式 (封裝內部實現)

// Nov2016/use01/TestService.java (公共介面)
package Nov2016.use01;

public interface TestService {
    String getString();
}

// Nov2016/use01/TestImpl.java (包私有實現)
class TestImpl implements TestService {
    public String getString() { return "123"; }
}

// Nov2016/use01/TestFactory.java (公共工廠)
public class TestFactory {
    public static TestService create() { return new TestImpl(); }
}

// Nov2016/Ques1121.java (外部調用)
package Nov2016;
import Nov2016.use01.TestFactory;
import Nov2016.use01.TestService;

public class Ques1121 {
    public static void main(String[] args) {
        TestService service = TestFactory.create();
        System.out.println(service.getString());
    }
}

最佳實踐建議

  1. API 類必須 public:跨包調用的類、介面、枚舉、註解必須聲明 public
  2. 內部實現類包私有:僅供模塊內部使用的實現類、工具類、DTO 可無修飾符,減少公開 API 面
  3. 模塊劃分遵循高內聚低耦合:同一業務領域的類放在同一包,對外僅暴露介面
  4. 使用 ArchUnit / JDepend 檢測:CI 中加入架構測試,防止誤將包私有類暴露為公共 API

延伸思考

  • 內部類:可使用 private/protected 修飾,外部類可訪問私有內部類
  • 模塊系統 (JPMS, Java 9+):module-info.java 中 exports 控制包導出,比修飾符更精細
  • 反射繞過檢查:Class.forName("Nov2016.use01.Test") 可加載,但 newInstance() 仍會拋出 IllegalAccessException (除非 setAccessible(true))
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved