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