droid_wrap/java/lang.rs
1/*
2 * Copyright (c) 2024. The RigelA open source project team and
3 * its contributors reserve all rights.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software distributed under the
10 * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 * See the License for the specific language governing permissions and limitations under the License.
12 */
13
14/**
15提供用于获取有关类和对象的反射信息的类和接口。
16*/
17#[cfg(feature = "java_lang_reflect")]
18pub mod reflect;
19
20use droid_wrap_derive::{
21 java_class, java_constructor, java_implement, java_interface, java_method,
22};
23use droid_wrap_utils::{vm_attach, Error, GlobalRef};
24use std::sync::Arc;
25
26use crate::{JObjNew, JObjRef, JProxy, JType};
27
28/**
29Object 类是类层次结构的根。每个类都有 Object 作为超类。所有对象(包括数组)都实现了此类的方法。
30*/
31#[java_class(name = "java/lang/Object")]
32pub struct Object;
33
34impl Object {
35 /**
36 返回对象的哈希码值。此方法支持哈希表,例如 java.util.HashMap 提供的哈希表。
37 hashCode 的一般约定是:在 Java 应用程序执行期间,只要对同一对象多次调用该方法,则 hashCode 方法必须始终返回相同的整数,前提是未修改对象上 equals 比较中使用的信息。此整数不必在应用程序的一次执行和同一应用程序的另一次执行之间保持一致。如果根据 equals(Object) 方法,两个对象相等,则对这两个对象中的每一个调用 hashCode 方法必须产生相同的整数结果。如果根据 equals(Object) 方法,两个对象不相等,则对这两个对象中的每一个调用 hashCode 方法不必产生不同的整数结果。
38 但是,程序员应该知道,为不相等的对象产生不同的整数结果可能会提高哈希表的性能。在合理可行的范围内,Object 类定义的 hashCode 方法确实会为不同的对象返回不同的整数。 (hashCode 可能被实现为某个时间点的对象内存地址的某个函数,也可能不被实现。)
39 返回:此对象的哈希码值。
40 */
41 #[java_method]
42 pub fn hash_code(&self) -> i32 {}
43}
44
45/// Object的扩展操作
46pub trait ObjectExt {
47 /// 把Object类型转换到任意java类型。
48 fn cast<T: JType>(&self) -> T
49 where
50 <T as JObjNew>::Fields: Default;
51}
52
53impl ObjectExt for Object {
54 fn cast<T: JType>(&self) -> T
55 where
56 <T as JObjNew>::Fields: Default,
57 {
58 T::_new(self.as_ref(), Default::default())
59 }
60}
61
62impl JObjRef for String {
63 fn java_ref(&self) -> GlobalRef {
64 vm_attach!(mut env);
65 let s = env.new_string(self.as_str()).unwrap();
66 env.new_global_ref(&s).unwrap()
67 }
68}
69
70impl JObjNew for String {
71 type Fields = ();
72
73 fn _new(this: &GlobalRef, _: Self::Fields) -> Self {
74 if this.is_null() {
75 return Self::default();
76 }
77 vm_attach!(mut env);
78 if let Ok(s) = env.get_string(this.as_obj().into()) {
79 return Self::from(s.to_str().unwrap());
80 }
81 Self::null()
82 }
83}
84
85impl JType for String {
86 type Error = Error;
87 const CLASS: &'static str = "java/lang/String";
88 //noinspection SpellCheckingInspection
89 const OBJECT_SIG: &'static str = "Ljava/lang/String;";
90}
91
92/**
93Boolean 类将原始类型布尔值包装在对象中。布尔类型的对象包含一个类型为布尔的字段。此外,此类还提供了许多将布尔值转换为字符串和将字符串转换为布尔值的方法,以及处理布尔值时有用的其他常量和方法。
94*/
95#[java_class(name = "java/lang/Boolean", extends=Object)]
96pub struct Boolean;
97
98impl Boolean {
99 /**
100 分配一个表示值参数的布尔对象。
101 `value` 布尔值。
102 */
103 #[deprecated(
104 note = "使用此构造函数很少适合。静态工厂valueOf(boolean)通常是一个更好的选择,因为它可能会产生更好的空间和时间性能。还要考虑如果可能的话,请考虑使用最终字段。"
105 )]
106 #[java_constructor]
107 pub fn new(value: bool) -> Self {}
108
109 /**
110 返回表示指定布尔值的布尔实例。如果指定的布尔值为真,则此方法返回 Boolean.TRUE;如果为假,则此方法返回 Boolean.FALSE。如果不需要新的布尔实例,则通常应优先使用此方法而不是构造函数 Boolean(boolean),因为此方法可能会产生更好的空间和时间性能。
111 返回:表示 b 的布尔实例。
112 `b` 布尔值。
113 */
114 #[java_method]
115 pub fn value_of(b: bool) -> Result<Self, <Self as JType>::Error> {}
116}
117
118impl From<&bool> for Boolean {
119 fn from(value: &bool) -> Self {
120 Self::value_of(*value).unwrap()
121 }
122}
123
124/// CharSequence的扩展操作
125pub trait CharSequenceExt {
126 /**
127 实现一个CharSequence类型。
128 */
129 fn to_char_sequence<CS: CharSequence>(&self) -> CS
130 where
131 <CS as JObjNew>::Fields: Default;
132}
133
134impl<'a> CharSequenceExt for &'a str {
135 fn to_char_sequence<CS: CharSequence>(&self) -> CS
136 where
137 <CS as JObjNew>::Fields: Default,
138 {
139 vm_attach!(mut env);
140 let s = env.new_string(*self).unwrap();
141 let s = env.new_global_ref(&s).unwrap();
142 CS::_new(&s, Default::default())
143 }
144}
145
146/**
147Integer 类将原始类型 int 的值包装在对象中。Integer 类型的对象包含一个类型为 int 的字段。此外,此类还提供了几种将 int 转换为 String 和将 String 转换为 int 的方法,以及处理 int 时有用的其他常量和方法。
148实现说明:“位操作”方法(如 highestOneBit 和 numberOfTrailingZeros)的实现基于 Henry S. Warren, Jr. 的《Hacker's Delight》(Addison Wesley,2002 年)中的材料。
149*/
150#[java_class(name = "java/lang/Integer", extends=Object)]
151pub struct Integer;
152
153impl Integer {
154 /// 具有-231的常数保持最小值。
155 pub const MIN_VALUE: u32 = 0x80000000;
156
157 /// 一个常数,保存 int 可以拥有的最大值 231-1。
158 pub const MAX_VALUE: u32 = 0x7fffffff;
159
160 /**
161 构造一个新分配的 Integer 对象,该对象表示指定的 int 值。
162 `value` Integer 对象要表示的值。
163 */
164 #[deprecated(
165 note = "很少适合使用此构造函数。静态工厂 valueOf(int) 通常是更好的选择,因为它可能会产生更好的空间和时间性能。"
166 )]
167 #[java_constructor]
168 pub fn new(value: i32) -> Self {}
169
170 //noinspection RsRedundantColonColon
171 /**
172 返回表示指定 int 值的 Integer 实例。如果不需要新的 Integer 实例,则通常应优先使用此方法而不是构造函数 Integer(int),因为此方法通过缓存频繁请求的值可能会产生更好的空间和时间性能。此方法将始终缓存 -128 到 127 范围内的值(含),并且可能会缓存此范围之外的其他值。
173 返回:表示 i 的 Integer 实例。
174 `i` 一个 int 值。
175 */
176 #[java_method]
177 pub fn value_of(i: i32) -> Result<Self, <Self as JType>::Error> {}
178}
179
180/**
181Float 类将原始类型浮点的值包装在对象中。Float 类型的对象包含一个类型为浮点的字段。此外,此类还提供了几种将浮点转换为字符串和将字符串转换为浮点的方法,以及处理浮点时有用的其他常量和方法。浮点相等、等价和比较 java.lang.Double 类讨论了浮点值的相等、等价和比较,其中相等适用于浮点值。
182*/
183#[java_class(name = "java/lang/Float", extends=Object)]
184pub struct Float;
185
186impl Float {
187 /**
188 构造一个新分配的 Float 对象,该对象表示原始 float 参数。
189 `value` Float 要表示的值。
190 */
191 #[deprecated(
192 note = "很少适合使用此构造函数。静态工厂 valueOf(float) 通常是更好的选择,因为它可能会产生更好的空间和时间性能。"
193 )]
194 #[java_constructor]
195 pub fn new(value: f32) -> Self {}
196
197 /**
198 返回表示指定浮点值的 Float 实例。如果不需要新的 Float 实例,则通常应优先使用此方法而不是构造函数 Float(float),因为此方法可能会通过缓存频繁请求的值来显著提高空间和时间性能。
199 返回:表示 f 的 Float 实例。
200 `f` 浮点值。
201 */
202 #[java_method]
203 pub fn value_of(f: f32) -> Result<Self, <Self as JType>::Error> {}
204}
205
206/**
207CharSequence 是可读的 char 值序列。此接口提供对许多不同种类的 char 序列的统一、只读访问。char 值表示基本多语言平面 (BMP) 中的字符或代理。有关详细信息,请参阅 Unicode 字符表示。此接口不会细化 equals 和 hashCode 方法的一般约定。因此,测试两个实现 CharSequence 的对象是否相等的结果通常是不确定的。每个对象可能由不同的类实现,并且不能保证每个类都能够测试其实例与另一个类的实例是否相等。因此,将任意 CharSequence 实例用作集合中的元素或映射中的键是不合适的。
208*/
209#[java_interface(name = "java/lang/CharSequence")]
210pub trait CharSequence {
211 /**
212 返回此字符序列的长度。长度是序列中的16位字符的数量。
213 返回:此序列中的字符数量
214 */
215 fn length(&self) -> i32;
216
217 /**
218 返回指定索引处的 char 值。索引范围从零到 length() - 1。序列的第一个 char 值位于索引零处,下一个位于索引一处,依此类推,就像数组索引一样。如果索引指定的 char 值是代理,则返回代理值。
219 返回:指定的 char 值
220 抛出 IndexOutOfBoundsException 如果 index 参数为负数或不小于 length()
221 `index` 要返回的 char 值的索引
222 * */
223 fn char_at(&self, index: i32) -> Result<char, Error>;
224}
225
226#[doc(hidden)]
227#[java_class(name = "java/lang/CharSequenceImpl", extends=Object)]
228pub struct CharSequenceImpl;
229
230impl CharSequence for CharSequenceImpl {
231 #[java_method]
232 fn length(&self) -> i32 {}
233
234 #[java_method]
235 fn char_at(&self, index: i32) -> Result<char, Error> {}
236}
237
238/**
239任何实例旨在由线程执行的类都应实现 Runnable 接口。该类必须定义一个名为 run 的无参数方法。此接口旨在为希望在活动期间执行代码的对象提供通用协议。例如,Runnable 由 Thread 类实现。
240活动状态仅表示线程已启动且尚未停止。此外,Runnable 还提供了在不子类化 Thread 的情况下使类处于活动状态的方法。实现 Runnable 的类可以通过实例化 Thread 实例并将其自身作为目标传递,而无需子类化 Thread 即可运行。
241在大多数情况下,如果您只打算覆盖 run() 方法而不覆盖其他 Thread 方法,则应使用 Runnable 接口。这一点很重要,因为除非程序员打算修改或增强类的基本行为,否则不应子类化类。
242*/
243#[java_interface(name = "java/lang/Runnable")]
244pub trait Runnable {
245 /**
246 当使用实现 Runnable 接口的对象创建线程时,启动该线程会导致在该单独执行的线程中调用该对象的 run 方法。
247 方法 run 的一般约定是它可以采取任何操作。
248 */
249 fn run(&self);
250}
251
252#[doc(hidden)]
253#[java_class(name = "java/lang/RunnableImpl", extends=Object)]
254pub struct RunnableImpl(Box<dyn Fn() + Sync + Send>);
255
256impl RunnableImpl {
257 pub fn from_fn(func: impl Fn() + Sync + Send + 'static) -> Arc<Self> {
258 Self::new(RunnableImplDefault(Box::new(func)))
259 }
260}
261
262impl Default for RunnableImplDefault {
263 fn default() -> Self {
264 Self(Box::new(|| ()))
265 }
266}
267
268#[java_implement]
269impl Runnable for RunnableImpl {
270 fn run(&self) {
271 self.0();
272 }
273}
274
275/**
276System 类包含几个有用的类字段和方法。它无法实例化。 System 类提供的功能包括标准输入、标准输出和错误输出流;访问外部定义的属性和环境变量;加载文件和库的方法;以及用于快速复制数组一部分的实用方法。
277*/
278#[java_class(name = "java/lang/System")]
279pub struct System;
280
281impl System {
282 /**
283 返回当前时间(以毫秒为单位)。请注意,虽然返回值的时间单位是毫秒,但值的粒度取决于底层操作系统,可能更大。例如,许多操作系统以数十毫秒为单位测量时间。有关“计算机时间”和协调世界时 (UTC) 之间可能出现的细微差异的讨论,请参阅 Date 类的描述。
284 返回:当前时间与 1970 年 1 月 1 日午夜 UTC 之间的差值(以毫秒为单位)。
285 */
286 #[java_method]
287 pub fn current_time_millis() -> i64 {}
288
289 /**
290 运行垃圾收集器。调用 gc 方法表明 Java 虚拟机会努力回收未使用的对象,以便使它们当前占用的内存可供快速重用。当控制权从方法调用返回时,Java 虚拟机已尽最大努力从所有丢弃的对象中回收空间。调用 System.gc() 实际上等同于调用: Runtime.getRuntime().gc()
291 */
292 #[java_method]
293 pub fn gc() {}
294
295 /**
296 终止当前正在运行的 Java 虚拟机。该参数用作状态代码;按照惯例,非零状态代码表示异常终止。此方法调用 Runtime 类中的 exit 方法。此方法永远不会正常返回。调用 System.exit(n) 实际上等同于调用: Runtime.getRuntime().exit(n)
297 抛出:SecurityException – 如果存在安全管理器并且其 checkExit 方法不允许以指定状态退出。
298 `status` 退出状态。
299 */
300 #[java_method]
301 pub fn exit(status: i32) -> Result<(), <Self as JType>::Error> {}
302}
303
304/**
305类加载器是负责加载类的对象。ClassLoader 类是一个抽象类。给定类的二进制名称,类加载器应尝试定位或生成构成该类定义的数据。典型的策略是将名称转换为文件名,然后从文件系统中读取该名称的“类文件”。
306每个 Class 对象都包含对定义它的 ClassLoader 的引用。数组类的类对象不是由类加载器创建的,而是由 Java 运行时根据需要自动创建的。Class.getClassLoader() 返回的数组类的类加载器与其元素类型的类加载器相同;如果元素类型是原始类型,则数组类没有类加载器。
307应用程序实现 ClassLoader 的子类,以扩展 Java 虚拟机动态加载类的方式。安全管理器通常可以使用类加载器来指示安全域。 ClassLoader 类使用委托模型来搜索类和资源。
308ClassLoader 的每个实例都有一个关联的父类加载器。当请求查找类或资源时,ClassLoader 实例会将对类或资源的搜索委托给其父类加载器,然后再尝试自己查找类或资源。虚拟机的内置类加载器称为“引导类加载器”,它本身没有父类,但可以充当 ClassLoader 实例的父类。
309支持并发加载类的类加载器称为具有并行能力的类加载器,需要在类初始化时通过调用 ClassLoader.registerAsParallelCapable 方法来注册自己。请注意,默认情况下,ClassLoader 类被注册为具有并行能力。但是,如果其子类具有并行能力,则仍需要注册自己。
310在委托模型不是严格分层的环境中,类加载器需要具有并行能力,否则类加载可能会导致死锁,因为加载器锁会在整个类加载过程中一直保持(请参阅 loadClass 方法)。
311通常,Java 虚拟机以与平台相关的方式从本地文件系统加载类。例如,在 UNIX 系统上,虚拟机从 CLASSPATH 环境变量定义的目录中加载类。但是,某些类可能不是源自文件;它们可能源自其他来源,例如网络,或者可以由应用程序构造。方法 defineClass 将字节数组转换为 Class 类的实例。
312可以使用 Class.newInstance 创建此新定义类的实例。类加载器创建的对象的方法和构造函数可能会引用其他类。为了确定引用的类,Java 虚拟机会调用最初创建该类的类加载器的 loadClass 方法。例如,应用程序可以创建网络类加载器以从服务器下载类文件。示例代码可能如下所示:
313ClassLoader loader = new NetworkClassLoader(host, port);
314Object main = loader.loadClass("Main", true).newInstance();
315...
316网络类加载器子类必须定义 findClass 和 loadClassData 方法,以便从网络加载类。下载组成类的字节后,应使用 defineClass 方法创建类实例。示例实现如下:
317class NetworkClassLoader extends ClassLoader {
318 String host;
319 int port;
320 public Class findClass(String name) {
321 byte[] b = loadClassData(name);
322 return defineClass(name, b, 0, b.length);
323 }
324 private byte[] loadClassData(String name) {
325 // 从连接加载类数据
326 ...
327 }
328}
329二进制名称作为 String 参数提供给 ClassLoader 中方法的任何类名都必须是 Java™ 语言规范定义的二进制名称。有效类名的示例包括:
330- "java.lang.String"
331- "javax.swing.JSpinner$DefaultEditor"
332- "java.security.KeyStore$Builder$FileBuilder$1"
333- "java.net.URLClassLoader$3$1"
334*/
335#[java_class(name = "java/lang/ClassLoader", extends=Object)]
336pub struct ClassLoader;
337
338/**
339此接口对实现它的每个类的对象施加了全排序。此排序称为类的自然排序,类的 compareTo 方法称为其自然比较方法。
340实现此接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)自动排序。
341实现此接口的对象可以用作有序映射中的键或有序集合中的元素,而无需指定比较器。
342当且仅当 e1.compareTo(e2) == 0 对于类 C 的每个 e1 和 e2 都具有与 e1.equals(e2) 相同的布尔值时,类 C 的自然排序才被认为与 equals 一致。
343请注意,null 不是任何类的实例,即使 e.equals(null) 返回 false,e.compareTo(null) 也应抛出 NullPointerException。
344强烈建议(但不是必需的)自然排序与 equals 一致。这是因为,当有序集合(和有序映射)与自然顺序与 equals 不一致的元素(或键)一起使用时,没有显式比较器的行为会“奇怪”。
345特别是,这样的有序集合(或有序映射)违反了集合(或映射)的一般约定,该约定是根据 equals 方法定义的。
346例如,如果将两个键 a 和 b 相加,使得 (!a.equals(b) && a.compareTo(b) == 0) 添加到不使用显式比较器的有序集合,则第二个添加操作将返回 false(并且有序集合的大小不会增加),因为从有序集合的角度来看,a 和 b 是相等的。
347几乎所有实现 Comparable 的 Java 核心类都具有与 equals 一致的自然顺序。一个例外是 java.math.BigDecimal,其自然顺序将具有相等数值和不同表示形式的 BigDecimal 对象相等(例如 4.0 和 4.00)。
348对于 BigDecimal。 equals() 返回 true,则两个 BigDecimal 对象的表示和数值必须相同。对于数学爱好者来说,定义给定类 C 的自然排序的关系是:
349{(x, y) 使得 x.compareTo(y) <= 0}。
350此全序的商是:
351{(x, y) 使得 x.compareTo(y) == 0}。
352根据 compareTo 的约定,可以立即得出,商是 C 上的等价关系,而自然排序是 C 上的全序。
353当我们说类的自然排序与 equals 一致时,我们的意思是自然排序的商是该类的 equals(Object) 方法定义的等价关系: {(x, y) 使得 x.equals(y)}。
354换句话说,当一个类的自然顺序与 equals 一致时,由 equals 方法的等价关系定义的等价类和由 compareTo 方法的商定义的等价类是相同的。此接口是 Java 集合框架的成员。
355*/
356pub trait Comparable<T>: JType {
357 /**
358 将此对象与指定对象进行比较以确定顺序。如果此对象小于、等于或大于指定对象,则返回负整数、零或正整数。
359 实现者必须确保对于所有 x 和 y,signum(x.compareTo(y)) == -signum(y.compareTo(x))。(这意味着当且仅当 y.compareTo(x) 抛出异常时,x.compareTo(y) 才必须抛出异常。)
360 实现者还必须确保关系是传递的:(x.compareTo(y) > 0 && y.compareTo(z) > 0)意味着 x.compareTo(z) > 0。
361 最后,实现者必须确保对于所有 z,x.compareTo(y)==0 意味着 signum(x.compareTo(z)) == signum(y.compareTo(z))。
362 返回:负整数、零或正整数,因为此对象小于、等于或大于指定对象。
363 抛出:
364 - NullPointerException – 如果指定对象为 null
365 - ClassCastException – 如果指定对象的类型阻止其与此对象进行比较。
366 强烈建议(但不严格要求)(x.compareTo(y)==0) == (x.equals(y))。一般来说,任何实现 Comparable 接口并违反此条件的类都应明确指出这一事实。建议的语言是“注意:此类具有与 equals 不一致的自然排序。”
367 `o` 要比较的对象。
368 */
369 fn compare_to(&self, o: &T) -> Result<i32, <Self as JType>::Error>;
370}
371
372/// 测试java.lang
373#[cfg(feature = "test_java_lang")]
374pub fn test() {
375 let integer = Integer::value_of(100).unwrap();
376 assert_eq!("100", integer.to_string());
377 let float = Float::value_of(423.3).unwrap();
378 assert_eq!("423.3", float.to_string());
379 let cs = "hello".to_char_sequence::<CharSequenceImpl>();
380 assert_eq!("hello", cs.to_string());
381 assert_eq!(5, cs.length());
382 assert_eq!('h', cs.char_at(0).unwrap());
383 assert!(System::current_time_millis() > 0);
384 System::gc();
385 let cl = ClassLoader::null();
386 assert_eq!(cl, ClassLoader::null());
387 let func = RunnableImpl::from_fn(move || println!("Runnable is running."));
388 dbg!(func);
389 // System::exit(0).unwrap();
390}