Java 標準 API 缺乏不回顯字元的主控台密碼輸入功能(JDK 6 引入 Console.readPassword() 前)。本文示範透過 JNI 呼叫 C/C++ 實作跨平台密碼輸入,適用於舊版 JDK 或需自訂行為的場景。
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);
}
}
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
// 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);
}
Win32 專案 → DLL,專案名 PasswordDLL$JDK_HOME/include、$JDK_HOME/include/win32jni.h、jni_md.h 至 VC++ Include 目錄或專案內PasswordDLL.dllPasswordDLL.dll 放入系統 PATH 目錄:%JAVA_HOME%\bin、%WINDIR%\System32 或專案根目錄java JNIPasswordReader| 平台 | 無回顯輸入函數 | 庫檔名 |
|---|---|---|
| Windows | _getch() (conio.h) | PasswordDLL.dll |
| Linux/macOS | termios 設定 ICANON/ECHO | libPasswordDLL.so |
#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;
}
Console console = System.console(); char[] pwd = console.readPassword();JPasswordField 圖形化輸入。JLine、Picocli 提供豐富主控台互動。System.loadLibrary 參數**不含副檔名**,跨平台自動對應。Java_套件_類別_方法(底線分隔,套件點號換底線)。JNIEnv* 僅在呼叫執行緒有效,**不可跨執行緒傳遞**。NewStringUTF (Modified UTF-8)、GetStringUTFChars 需 Release。