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

JNI 實作主控台密碼輸入:C/C++ 原生方法隱藏輸入字元完整教學

     編輯:Java 相關知識

Java 主控台密碼輸入難題

Java 標準 API 缺乏不回顯字元的主控台密碼輸入功能(JDK 6 引入 Console.readPassword() 前)。本文示範透過 JNI 呼叫 C/C++ 實作跨平台密碼輸入,適用於舊版 JDK 或需自訂行為的場景。

1. Java 端宣告原生方法

public class JNIPasswordReader {
    // 原生方法宣告
    private native String readPassword();

    // 載入原生庫
    static {
        System.loadLibrary("PasswordDLL"); // 不含副檔名,平台自動對應 .dll/.so/.dylib
    }

    public static void main(String[] args) {
        JNIPasswordReader reader = new JNIPasswordReader();
        String pwd = reader.readPassword();
        System.out.println("\nYour Password is: " + pwd);
    }
}

2. 產生 JNI 標頭檔

javac JNIPasswordReader.java
javah -jni JNIPasswordReader

產生 JNIPasswordReader.h:

#include 
#ifndef _Included_JNIPasswordReader
#define _Included_JNIPasswordReader
#ifdef __cplusplus
extern "C" {
#endif
JNIEXPORT jstring JNICALL Java_JNIPasswordReader_readPassword(JNIEnv*, jobject);
#ifdef __cplusplus
}
#endif
#endif

3. C++ 實作原生方法

// PasswordDLL.cpp
#include "JNIPasswordReader.h"
#include   // Windows: _getch()
#include 

JNIEXPORT jstring JNICALL Java_JNIPasswordReader_readPassword(JNIEnv* env, jobject obj) {
    char buffer[256] = {0};
    char* p = buffer;
    int ch;

    while ((ch = _getch()) != '\r' && ch != '\n') { // Enter 結束
        if (ch == '\b' && p > buffer) { // Backspace
            *--p = 0;
            std::cout << "\b \b"; // 終端機游標回退覆蓋
        } else if (isprint(ch) && p < buffer + 255) {
            *p++ = ch;
            std::cout << '*'; // 顯示星號
        }
    }
    std::cout << std::endl;
    return env->NewStringUTF(buffer);
}

4. Visual Studio 2005+ 建置 DLL

  1. 建立 Win32 專案 → DLL,專案名 PasswordDLL
  2. 包含目錄加入:$JDK_HOME/include、$JDK_HOME/include/win32
  3. 複製 jni.h、jni_md.h 至 VC++ Include 目錄或專案內
  4. 建置 → 產生 PasswordDLL.dll

5. 部署與執行

  1. 將 PasswordDLL.dll 放入系統 PATH 目錄:%JAVA_HOME%\bin、%WINDIR%\System32 或專案根目錄
  2. 執行:java JNIPasswordReader
  3. 輸入密碼 → 螢幕顯示星號 → 完成後印出明文(僅示範)

6. 跨平台考量

平台無回顯輸入函數庫檔名
Windows_getch() (conio.h)PasswordDLL.dll
Linux/macOStermios 設定 ICANON/ECHOlibPasswordDLL.so

Linux 實作片段

#include 
#include 

int getch() {
    struct termios oldt, newt;
    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~(ICANON | ECHO);
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);
    int ch = getchar();
    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    return ch;
}

7. 現代替代方案

  • JDK 6+:Console console = System.console(); char[] pwd = console.readPassword();
  • Swing:JPasswordField 圖形化輸入。
  • 第三方庫:JLine、Picocli 提供豐富主控台互動。

8. JNI 開發關鍵提醒

  1. System.loadLibrary 參數**不含副檔名**,跨平台自動對應。
  2. JNI 函數命名規範:Java_套件_類別_方法(底線分隔,套件點號換底線)。
  3. JNIEnv* 僅在呼叫執行緒有效,**不可跨執行緒傳遞**。
  4. 原生代碼崩潰會導致 JVM 直接終止,需嚴謹測試。
  5. 字串傳遞:NewStringUTF (Modified UTF-8)、GetStringUTFChars 需 Release。

參考資源

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved