P0 Bug 修复: - Canvas.drawBitmap 重复定义导致重载丢失 → 合并为*args重载 - String.hashCode() 不可达的第二return → 修复为单return - File.compareTo() 调用不存在的__cmp__ → 改为显式比较 - HashMap.remove() 逻辑错误 → 区分单参(返回旧值)/双参(返回boolean) P1 核心行为增强: - Handler: sendMessage/sendMessageDelayed 现在真正入队异步执行 - Looper: loop() 实现真正的消息循环(按when时间取出到期消息) - AsyncTask: execute() 在后台线程池执行,完成后主线程回调 - Bundle: 新增12个数组类型put/get方法 - Math.round: 改为Java语义(floor(a+0.5))而非Python银行家舍入 - Thread: currentThread()缓存对象, 新增join/getState/getId/getPriority - String: 新增strip/repeat/isBlank/lines/subSequence/getChars/chars/formatted/translateEscapes P2 缺失API补全: - 新增21个Java标准Exception类 (NullPointerException等) - View: 新增39个事件处理/监听器/位置尺寸方法 - Activity: 新增33个生命周期/权限/UI方法 - Context: 新增22个文件流/权限/资源/主题方法 - Canvas: 支持 Canvas(Bitmap) 构造函数重载 - __init__.py: __all__ 补全Exception体系和Activity类
1786 lines
46 KiB
Python
1786 lines
46 KiB
Python
"""
|
||
Java lang standard library APIs implemented in Python.
|
||
java.lang package - String, Integer, Math, Thread, System, Object, etc.
|
||
"""
|
||
|
||
from .._core import Stub, AndroidOnlyError
|
||
import re as _re
|
||
import math as _py_math
|
||
import sys as _sys
|
||
import os as _os
|
||
import time as _time
|
||
import threading as _threading
|
||
import inspect as _inspect
|
||
import math
|
||
import random
|
||
import time
|
||
from datetime import datetime as _datetime
|
||
|
||
__all__ = [
|
||
"Object", "Throwable", "Exception", "RuntimeException", "Error",
|
||
"NullPointerException", "IllegalArgumentException", "IllegalStateException",
|
||
"IndexOutOfBoundsException", "ArrayIndexOutOfBoundsException",
|
||
"StringIndexOutOfBoundsException", "ClassCastException",
|
||
"UnsupportedOperationException", "ArithmeticException",
|
||
"NumberFormatException", "SecurityException",
|
||
"ConcurrentModificationException", "NegativeArraySizeException",
|
||
"NoSuchFieldException", "NoSuchMethodException", "InterruptedException",
|
||
"CloneNotSupportedException", "IllegalMonitorStateException",
|
||
"IllegalThreadStateException", "EnumConstantNotPresentException",
|
||
"TypeNotPresentException",
|
||
"String", "Integer", "Long", "Short", "Byte", "Float", "Double",
|
||
"Boolean", "Character", "Math", "StrictMath", "System",
|
||
"Thread", "ThreadLocal", "StringBuilder", "StringBuffer",
|
||
"Class", "Void", "VoidType",
|
||
"Stub", "Comparable", "CharSequence", "Iterable", "Appendable",
|
||
"Readable", "AutoCloseable", "Cloneable", "Runnable",
|
||
"StackTraceElement", "Number", "SuppressWarnings", "Deprecated",
|
||
"Override", "FunctionalInterface",
|
||
]
|
||
|
||
|
||
# ============================================================
|
||
# Interfaces
|
||
# ============================================================
|
||
|
||
class Comparable(Stub):
|
||
def compareTo(self, other):
|
||
raise NotImplementedError
|
||
|
||
class Iterable(Stub):
|
||
def iterator(self):
|
||
raise NotImplementedError
|
||
|
||
class AutoCloseable(Stub):
|
||
def close(self):
|
||
raise NotImplementedError
|
||
|
||
class Cloneable(Stub):
|
||
def clone(self):
|
||
return self.__class__()
|
||
|
||
class CharSequence(Stub):
|
||
def length(self):
|
||
raise NotImplementedError
|
||
def charAt(self, index):
|
||
raise NotImplementedError
|
||
def subSequence(self, start, end):
|
||
raise NotImplementedError
|
||
def toString(self):
|
||
raise NotImplementedError
|
||
|
||
class Appendable(Stub):
|
||
def append(self, c):
|
||
raise NotImplementedError
|
||
|
||
class Readable(Stub):
|
||
def read(self, cb):
|
||
raise NotImplementedError
|
||
|
||
class Runnable(Stub):
|
||
def run(self):
|
||
pass
|
||
|
||
|
||
# ============================================================
|
||
# Throwable hierarchy
|
||
# ============================================================
|
||
|
||
class Throwable(Exception, Stub):
|
||
def __init__(self, message=None, cause=None):
|
||
super().__init__(message or "")
|
||
self._detail_message = str(message) if message else None
|
||
self._cause = cause
|
||
self._stack_trace = []
|
||
self._suppressed = []
|
||
self._fill_in_stack()
|
||
|
||
def _fill_in_stack(self):
|
||
import traceback
|
||
stack = traceback.extract_stack()
|
||
self._stack_trace = [
|
||
StackTraceElement(
|
||
frame.filename, frame.name, frame.filename, frame.lineno, False
|
||
)
|
||
for frame in stack[:-1]
|
||
]
|
||
|
||
def getMessage(self):
|
||
return self._detail_message
|
||
|
||
def getLocalizedMessage(self):
|
||
return self._detail_message
|
||
|
||
def getCause(self):
|
||
return self._cause
|
||
|
||
def initCause(self, cause):
|
||
self._cause = cause
|
||
return self
|
||
|
||
def toString(self):
|
||
msg = self._detail_message or ""
|
||
return f"{self.__class__.__name__}: {msg}" if msg else self.__class__.__name__
|
||
|
||
def printStackTrace(self, file=None):
|
||
import traceback
|
||
if file is None:
|
||
file = _sys.stderr
|
||
traceback.print_exc(file=file)
|
||
|
||
def fillInStackTrace(self):
|
||
self._fill_in_stack()
|
||
return self
|
||
|
||
def getStackTrace(self):
|
||
return self._stack_trace
|
||
|
||
def setStackTrace(self, stack_trace):
|
||
self._stack_trace = stack_trace
|
||
|
||
def addSuppressed(self, exception):
|
||
self._suppressed.append(exception)
|
||
|
||
def getSuppressed(self):
|
||
return self._suppressed
|
||
|
||
def __str__(self):
|
||
return self.toString()
|
||
|
||
|
||
class Exception(Throwable):
|
||
pass
|
||
|
||
class RuntimeException(Exception):
|
||
pass
|
||
|
||
class Error(Throwable):
|
||
pass
|
||
|
||
|
||
class NullPointerException(RuntimeException):
|
||
pass
|
||
|
||
class IllegalArgumentException(RuntimeException):
|
||
pass
|
||
|
||
class IllegalStateException(RuntimeException):
|
||
pass
|
||
|
||
class IndexOutOfBoundsException(RuntimeException):
|
||
pass
|
||
|
||
class ArrayIndexOutOfBoundsException(IndexOutOfBoundsException):
|
||
pass
|
||
|
||
class StringIndexOutOfBoundsException(IndexOutOfBoundsException):
|
||
pass
|
||
|
||
class ClassCastException(RuntimeException):
|
||
pass
|
||
|
||
class UnsupportedOperationException(RuntimeException):
|
||
pass
|
||
|
||
class ArithmeticException(RuntimeException):
|
||
pass
|
||
|
||
class NumberFormatException(IllegalArgumentException):
|
||
pass
|
||
|
||
class SecurityException(RuntimeException):
|
||
pass
|
||
|
||
class ConcurrentModificationException(RuntimeException):
|
||
pass
|
||
|
||
class NegativeArraySizeException(RuntimeException):
|
||
pass
|
||
|
||
class NoSuchFieldException(Exception):
|
||
pass
|
||
|
||
class NoSuchMethodException(Exception):
|
||
pass
|
||
|
||
class InterruptedException(Exception):
|
||
pass
|
||
|
||
class CloneNotSupportedException(Exception):
|
||
pass
|
||
|
||
class IllegalMonitorStateException(RuntimeException):
|
||
pass
|
||
|
||
class IllegalThreadStateException(IllegalArgumentException):
|
||
pass
|
||
|
||
class EnumConstantNotPresentException(RuntimeException):
|
||
def __init__(self, e, constant):
|
||
super().__init__(f"{e}.{constant}")
|
||
self.enumType = e
|
||
self.constantName = constant
|
||
|
||
class TypeNotPresentException(RuntimeException):
|
||
def __init__(self, typeName, cause=None):
|
||
super().__init__(f"Type {typeName} not present", cause)
|
||
self.typeName = typeName
|
||
|
||
|
||
# ============================================================
|
||
# StackTraceElement
|
||
# ============================================================
|
||
|
||
class StackTraceElement(Stub):
|
||
def __init__(self, declaring_class, method_name, file_name, line_number, native_method):
|
||
super().__init__()
|
||
self._class = declaring_class
|
||
self._method = method_name
|
||
self._file = file_name
|
||
self._line = line_number
|
||
self._native = native_method
|
||
|
||
def getClassName(self):
|
||
return self._class
|
||
|
||
def getMethodName(self):
|
||
return self._method
|
||
|
||
def getFileName(self):
|
||
return self._file
|
||
|
||
def getLineNumber(self):
|
||
return self._line
|
||
|
||
def isNativeMethod(self):
|
||
return self._native
|
||
|
||
def toString(self):
|
||
return f"{self._class}.{self._method}({self._file}:{self._line})"
|
||
|
||
|
||
# ============================================================
|
||
# Object
|
||
# ============================================================
|
||
|
||
class Object(Stub):
|
||
def __init__(self):
|
||
super().__init__()
|
||
|
||
def getClass(self):
|
||
return self.__class__
|
||
|
||
def hashCode(self):
|
||
return hash(self) & 0x7FFFFFFF
|
||
|
||
def equals(self, other):
|
||
return self is other
|
||
|
||
def toString(self):
|
||
return f"{self.__class__.__name__}@{hex(id(self))}"
|
||
|
||
def notify(self):
|
||
pass
|
||
|
||
def notifyAll(self):
|
||
pass
|
||
|
||
def wait(self, timeout=None):
|
||
pass
|
||
|
||
def clone(self):
|
||
return self.__class__()
|
||
|
||
def finalize(self):
|
||
pass
|
||
|
||
|
||
# ============================================================
|
||
# String
|
||
# ============================================================
|
||
|
||
class String(CharSequence):
|
||
def __init__(self, value=None):
|
||
super().__init__()
|
||
if value is None:
|
||
self._str = ""
|
||
elif isinstance(value, bytes):
|
||
self._str = value.decode("utf-8", errors="replace")
|
||
else:
|
||
self._str = str(value)
|
||
|
||
def charAt(self, index):
|
||
return self._str[index]
|
||
|
||
def codePointAt(self, index):
|
||
return ord(self._str[index])
|
||
|
||
def codePointBefore(self, index):
|
||
return ord(self._str[index - 1]) if index > 0 else -1
|
||
|
||
def codePointCount(self, beginIndex, endIndex):
|
||
return endIndex - beginIndex
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, String):
|
||
return (self._str > other._str) - (self._str < other._str)
|
||
return -1
|
||
|
||
def compareToIgnoreCase(self, other):
|
||
if isinstance(other, String):
|
||
return (self._str.lower() > other._str.lower()) - (self._str.lower() < other._str.lower())
|
||
return -1
|
||
|
||
def concat(self, s):
|
||
return String(self._str + str(s))
|
||
|
||
def contains(self, s):
|
||
return str(s) in self._str
|
||
|
||
def contentEquals(self, cs):
|
||
return self._str == str(cs)
|
||
|
||
def endsWith(self, suffix):
|
||
return self._str.endswith(suffix)
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, String):
|
||
return self._str == other._str
|
||
return False
|
||
|
||
def equalsIgnoreCase(self, other):
|
||
if isinstance(other, String):
|
||
return self._str.lower() == other._str.lower()
|
||
return False
|
||
|
||
def getBytes(self, charset="UTF-8"):
|
||
return self._str.encode(charset, errors="replace")
|
||
|
||
def hashCode(self) -> int:
|
||
h = 0
|
||
for i in range(len(self._str)):
|
||
h = 31 * h + ord(self._str[i])
|
||
return h & 0x7FFFFFFF
|
||
|
||
def indexOf(self, ch, fromIndex=0):
|
||
if isinstance(ch, int):
|
||
ch = chr(ch)
|
||
return self._str.index(str(ch), fromIndex) if str(ch) in self._str[fromIndex:] else -1
|
||
|
||
def intern(self):
|
||
return self
|
||
|
||
def isEmpty(self):
|
||
return len(self._str) == 0
|
||
|
||
def lastIndexOf(self, ch, fromIndex=None):
|
||
if isinstance(ch, int):
|
||
ch = chr(ch)
|
||
if fromIndex is None:
|
||
fromIndex = len(self._str) - 1
|
||
search_in = self._str[:fromIndex + 1]
|
||
return search_in.rfind(str(ch)) if str(ch) in search_in else -1
|
||
|
||
def length(self):
|
||
return len(self._str)
|
||
|
||
def matches(self, regex):
|
||
return bool(_re.fullmatch(regex, self._str))
|
||
|
||
def offsetByCodePoints(self, index, codePointOffset):
|
||
return index + codePointOffset
|
||
|
||
def regionMatches(self, ignoreCase, toffset, other, ooffset, length):
|
||
if ignoreCase:
|
||
return self._str[toffset:toffset+length].lower() == other._str[ooffset:ooffset+length].lower()
|
||
return self._str[toffset:toffset+length] == other._str[ooffset:ooffset+length]
|
||
|
||
def replace(self, oldChar, newChar):
|
||
if isinstance(oldChar, int):
|
||
oldChar = chr(oldChar)
|
||
if isinstance(newChar, int):
|
||
newChar = chr(newChar)
|
||
return String(self._str.replace(oldChar, newChar))
|
||
|
||
def replaceAll(self, regex, replacement):
|
||
return String(_re.sub(regex, replacement, self._str))
|
||
|
||
def replaceFirst(self, regex, replacement):
|
||
return String(_re.sub(regex, replacement, self._str, count=1))
|
||
|
||
def split(self, regex, limit=0):
|
||
if limit <= 0:
|
||
parts = _re.split(regex, self._str)
|
||
if limit == 0:
|
||
while parts and parts[-1] == "":
|
||
parts.pop()
|
||
else:
|
||
parts = _re.split(regex, self._str, maxsplit=limit - 1)
|
||
while len(parts) < limit:
|
||
parts.append("")
|
||
return [String(p) for p in parts]
|
||
|
||
def startsWith(self, prefix):
|
||
return self._str.startswith(prefix)
|
||
|
||
def substring(self, beginIndex, endIndex=None):
|
||
if endIndex is None:
|
||
return String(self._str[beginIndex:])
|
||
return String(self._str[beginIndex:endIndex])
|
||
|
||
def toCharArray(self):
|
||
return list(self._str)
|
||
|
||
def toLowerCase(self):
|
||
return String(self._str.lower())
|
||
|
||
def toUpperCase(self):
|
||
return String(self._str.upper())
|
||
|
||
def trim(self):
|
||
return String(self._str.strip())
|
||
|
||
def strip(self):
|
||
return String(self._str.strip())
|
||
|
||
def stripLeading(self):
|
||
return String(self._str.lstrip())
|
||
|
||
def stripTrailing(self):
|
||
return String(self._str.rstrip())
|
||
|
||
def isBlank(self):
|
||
return self._str.strip() == ""
|
||
|
||
def repeat(self, count):
|
||
return String(self._str * count)
|
||
|
||
def lines(self):
|
||
from .util import ArrayList
|
||
result = ArrayList()
|
||
for line in self._str.splitlines():
|
||
result.add(String(line))
|
||
return result
|
||
|
||
def subSequence(self, start, end):
|
||
return self.substring(start, end)
|
||
|
||
def getChars(self, srcBegin, srcEnd, dst, dstBegin):
|
||
chars = self._str[srcBegin:srcEnd]
|
||
for i, c in enumerate(chars):
|
||
dst[dstBegin + i] = c
|
||
|
||
def chars(self):
|
||
return [ord(c) for c in self._str]
|
||
|
||
def formatted(self, *args):
|
||
return String(self._str.format(*args))
|
||
|
||
def translateEscapes(self):
|
||
result = []
|
||
s = self._str
|
||
i = 0
|
||
n = len(s)
|
||
while i < n:
|
||
c = s[i]
|
||
if c == '\\' and i + 1 < n:
|
||
nxt = s[i + 1]
|
||
if nxt == 'b':
|
||
result.append('\b'); i += 2
|
||
elif nxt == 't':
|
||
result.append('\t'); i += 2
|
||
elif nxt == 'n':
|
||
result.append('\n'); i += 2
|
||
elif nxt == 'f':
|
||
result.append('\f'); i += 2
|
||
elif nxt == 'r':
|
||
result.append('\r'); i += 2
|
||
elif nxt == 's':
|
||
result.append(' '); i += 2
|
||
elif nxt == '"':
|
||
result.append('"'); i += 2
|
||
elif nxt == "'":
|
||
result.append("'"); i += 2
|
||
elif nxt == '\\':
|
||
result.append('\\'); i += 2
|
||
elif nxt in '01234567':
|
||
octal = nxt
|
||
i += 2
|
||
max_digits = 2 if nxt in '0123' else 1
|
||
while len(octal) < max_digits + 1 and i < n and s[i] in '01234567':
|
||
octal += s[i]
|
||
i += 1
|
||
result.append(chr(int(octal, 8)))
|
||
elif nxt == '\n':
|
||
i += 2
|
||
elif nxt == '\r':
|
||
i += 2
|
||
if i < n and s[i] == '\n':
|
||
i += 1
|
||
else:
|
||
result.append(nxt); i += 2
|
||
else:
|
||
result.append(c); i += 1
|
||
return String(''.join(result))
|
||
|
||
@staticmethod
|
||
def valueOf(obj):
|
||
return String(str(obj))
|
||
|
||
@staticmethod
|
||
def copyValueOf(data, offset=0, count=None):
|
||
if count is None:
|
||
return String("".join(data))
|
||
return String("".join(data[offset:offset+count]))
|
||
|
||
@staticmethod
|
||
def format(fmt, *args):
|
||
return String(str(fmt) % args if args else str(fmt))
|
||
|
||
@staticmethod
|
||
def join(delimiter, *elements):
|
||
if hasattr(elements[0], '__iter__') and not isinstance(elements[0], (str, bytes)):
|
||
elements = elements[0]
|
||
return String(str(delimiter).join(str(s) for s in elements))
|
||
|
||
def toString(self):
|
||
return self._str
|
||
|
||
def __str__(self):
|
||
return self._str
|
||
|
||
def __repr__(self):
|
||
return f"String({self._str!r})"
|
||
|
||
def __len__(self):
|
||
return len(self._str)
|
||
|
||
def __getitem__(self, idx):
|
||
return self._str[idx]
|
||
|
||
def __add__(self, other):
|
||
return String(self._str + str(other))
|
||
|
||
def __eq__(self, other):
|
||
if isinstance(other, String):
|
||
return self._str == other._str
|
||
return NotImplemented
|
||
|
||
|
||
# ============================================================
|
||
# Number
|
||
# ============================================================
|
||
|
||
class Number(Stub):
|
||
def intValue(self):
|
||
raise NotImplementedError
|
||
def longValue(self):
|
||
raise NotImplementedError
|
||
def floatValue(self):
|
||
raise NotImplementedError
|
||
def doubleValue(self):
|
||
raise NotImplementedError
|
||
def byteValue(self):
|
||
return self.intValue() & 0xFF
|
||
def shortValue(self):
|
||
return self.intValue() & 0xFFFF
|
||
|
||
|
||
# ============================================================
|
||
# Integer
|
||
# ============================================================
|
||
|
||
class Integer(Number, Comparable):
|
||
MAX_VALUE = 2147483647
|
||
MIN_VALUE = -2147483648
|
||
SIZE = 32
|
||
BYTES = 4
|
||
TYPE = int
|
||
|
||
def __init__(self, value=0):
|
||
super().__init__()
|
||
if isinstance(value, str):
|
||
self._value = Integer.parseInt(value)
|
||
else:
|
||
self._value = int(value)
|
||
|
||
@staticmethod
|
||
def parseInt(s, radix=10):
|
||
if isinstance(s, String):
|
||
s = str(s)
|
||
if radix == 10:
|
||
return int(str(s))
|
||
return int(str(s), radix)
|
||
|
||
@staticmethod
|
||
def toString(i, radix=10):
|
||
if radix == 10:
|
||
return String(str(i))
|
||
if radix == 2:
|
||
return String(bin(i)[2:])
|
||
if radix == 8:
|
||
return String(oct(i)[2:])
|
||
if radix == 16:
|
||
return String(hex(i)[2:])
|
||
return String(str(i))
|
||
|
||
@staticmethod
|
||
def toBinaryString(i):
|
||
if i >= 0:
|
||
return String(bin(i)[2:])
|
||
return String(bin(i & 0xFFFFFFFF)[2:])
|
||
|
||
@staticmethod
|
||
def toHexString(i):
|
||
if i >= 0:
|
||
return String(hex(i)[2:])
|
||
return String(hex(i & 0xFFFFFFFF)[2:])
|
||
|
||
@staticmethod
|
||
def toOctalString(i):
|
||
if i >= 0:
|
||
return String(oct(i)[2:])
|
||
return String(oct(i & 0xFFFFFFFF)[2:])
|
||
|
||
@staticmethod
|
||
def valueOf(i, radix=10):
|
||
if isinstance(i, str):
|
||
return Integer(Integer.parseInt(i, radix))
|
||
return Integer(i)
|
||
|
||
def intValue(self):
|
||
return self._value
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, Integer):
|
||
return (self._value > other._value) - (self._value < other._value)
|
||
return -1
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, Integer):
|
||
return self._value == other._value
|
||
return False
|
||
|
||
def byteValue(self):
|
||
return self._value & 0xFF
|
||
|
||
def shortValue(self):
|
||
return self._value & 0xFFFF
|
||
|
||
def longValue(self):
|
||
return self._value
|
||
|
||
def floatValue(self):
|
||
return float(self._value)
|
||
|
||
def doubleValue(self):
|
||
return float(self._value)
|
||
|
||
@staticmethod
|
||
def bitCount(i):
|
||
return bin(i & 0xFFFFFFFF).count("1")
|
||
|
||
@staticmethod
|
||
def highestOneBit(i):
|
||
if i == 0:
|
||
return 0
|
||
return 1 << (i.bit_length() - 1)
|
||
|
||
@staticmethod
|
||
def lowestOneBit(i):
|
||
return i & -i
|
||
|
||
@staticmethod
|
||
def numberOfLeadingZeros(i):
|
||
if i == 0:
|
||
return 32
|
||
return 32 - i.bit_length()
|
||
|
||
@staticmethod
|
||
def numberOfTrailingZeros(i):
|
||
if i == 0:
|
||
return 32
|
||
return (i & -i).bit_length() - 1
|
||
|
||
@staticmethod
|
||
def reverse(i):
|
||
v = i & 0xFFFFFFFF
|
||
result = 0
|
||
for _ in range(32):
|
||
result = (result << 1) | (v & 1)
|
||
v >>= 1
|
||
return result
|
||
|
||
@staticmethod
|
||
def reverseBytes(i):
|
||
v = i & 0xFFFFFFFF
|
||
return ((v >> 24) & 0xFF) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | ((v << 24) & 0xFF000000)
|
||
|
||
@staticmethod
|
||
def rotateLeft(i, distance):
|
||
v = i & 0xFFFFFFFF
|
||
d = distance & 31
|
||
return ((v << d) | (v >> (32 - d))) & 0xFFFFFFFF
|
||
|
||
@staticmethod
|
||
def rotateRight(i, distance):
|
||
v = i & 0xFFFFFFFF
|
||
d = distance & 31
|
||
return ((v >> d) | (v << (32 - d))) & 0xFFFFFFFF
|
||
|
||
@staticmethod
|
||
def signum(i):
|
||
if i > 0:
|
||
return 1
|
||
if i < 0:
|
||
return -1
|
||
return 0
|
||
|
||
@staticmethod
|
||
def decode(nm):
|
||
if nm.startswith("0x") or nm.startswith("0X"):
|
||
return Integer(int(nm, 16))
|
||
if nm.startswith("0") and len(nm) > 1:
|
||
return Integer(int(nm, 8))
|
||
if nm.startswith("#"):
|
||
return Integer(int(nm[1:], 16))
|
||
return Integer(int(nm))
|
||
|
||
@staticmethod
|
||
def getInteger(nm, val=None):
|
||
env_val = _os.environ.get(nm)
|
||
if env_val is not None:
|
||
return Integer(int(env_val))
|
||
return Integer(val) if val is not None else None
|
||
|
||
def toString(self):
|
||
return String(str(self._value))
|
||
|
||
def __str__(self):
|
||
return str(self._value)
|
||
|
||
def __int__(self):
|
||
return self._value
|
||
|
||
|
||
# ============================================================
|
||
# Long
|
||
# ============================================================
|
||
|
||
class Long(Number, Comparable):
|
||
MAX_VALUE = 9223372036854775807
|
||
MIN_VALUE = -9223372036854775808
|
||
SIZE = 64
|
||
BYTES = 8
|
||
TYPE = int
|
||
|
||
def __init__(self, value=0):
|
||
super().__init__()
|
||
if isinstance(value, str):
|
||
self._value = Long.parseLong(value)
|
||
else:
|
||
self._value = int(value)
|
||
|
||
@staticmethod
|
||
def parseLong(s, radix=10):
|
||
if isinstance(s, String):
|
||
s = str(s)
|
||
if radix == 10:
|
||
return int(str(s))
|
||
return int(str(s), radix)
|
||
|
||
@staticmethod
|
||
def toString(i, radix=10):
|
||
if radix == 10:
|
||
return String(str(i))
|
||
return String(str(i))
|
||
|
||
@staticmethod
|
||
def toBinaryString(i):
|
||
if i >= 0:
|
||
return String(bin(i)[2:])
|
||
return String(bin(i & 0xFFFFFFFFFFFFFFFF)[2:])
|
||
|
||
@staticmethod
|
||
def toHexString(i):
|
||
if i >= 0:
|
||
return String(hex(i)[2:])
|
||
return String(hex(i & 0xFFFFFFFFFFFFFFFF)[2:])
|
||
|
||
@staticmethod
|
||
def toOctalString(i):
|
||
if i >= 0:
|
||
return String(oct(i)[2:])
|
||
return String(oct(i & 0xFFFFFFFFFFFFFFFF)[2:])
|
||
|
||
@staticmethod
|
||
def valueOf(i, radix=10):
|
||
if isinstance(i, str):
|
||
return Long(Long.parseLong(i, radix))
|
||
return Long(i)
|
||
|
||
def longValue(self):
|
||
return self._value
|
||
|
||
def intValue(self):
|
||
return int(self._value)
|
||
|
||
def floatValue(self):
|
||
return float(self._value)
|
||
|
||
def doubleValue(self):
|
||
return float(self._value)
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, Long):
|
||
return (self._value > other._value) - (self._value < other._value)
|
||
return -1
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, Long):
|
||
return self._value == other._value
|
||
return False
|
||
|
||
def toString(self):
|
||
return String(str(self._value))
|
||
|
||
def __str__(self):
|
||
return str(self._value)
|
||
|
||
|
||
# ============================================================
|
||
# Short, Byte
|
||
# ============================================================
|
||
|
||
class Short(Number, Comparable):
|
||
MAX_VALUE = 32767
|
||
MIN_VALUE = -32768
|
||
SIZE = 16
|
||
BYTES = 2
|
||
TYPE = int
|
||
|
||
def __init__(self, value=0):
|
||
super().__init__()
|
||
if isinstance(value, str):
|
||
self._value = Short.parseShort(value)
|
||
else:
|
||
self._value = int(value) & 0xFFFF
|
||
|
||
@staticmethod
|
||
def parseShort(s, radix=10):
|
||
return int(str(s), radix)
|
||
|
||
@staticmethod
|
||
def valueOf(i, radix=10):
|
||
if isinstance(i, str):
|
||
return Short(Short.parseShort(i, radix))
|
||
return Short(i)
|
||
|
||
def shortValue(self):
|
||
return self._value
|
||
|
||
def intValue(self):
|
||
return self._value
|
||
|
||
def longValue(self):
|
||
return self._value
|
||
|
||
def floatValue(self):
|
||
return float(self._value)
|
||
|
||
def doubleValue(self):
|
||
return float(self._value)
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, Short):
|
||
return (self._value > other._value) - (self._value < other._value)
|
||
return -1
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, Short):
|
||
return self._value == other._value
|
||
return False
|
||
|
||
def toString(self):
|
||
return String(str(self._value))
|
||
|
||
|
||
class Byte(Number, Comparable):
|
||
MAX_VALUE = 127
|
||
MIN_VALUE = -128
|
||
SIZE = 8
|
||
BYTES = 1
|
||
TYPE = int
|
||
|
||
def __init__(self, value=0):
|
||
super().__init__()
|
||
if isinstance(value, str):
|
||
self._value = Byte.parseByte(value)
|
||
else:
|
||
self._value = int(value) & 0xFF
|
||
if self._value > 127:
|
||
self._value -= 256
|
||
|
||
@staticmethod
|
||
def parseByte(s, radix=10):
|
||
return int(str(s), radix)
|
||
|
||
@staticmethod
|
||
def valueOf(i, radix=10):
|
||
if isinstance(i, str):
|
||
return Byte(Byte.parseByte(i, radix))
|
||
return Byte(i)
|
||
|
||
def byteValue(self):
|
||
return self._value
|
||
|
||
def intValue(self):
|
||
return self._value
|
||
|
||
def longValue(self):
|
||
return self._value
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, Byte):
|
||
return (self._value > other._value) - (self._value < other._value)
|
||
return -1
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, Byte):
|
||
return self._value == other._value
|
||
return False
|
||
|
||
def toString(self):
|
||
return String(str(self._value))
|
||
|
||
|
||
# ============================================================
|
||
# Float
|
||
# ============================================================
|
||
|
||
class Float(Number, Comparable):
|
||
MAX_VALUE = 3.4028235e38
|
||
MIN_VALUE = 1.4e-45
|
||
MIN_NORMAL = 1.17549435e-38
|
||
MAX_EXPONENT = 127
|
||
MIN_EXPONENT = -126
|
||
SIZE = 32
|
||
BYTES = 4
|
||
TYPE = float
|
||
NaN = float("nan")
|
||
POSITIVE_INFINITY = float("inf")
|
||
NEGATIVE_INFINITY = float("-inf")
|
||
|
||
def __init__(self, value=0.0):
|
||
super().__init__()
|
||
if isinstance(value, str):
|
||
self._value = Float.parseFloat(value)
|
||
else:
|
||
self._value = float(value)
|
||
|
||
@staticmethod
|
||
def parseFloat(s):
|
||
if isinstance(s, String):
|
||
s = str(s)
|
||
s = str(s).strip()
|
||
if s == "NaN":
|
||
return float("nan")
|
||
if s == "Infinity" or s == "Inf":
|
||
return float("inf")
|
||
if s == "-Infinity" or s == "-Inf":
|
||
return float("-inf")
|
||
return float(s)
|
||
|
||
@staticmethod
|
||
def toString(f):
|
||
return String(str(f))
|
||
|
||
@staticmethod
|
||
def valueOf(f):
|
||
if isinstance(f, str):
|
||
return Float(Float.parseFloat(f))
|
||
return Float(f)
|
||
|
||
def floatValue(self):
|
||
return self._value
|
||
|
||
def intValue(self):
|
||
return int(self._value)
|
||
|
||
def longValue(self):
|
||
return int(self._value)
|
||
|
||
def doubleValue(self):
|
||
return float(self._value)
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, Float):
|
||
a, b = self._value, other._value
|
||
if _py_math.isnan(a) and _py_math.isnan(b):
|
||
return 0
|
||
if _py_math.isnan(a):
|
||
return 1
|
||
if _py_math.isnan(b):
|
||
return -1
|
||
return (a > b) - (a < b)
|
||
return -1
|
||
|
||
def isNaN(self):
|
||
return _py_math.isnan(self._value)
|
||
|
||
def isInfinite(self):
|
||
return _py_math.isinf(self._value)
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, Float):
|
||
if _py_math.isnan(self._value) and _py_math.isnan(other._value):
|
||
return True
|
||
return self._value == other._value
|
||
return False
|
||
|
||
def hashCode(self):
|
||
return _struct.pack(">f", self._value)
|
||
|
||
def toString(self):
|
||
return String(str(self._value))
|
||
|
||
def __str__(self):
|
||
return str(self._value)
|
||
|
||
import struct as _struct
|
||
|
||
|
||
# ============================================================
|
||
# Double
|
||
# ============================================================
|
||
|
||
class Double(Number, Comparable):
|
||
MAX_VALUE = 1.7976931348623157e308
|
||
MIN_VALUE = 4.9e-324
|
||
MIN_NORMAL = 2.2250738585072014e-308
|
||
MAX_EXPONENT = 1023
|
||
MIN_EXPONENT = -1022
|
||
SIZE = 64
|
||
BYTES = 8
|
||
TYPE = float
|
||
NaN = float("nan")
|
||
POSITIVE_INFINITY = float("inf")
|
||
NEGATIVE_INFINITY = float("-inf")
|
||
|
||
def __init__(self, value=0.0):
|
||
super().__init__()
|
||
if isinstance(value, str):
|
||
self._value = Double.parseDouble(value)
|
||
else:
|
||
self._value = float(value)
|
||
|
||
@staticmethod
|
||
def parseDouble(s):
|
||
if isinstance(s, String):
|
||
s = str(s)
|
||
s = str(s).strip()
|
||
if s == "NaN":
|
||
return float("nan")
|
||
if s == "Infinity" or s == "Inf":
|
||
return float("inf")
|
||
if s == "-Infinity" or s == "-Inf":
|
||
return float("-inf")
|
||
return float(s)
|
||
|
||
@staticmethod
|
||
def toString(d):
|
||
return String(str(d))
|
||
|
||
@staticmethod
|
||
def valueOf(d):
|
||
if isinstance(d, str):
|
||
return Double(Double.parseDouble(d))
|
||
return Double(d)
|
||
|
||
def doubleValue(self):
|
||
return self._value
|
||
|
||
def intValue(self):
|
||
return int(self._value)
|
||
|
||
def longValue(self):
|
||
return int(self._value)
|
||
|
||
def floatValue(self):
|
||
return float(self._value)
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, Double):
|
||
a, b = self._value, other._value
|
||
if _py_math.isnan(a) and _py_math.isnan(b):
|
||
return 0
|
||
if _py_math.isnan(a):
|
||
return 1
|
||
if _py_math.isnan(b):
|
||
return -1
|
||
return (a > b) - (a < b)
|
||
return -1
|
||
|
||
def isNaN(self):
|
||
return _py_math.isnan(self._value)
|
||
|
||
def isInfinite(self):
|
||
return _py_math.isinf(self._value)
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, Double):
|
||
if _py_math.isnan(self._value) and _py_math.isnan(other._value):
|
||
return True
|
||
return self._value == other._value
|
||
return False
|
||
|
||
def toString(self):
|
||
return String(str(self._value))
|
||
|
||
def __str__(self):
|
||
return str(self._value)
|
||
|
||
|
||
# ============================================================
|
||
# Boolean
|
||
# ============================================================
|
||
|
||
class Boolean(Stub):
|
||
TRUE = "true"
|
||
FALSE = "false"
|
||
TYPE = bool
|
||
|
||
def __init__(self, value=False):
|
||
super().__init__()
|
||
if isinstance(value, str):
|
||
self._value = Boolean.parseBoolean(value)
|
||
elif isinstance(value, bool):
|
||
self._value = value
|
||
else:
|
||
self._value = bool(value)
|
||
|
||
@staticmethod
|
||
def parseBoolean(s):
|
||
return str(s).lower() == "true"
|
||
|
||
@staticmethod
|
||
def toString(b):
|
||
return String(str(b).lower())
|
||
|
||
@staticmethod
|
||
def valueOf(b):
|
||
if isinstance(b, str):
|
||
return Boolean(Boolean.parseBoolean(b))
|
||
return Boolean(b)
|
||
|
||
def booleanValue(self):
|
||
return self._value
|
||
|
||
@staticmethod
|
||
def logicalAnd(a, b):
|
||
return a and b
|
||
|
||
@staticmethod
|
||
def logicalOr(a, b):
|
||
return a or b
|
||
|
||
@staticmethod
|
||
def logicalXor(a, b):
|
||
return a ^ b
|
||
|
||
def compareTo(self, other):
|
||
if isinstance(other, Boolean):
|
||
return (self._value > other._value) - (self._value < other._value)
|
||
return -1
|
||
|
||
def equals(self, other):
|
||
if isinstance(other, Boolean):
|
||
return self._value == other._value
|
||
return False
|
||
|
||
def toString(self):
|
||
return String("true" if self._value else "false")
|
||
|
||
def __str__(self):
|
||
return "true" if self._value else "false"
|
||
|
||
def __bool__(self):
|
||
return self._value
|
||
|
||
|
||
# ============================================================
|
||
# Character
|
||
# ============================================================
|
||
|
||
class Character(Stub):
|
||
MAX_VALUE = 65535
|
||
MIN_VALUE = 0
|
||
SIZE = 16
|
||
BYTES = 2
|
||
TYPE = str
|
||
|
||
def __init__(self, value=""):
|
||
super().__init__()
|
||
if isinstance(value, int):
|
||
self._value = chr(value)
|
||
else:
|
||
self._value = str(value)[0] if value else ""
|
||
|
||
def charValue(self):
|
||
return self._value
|
||
|
||
@staticmethod
|
||
def isDigit(ch):
|
||
return str(ch).isdigit()
|
||
|
||
@staticmethod
|
||
def isLetter(ch):
|
||
return str(ch).isalpha()
|
||
|
||
@staticmethod
|
||
def isLetterOrDigit(ch):
|
||
return str(ch).isalnum()
|
||
|
||
@staticmethod
|
||
def isLowerCase(ch):
|
||
return str(ch).islower()
|
||
|
||
@staticmethod
|
||
def isUpperCase(ch):
|
||
return str(ch).isupper()
|
||
|
||
@staticmethod
|
||
def isWhitespace(ch):
|
||
return str(ch).isspace()
|
||
|
||
@staticmethod
|
||
def isSpaceChar(ch):
|
||
return str(ch) in " \t\n\r\f\u000B"
|
||
|
||
@staticmethod
|
||
def isISOControl(ch):
|
||
c = ord(ch) if isinstance(ch, str) else ch
|
||
return c < 0x20 or c == 0x7F
|
||
|
||
@staticmethod
|
||
def isJavaIdentifierPart(ch):
|
||
c = str(ch)
|
||
return c.isalnum() or c == "_" or c == "$"
|
||
|
||
@staticmethod
|
||
def isJavaIdentifierStart(ch):
|
||
c = str(ch)
|
||
return c.isalpha() or c == "_" or c == "$"
|
||
|
||
@staticmethod
|
||
def isJavaLetter(ch):
|
||
return Character.isJavaIdentifierStart(ch)
|
||
|
||
@staticmethod
|
||
def isJavaLetterOrDigit(ch):
|
||
return Character.isJavaIdentifierPart(ch)
|
||
|
||
@staticmethod
|
||
def toLowerCase(ch):
|
||
return str(ch).lower()
|
||
|
||
@staticmethod
|
||
def toUpperCase(ch):
|
||
return str(ch).upper()
|
||
|
||
@staticmethod
|
||
def toTitleCase(ch):
|
||
return str(ch).upper()
|
||
|
||
@staticmethod
|
||
def getNumericValue(ch):
|
||
s = str(ch)
|
||
if s.isdigit():
|
||
return int(s)
|
||
if "a" <= s <= "z":
|
||
return ord(s) - ord("a") + 10
|
||
if "A" <= s <= "Z":
|
||
return ord(s) - ord("A") + 10
|
||
return -1
|
||
|
||
@staticmethod
|
||
def digit(ch, radix):
|
||
val = Character.getNumericValue(ch)
|
||
return val if val < radix else -1
|
||
|
||
@staticmethod
|
||
def forDigit(digit, radix):
|
||
if digit >= radix:
|
||
return "\0"
|
||
return str(digit) if digit < 10 else chr(ord("a") + digit - 10)
|
||
|
||
@staticmethod
|
||
def getType(ch):
|
||
return 0
|
||
|
||
@staticmethod
|
||
def getDirectionality(ch):
|
||
return 0
|
||
|
||
@staticmethod
|
||
def getName(ch):
|
||
return f"CHARACTER {ord(ch)}"
|
||
|
||
@staticmethod
|
||
def charCount(codePoint):
|
||
return 1 if codePoint < 0x10000 else 2
|
||
|
||
@staticmethod
|
||
def isBmpCodePoint(cp):
|
||
return cp <= 0xFFFF
|
||
|
||
@staticmethod
|
||
def isHighSurrogate(ch):
|
||
c = ord(ch) if isinstance(ch, str) else ch
|
||
return 0xD800 <= c <= 0xDBFF
|
||
|
||
@staticmethod
|
||
def isLowSurrogate(ch):
|
||
c = ord(ch) if isinstance(ch, str) else ch
|
||
return 0xDC00 <= c <= 0xDFFF
|
||
|
||
@staticmethod
|
||
def isSupplementaryCodePoint(cp):
|
||
return 0x10000
|
||
|
||
|
||
class Math:
|
||
"""java.lang.Math — 数学运算"""
|
||
E = 2.718281828459045
|
||
PI = 3.141592653589793
|
||
|
||
@staticmethod
|
||
def abs(a): return abs(a)
|
||
@staticmethod
|
||
def ceil(a): return int(math.ceil(a))
|
||
@staticmethod
|
||
def floor(a): return int(math.floor(a))
|
||
@staticmethod
|
||
def round(a: float) -> int:
|
||
return int(math.floor(a + 0.5))
|
||
@staticmethod
|
||
def min(a, b): return a if a < b else b
|
||
@staticmethod
|
||
def max(a, b): return a if a > b else b
|
||
@staticmethod
|
||
def sqrt(a): return math.sqrt(a)
|
||
@staticmethod
|
||
def cbrt(a): return math.cbrt(a)
|
||
@staticmethod
|
||
def pow(a, b): return math.pow(a, b)
|
||
@staticmethod
|
||
def exp(a): return math.exp(a)
|
||
@staticmethod
|
||
def log(a): return math.log(a)
|
||
@staticmethod
|
||
def log10(a): return math.log10(a)
|
||
@staticmethod
|
||
def sin(a): return math.sin(a)
|
||
@staticmethod
|
||
def cos(a): return math.cos(a)
|
||
@staticmethod
|
||
def tan(a): return math.tan(a)
|
||
@staticmethod
|
||
def asin(a): return math.asin(a)
|
||
@staticmethod
|
||
def acos(a): return math.acos(a)
|
||
@staticmethod
|
||
def atan(a): return math.atan(a)
|
||
@staticmethod
|
||
def atan2(y, x): return math.atan2(y, x)
|
||
@staticmethod
|
||
def toDegrees(r): return math.degrees(r)
|
||
@staticmethod
|
||
def toRadians(d): return math.radians(d)
|
||
@staticmethod
|
||
def hypot(x, y): return math.hypot(x, y)
|
||
@staticmethod
|
||
def sinh(x): return math.sinh(x)
|
||
@staticmethod
|
||
def cosh(x): return math.cosh(x)
|
||
@staticmethod
|
||
def tanh(x): return math.tanh(x)
|
||
@staticmethod
|
||
def signum(x): return 0.0 if x == 0 else (1.0 if x > 0 else -1.0)
|
||
@staticmethod
|
||
def random(): return random.random()
|
||
@staticmethod
|
||
def addExact(x, y):
|
||
result = x + y
|
||
if (x > 0 and y > 0 and result < 0) or (x < 0 and y < 0 and result > 0):
|
||
raise ArithmeticError("integer overflow")
|
||
return result
|
||
@staticmethod
|
||
def copySign(m, s): return abs(m) * (1 if s >= 0 else -1)
|
||
@staticmethod
|
||
def floorDiv(x, y): return x // y if (x ^ y) >= 0 else -(abs(x) // abs(y))
|
||
@staticmethod
|
||
def floorMod(x, y): return x - Math.floorDiv(x, y) * y
|
||
|
||
|
||
class StrictMath(Math):
|
||
"""java.lang.StrictMath"""
|
||
pass
|
||
|
||
|
||
class _Console:
|
||
"""java.io.Console 简化实现,供 System.console() 使用"""
|
||
def readLine(self, fmt=None, *args):
|
||
if fmt is not None:
|
||
try:
|
||
_sys.stdout.write(str(fmt) % args if args else str(fmt))
|
||
except Exception:
|
||
_sys.stdout.write(str(fmt))
|
||
_sys.stdout.flush()
|
||
line = _sys.stdin.readline()
|
||
if line == "":
|
||
return None
|
||
return line.rstrip("\r\n")
|
||
|
||
def readPassword(self, fmt=None, *args):
|
||
import getpass
|
||
if fmt is not None:
|
||
try:
|
||
_sys.stderr.write(str(fmt) % args if args else str(fmt))
|
||
except Exception:
|
||
_sys.stderr.write(str(fmt))
|
||
_sys.stderr.flush()
|
||
pwd = getpass.getpass("")
|
||
return list(pwd) if pwd is not None else None
|
||
|
||
def printf(self, fmt, *args):
|
||
try:
|
||
_sys.stdout.write(str(fmt) % args if args else str(fmt))
|
||
except Exception:
|
||
_sys.stdout.write(str(fmt))
|
||
return self
|
||
|
||
def format(self, fmt, *args):
|
||
try:
|
||
_sys.stdout.write(str(fmt) % args if args else str(fmt))
|
||
except Exception:
|
||
_sys.stdout.write(str(fmt))
|
||
return self
|
||
|
||
def flush(self):
|
||
_sys.stdout.flush()
|
||
|
||
def writer(self):
|
||
return _sys.stdout
|
||
|
||
def reader(self):
|
||
return _sys.stdin
|
||
|
||
|
||
class System:
|
||
"""java.lang.System"""
|
||
_console = None
|
||
@staticmethod
|
||
def currentTimeMillis(): return int(time.time() * 1000)
|
||
@staticmethod
|
||
def nanoTime(): return time.perf_counter_ns()
|
||
@staticmethod
|
||
def arraycopy(src, srcPos, dest, destPos, length):
|
||
if isinstance(src, (list, bytearray)):
|
||
dest[destPos:destPos+length] = src[srcPos:srcPos+length]
|
||
else:
|
||
raise TypeError("Unsupported type for arraycopy")
|
||
@staticmethod
|
||
def identityHashCode(obj): return id(obj) & 0x7FFFFFFF
|
||
@staticmethod
|
||
def gc(): pass
|
||
@staticmethod
|
||
def exit(status): raise SystemExit(status)
|
||
@staticmethod
|
||
def getProperty(key, default=None):
|
||
import os
|
||
return os.environ.get(key, default)
|
||
@staticmethod
|
||
def setProperty(key, value):
|
||
import os
|
||
os.environ[key] = value
|
||
return value
|
||
@staticmethod
|
||
def clearProperty(key):
|
||
return _os.environ.pop(key, None)
|
||
@staticmethod
|
||
def getenv(name=None):
|
||
if name is None:
|
||
return dict(_os.environ)
|
||
return _os.environ.get(name)
|
||
@staticmethod
|
||
def console():
|
||
if System._console is None:
|
||
System._console = _Console()
|
||
return System._console
|
||
@staticmethod
|
||
def setIn(in_stream):
|
||
System.in_ = in_stream
|
||
@staticmethod
|
||
def setOut(out_stream):
|
||
System.out = out_stream
|
||
@staticmethod
|
||
def setErr(err_stream):
|
||
System.err = err_stream
|
||
@staticmethod
|
||
def lineSeparator(): return _os.linesep
|
||
in_ = _sys.stdin
|
||
out = _sys.stdout
|
||
err = _sys.stderr
|
||
|
||
|
||
class Thread(Runnable):
|
||
"""java.lang.Thread"""
|
||
MIN_PRIORITY = 1
|
||
NORM_PRIORITY = 5
|
||
MAX_PRIORITY = 10
|
||
|
||
# Thread.State 常量(java.lang.Thread.State)
|
||
NEW = "NEW"
|
||
RUNNABLE = "RUNNABLE"
|
||
BLOCKED = "BLOCKED"
|
||
WAITING = "WAITING"
|
||
TIMED_WAITING = "TIMED_WAITING"
|
||
TERMINATED = "TERMINATED"
|
||
|
||
# 按 Python 线程 ident 缓存 Thread 对象,供 currentThread() 复用
|
||
_thread_cache = {}
|
||
_default_uncaught_exception_handler = None
|
||
|
||
def __init__(self, target=None, name=None):
|
||
super().__init__()
|
||
self._target = target
|
||
self._name = name or f"Thread-{id(self)}"
|
||
self._alive = False
|
||
self._daemon = False
|
||
self._interrupted = False
|
||
self._priority = Thread.NORM_PRIORITY
|
||
self._state = Thread.NEW
|
||
self._py_thread = None
|
||
self._id = _threading.get_ident()
|
||
|
||
def start(self):
|
||
self._alive = True
|
||
self._state = Thread.RUNNABLE
|
||
self._py_thread = _threading.Thread(
|
||
target=self._run_wrapper, daemon=self._daemon, name=self._name
|
||
)
|
||
self._py_thread.start()
|
||
self._id = self._py_thread.ident
|
||
|
||
def _run_wrapper(self):
|
||
tid = _threading.get_ident()
|
||
self._id = tid
|
||
Thread._thread_cache[tid] = self
|
||
try:
|
||
self.run()
|
||
except (SystemExit, KeyboardInterrupt):
|
||
raise
|
||
except BaseException as e:
|
||
# 注意:模块内 Exception 已被 java.lang.Exception 覆盖,
|
||
# 这里用 BaseException 捕获 Python 原生异常并转发给未捕获异常处理器
|
||
handler = Thread._default_uncaught_exception_handler
|
||
if handler is not None:
|
||
try:
|
||
handler.uncaughtException(self, e)
|
||
except BaseException:
|
||
pass
|
||
finally:
|
||
self._alive = False
|
||
self._state = Thread.TERMINATED
|
||
Thread._thread_cache.pop(tid, None)
|
||
|
||
def run(self):
|
||
if self._target:
|
||
self._target()
|
||
|
||
def join(self, millis=0):
|
||
if self._py_thread is not None:
|
||
if millis and millis > 0:
|
||
self._py_thread.join(millis / 1000.0)
|
||
else:
|
||
self._py_thread.join()
|
||
|
||
def interrupt(self):
|
||
self._interrupted = True
|
||
|
||
def isInterrupted(self):
|
||
return self._interrupted
|
||
|
||
@staticmethod
|
||
def interrupted():
|
||
tid = _threading.get_ident()
|
||
t = Thread._thread_cache.get(tid)
|
||
if t is not None:
|
||
status = t._interrupted
|
||
t._interrupted = False
|
||
return status
|
||
return False
|
||
|
||
def isAlive(self):
|
||
if self._py_thread is not None:
|
||
return self._py_thread.is_alive()
|
||
return self._alive
|
||
|
||
def getState(self):
|
||
if self._py_thread is not None:
|
||
if self._py_thread.is_alive():
|
||
return Thread.RUNNABLE
|
||
return Thread.TERMINATED
|
||
return self._state
|
||
|
||
def getPriority(self):
|
||
return self._priority
|
||
|
||
def setPriority(self, priority):
|
||
if Thread.MIN_PRIORITY <= priority <= Thread.MAX_PRIORITY:
|
||
self._priority = priority
|
||
|
||
def getId(self):
|
||
return self._id
|
||
|
||
def getName(self): return self._name
|
||
def setName(self, n): self._name = n
|
||
def setDaemon(self, d): self._daemon = d
|
||
def isDaemon(self): return self._daemon
|
||
|
||
@staticmethod
|
||
def currentThread():
|
||
tid = _threading.get_ident()
|
||
t = Thread._thread_cache.get(tid)
|
||
if t is not None:
|
||
return t
|
||
# 未缓存的线程(如主线程):创建并缓存一个代表对象
|
||
try:
|
||
is_main = (tid == _threading.main_thread().ident)
|
||
except Exception:
|
||
is_main = False
|
||
t = Thread(name="main" if is_main else f"Thread-{tid}")
|
||
t._state = Thread.RUNNABLE
|
||
t._alive = True
|
||
t._id = tid
|
||
Thread._thread_cache[tid] = t
|
||
return t
|
||
|
||
@staticmethod
|
||
def sleep(millis):
|
||
_time.sleep(millis / 1000.0)
|
||
|
||
@staticmethod
|
||
def yield_():
|
||
_time.sleep(0)
|
||
|
||
@staticmethod
|
||
def setDefaultUncaughtExceptionHandler(handler):
|
||
Thread._default_uncaught_exception_handler = handler
|
||
|
||
@staticmethod
|
||
def getDefaultUncaughtExceptionHandler():
|
||
return Thread._default_uncaught_exception_handler
|
||
|
||
|
||
class ThreadLocal(Stub):
|
||
"""java.lang.ThreadLocal"""
|
||
def __init__(self):
|
||
super().__init__()
|
||
self._data = {}
|
||
|
||
def get(self):
|
||
tid = _threading.get_ident()
|
||
return self._data.get(tid, None)
|
||
def set(self, value):
|
||
self._data[_threading.get_ident()] = value
|
||
def remove(self):
|
||
self._data.pop(_threading.get_ident(), None)
|
||
|
||
|
||
class StringBuilder(Stub):
|
||
"""java.lang.StringBuilder — 可变字符序列"""
|
||
def __init__(self, s=""):
|
||
super().__init__()
|
||
self._buf = list(str(s))
|
||
|
||
def append(self, obj):
|
||
if isinstance(obj, bool):
|
||
self._buf.append("true" if obj else "false")
|
||
else:
|
||
self._buf.append(str(obj))
|
||
return self
|
||
|
||
def insert(self, offset, obj):
|
||
self._buf[offset:offset] = list(str(obj))
|
||
return self
|
||
|
||
def delete(self, start, end):
|
||
del self._buf[start:end]
|
||
return self
|
||
|
||
def deleteCharAt(self, index):
|
||
del self._buf[index]
|
||
return self
|
||
|
||
def replace(self, start, end, s):
|
||
self._buf[start:end] = list(s)
|
||
return self
|
||
|
||
def reverse(self):
|
||
self._buf.reverse()
|
||
return self
|
||
|
||
def toString(self): return "".join(self._buf)
|
||
def length(self): return len(self._buf)
|
||
def capacity(self): return len(self._buf) + 16
|
||
def charAt(self, i): return self._buf[i]
|
||
def setCharAt(self, i, c): self._buf[i] = c
|
||
def substring(self, s, e=None):
|
||
return "".join(self._buf[s:e])
|
||
def indexOf(self, s, f=0):
|
||
return self.toString().find(s, f)
|
||
def lastIndexOf(self, s, f=None):
|
||
return self.toString().rfind(s)
|
||
|
||
|
||
class StringBuffer(StringBuilder):
|
||
"""java.lang.StringBuffer — 线程安全的可变字符序列"""
|
||
pass
|
||
|
||
|
||
class Class(Stub):
|
||
"""java.lang.Class"""
|
||
def __init__(self, cls):
|
||
super().__init__()
|
||
self._cls = cls
|
||
def getName(self): return self._cls.__name__
|
||
def getSimpleName(self): return self._cls.__name__
|
||
def getCanonicalName(self): return self._cls.__name__
|
||
def isInterface(self): return isinstance(self._cls, type)
|
||
def isArray(self): return self._cls is list
|
||
def isPrimitive(self): return self._cls in (int, float, bool, str, bytes)
|
||
def getSuperclass(self): return Class(self._cls.__base__) if self._cls.__base__ else None
|
||
def cast(self, obj): return obj
|
||
|
||
|
||
class Void(Stub):
|
||
"""java.lang.Void"""
|
||
TYPE = None
|
||
|
||
|
||
class VoidType(Stub):
|
||
"""java.lang.Void (inner type)"""
|
||
pass
|
||
|
||
|
||
# 注解类
|
||
class SuppressWarnings(Stub):
|
||
pass
|
||
class Deprecated(Stub):
|
||
pass
|
||
class Override(Stub):
|
||
pass
|
||
class FunctionalInterface(Stub):
|
||
pass |