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