首页 文章 精选 留言 我的

精选列表

搜索[面试],共4912篇文章
优秀的个人博客,低调大师

Android面试,IntentService的原理及使用

在Android开发中,我们或许会碰到这么一种业务需求,一项任务分成几个子任务,子任务按顺序先后执行,子任务全部执行完后,这项任务才算成功。那么,利用几个子线程顺序执行是可以达到这个目的的,但是每个线程必须去手动控制,而且得在一个子线程执行完后,再开启另一个子线程。或者,全部放到一个线程中让其顺序执行。这样都可以做到,但是,如果这是一个后台任务,就得放到Service里面,由于Service和Activity是同级的,所以,要执行耗时任务,就得在Service里面开子线程来执行。那么,有没有一种简单的方法来处理这个过程呢,答案就是IntentService。 什么是IntentService,IntentService是继承于Service并处理异步请求的一个类,在IntentService内有一个工作线程来处理耗时操作,启动IntentService的方式和启动传统Service一样,同时,当任务执行完后,IntentService会自动停止,而不需要我们去手动控制。另外,可以启动IntentService多次,而每一个耗时操作会以工作队列的方式在IntentService的onHandleIntent回调方法中执行,并且,每次只会执行一个工作线程,执行完第一个再执行第二个,以此类推。 所有请求都在一个单线程中,不会阻塞应用程序的主线程(UI Thread),同一时间只处理一个请求。 那么,用IntentService有什么好处呢?首先,我们省去了在Service中手动开线程的麻烦,第二,当操作完成时,我们不用手动停止Service。 Code 接下来让我们来看看如何使用,我写了一个Demo来模拟两个耗时操作,Operation1与Operation2,先执行1,2必须等1执行完才能执行: 新建工程,新建一个继承IntentService的类,我这里是IntentServiceDemo.java public class IntentServiceDemo extends IntentService { public IntentServiceDemo() { //必须实现父类的构造方法 super("IntentServiceDemo"); } @Override public IBinder onBind(Intent intent) { System.out.println("onBind"); return super.onBind(intent); } @Override public void onCreate() { System.out.println("onCreate"); super.onCreate(); } @Override public void onStart(Intent intent, int startId) { System.out.println("onStart"); super.onStart(intent, startId); } @Override public int onStartCommand(Intent intent, int flags, int startId) { System.out.println("onStartCommand"); return super.onStartCommand(intent, flags, startId); } @Override public void setIntentRedelivery(boolean enabled) { super.setIntentRedelivery(enabled); System.out.println("setIntentRedelivery"); } @Override protected void onHandleIntent(Intent intent) { //Intent是从Activity发过来的,携带识别参数,根据参数不同执行不同的任务 String action = intent.getExtras().getString("param"); if (action.equals("oper1")) { System.out.println("Operation1"); }else if (action.equals("oper2")) { System.out.println("Operation2"); } try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } @Override public void onDestroy() { System.out.println("onDestroy"); super.onDestroy(); } } 我把生命周期方法全打印出来了,待会我们来看看它执行的过程是怎样的。接下来是Activity,在Activity中来启动IntentService: public class TestActivity extends Activity { /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); //可以启动多次,每启动一次,就会新建一个work thread,但IntentService的实例始终只有一个 //Operation 1 Intent startServiceIntent = new Intent("com.test.intentservice"); Bundle bundle = new Bundle(); bundle.putString("param", "oper1"); startServiceIntent.putExtras(bundle); startService(startServiceIntent); //Operation 2 Intent startServiceIntent2 = new Intent("com.test.intentservice"); Bundle bundle2 = new Bundle(); bundle2.putString("param", "oper2"); startServiceIntent2.putExtras(bundle2); startService(startServiceIntent2); } } 最后,别忘了配置Service,因为它继承于Service,所以,它还是一个Service,一定要配置,否则是不起作用的,开始我就是忘了,结果半天没反应。 <service android:name=".IntentServiceDemo"> <intent-filter > <action android:name="com.test.intentservice"/> </intent-filter> </service> 最后来看看执行结果: 从结果可以看到,onCreate方法只执行了一次,而onStartCommand和onStart方法执行了两次,开启了两个Work Thread,这就证实了之前所说的,启动多次,但IntentService的实例只有一个,这跟传统的Service是一样的。Operation1也是先于Operation2打印,并且我让两个操作间停顿了2s,最后是onDestroy销毁了IntentService。 我是天王盖地虎的分割线 本文转自我爱物联网博客园博客,原文链接:http://www.cnblogs.com/yydcdut/p/3960886.html,如需转载请自行联系原作者

优秀的个人博客,低调大师

Android -- 面试 -- 数据库升级策略

升级:重写onUpgrade方法 确定 相邻版本 的差别,从版本1开始依次迭代更新,先执行v1到v2,再v2到v3…… 为 每个版本 确定与现在数据库的差别,为每个case撰写专门的升级代码。 降级 onDowngrade()数据库降级:比如从数据库4降级到数据库3必须重写该方法。 @Override public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { super.onDowngrade(db, oldVersion, newVersion); } 迁移数据: 将现有表重命名为临时表; 创建新表; 将临时表的数据导入新表(注意处理修改的列); 删除临时表。 protected void upgradeTables(SQLiteDatabase db, String tableName, String columns) { try { db.beginTransaction(); // 1, 将现有表重命名为临时表 String tempTableName = tableName + "_temp"; String sql = "ALTER TABLE " + tableName +" RENAME TO " + tempTableName; execSQL(db, sql, null); // 2, 创建新表 //onCreateTable(db); createNewTableX(db); // 3, 将临时表数据导入新表中 sql = "INSERT INTO " + tableName + " (" + columns + ") " + " SELECT " + columns + " FROM " + tempTableName; execSQL(db, sql, null); // 4, 删除临时表 execSQL(db, "DROP TABLE IF EXISTS " + tempTableName, null); db.setTransactionSuccessful(); } catch (SQLException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); } finally { db.endTransaction(); } }

优秀的个人博客,低调大师

10道面试官喜欢问的微服务面试题Spring Cloud+Spring Boot

前言为什么要使用微服务?随着互联网的快速发展,各行各业都在用互联网。互联网已经离不开人们的形形色色。随着越来越多的用户,业务场景也愈来愈复杂。传统的单体架构已经很难满足互联网技术发展的要求,代码可维护性扩展性和可读性降低,维护成本的提高都是驱动微服务的发展趋势。 微服务哪些框架 Dubbo,是阿里巴巴服务化治理的核心框架,并被广泛应用于阿里巴巴集团的各成员站点。阿里巴巴近几年对开源社区的贡献不论在国内还是国外都是引人注目的,比如:JStorm 捐赠给 Apache 并加入 Apache 基金会等,为中国互联网人争足了面子,使得阿里巴巴在国人眼里已经从电商升级为一家科技公司了。Spring Cloud,从命名我们就可以知道,它是 Spring Source 的产物,Spring 社区的强大背书可以说是 Java 企业界最有影响力的组织了,除了 Spring Source 之外,还有Pivotal 和 Netfix 是其强大的后盾与技术输出。其中 Netflix 开源的整套微服务架构套件是Spring Cloud 的核心。 说说 RPC 的实现原理 首先需要有处理网络连接通讯的模块,负责连接建立、管理和消息的传输。其次需要有编解码的模块,因为网络通讯都是传输的字节码,需要将我们使用的对象序列化和反序列化。剩下的就是客户端和服务器端的部分,服务器端暴露要开放的服务接口,客户调用服务接口的一个代理实现,这个代理实现负责收集数据、编码并传输给服务器然后等待结果返回。 说说 Dubbo 的实现原理 dubbo 作为 rpc 框架,实现的效果就是调用远程的方法就像在本地调用一样。如何做到呢?就是本地有对远程方法的描述,包括方法名、参数、返回值,在 dubbo 中是远程和本地使用同样的接口;然后呢,要有对网络通信的封装,要对调用方来说通信细节是完全不可见的,网络通信要做的就是将调用方法的属性通过一定的协议(简单来说就是消息格式)传递到服务端;服务端按照协议解析出调用的信息;执行相应的方法;在将方法的返回值通过协议传递给客户端;客户端再解析;在调用方式上又可以分为同步调用和异步调用;简单来说基本就这个过程 Spring Boot 有哪些优点? Spring Boot 的优点有:减少开发,测试时间和努力。使用 JavaConfig 有助于避免使用 XML。避免大量的 Maven 导入和各种版本冲突。提供意见发展方法。通过提供默认值快速开始开发。没有单独的 Web 服务器需要。这意味着你不再需要启动 Tomcat,Glassfish 或其他任何东西。需要更少的配置 因为没有 web.xml 文件。只需添加用@ Configuration 注释的类,然后添加用@Bean 注释的方法,Spring 将自动加载对象并像以前一样对其进行管理。您甚至可以将@Autowired 添加到 bean 方法中,以使 Spring 自动装入需要的依赖关系中。基于环境的配置 使用这些属性,您可以将您正在使用的环境传递到应用程序:-Dspring.profiles.active = {enviornment}。在加载主应用程序属性文件后,Spring 将在(application{environment} .properties)中加载后续的应用程序属性文件。如何实现 Spring Boot 应用程序的安全性?为了实现 Spring Boot 的安全性,我们使用 spring-boot-starter-security 依赖项,并且必须添加安全配置。它只需要很少的代码。配置类将必须扩展 WebSecurityConfigurerAdapter 并覆盖其方法。 如何集成 Spring Boot 和 ActiveMQ? 对于集成 Spring Boot 和 ActiveMQ,我们使用spring-boot-starter-activemq依赖关系。 它只需要很少的配置,并且不需要样板代码。 什么是 Swagger?你用 Spring Boot 实现了它吗? Swagger 广泛用于可视化 API,使用 Swagger UI 为前端开发人员提供在线沙箱。Swagger 是用于生成 RESTful Web 服务的可视化表示的工具,规范和完整框架实现。它使文档能够以与服务器相同的速度更新。当通过 Swagger 正确定义时,消费者可以使用最少量的实现逻辑来理解远程服务并与其进行交互。因此,Swagger 消除了调用服务时的猜测。 使用 Spring Cloud 有什么优势? 使用 Spring Boot 开发分布式微服务时,我们面临以下问题与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题。服务发现-服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服务目录,在该目录中注册服务,然后能够查找并连接到该目录中的服务。冗余-分布式系统中的冗余问题。负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路,中央处理单元,或磁盘驱动器的分布。性能-问题 由于各种运营开销导致的性能问题。部署复杂性-Devops 技能的要求。 负载平衡的意义什么? 在计算中,负载平衡可以改善跨计算机,计算机集群,网络链接,中央处理单元或磁盘驱动器等多种计算资源的工作负载分布。负载平衡旨在优化资源使用,最大化吞吐量,最小化响应时间并避免任何单一资源的过载。使用多个组件进行负载平衡而不是单个组件可能会通过冗余来提高可靠性和可用性。负载平衡通常涉及专用软件或硬件,例如多层交换机或域名系统服务器进程。 什么是 Netflix Feign?它的优点是什么? Feign 是受到 Retrofit,JAXRS-2.0 和 WebSocket 启发的 java 客户端联编程序。Feign 的第一个目标是将约束分母的复杂性统一到 http apis,而不考虑其稳定性。在 employee-consumer 的例子中,我们使用了 employee-producer 使用 REST 模板公开的 REST 服务。但是我们必须编写大量代码才能执行以下步骤使用功能区进行负载平衡。获取服务实例,然后获取基本 URL。利用 REST 模板来使用服务。 前面的代码如下 @Controller public class ConsumerControllerClient { @Autowired private LoadBalancerClient loadBalancer; public void getEmployee() throws RestClientException, IOException { ServiceInstance serviceInstance=loadBalancer.choose("employee-producer"); System.out.println(serviceInstance.getUri()); String baseUrl=serviceInstance.getUri().toString(); baseUrl=baseUrl+"/employee"; RestTemplate restTemplate = new RestTemplate(); ResponseEntity<String> response=null; try{ response=restTemplate.exchange(baseUrl, HttpMethod.GET, getHeaders(),String.class); }catch (Exception ex) { System.out.println(ex); } System.out.println(response.getBody()); } 之前的代码,有像 NullPointer 这样的例外的机会,并不是最优的。我们将看到如何使用 Netflix Feign使呼叫变得更加轻松和清洁。如果 Netflix Ribbon 依赖关系也在类路径中,那么 Feign 默认也会负责负载平衡。 喜欢文章记得点个赞,感谢支持!

优秀的个人博客,低调大师

20道BAT面试官最喜欢问的JVM+MySQL面试题(含答案解析)

1. 内存模型以及分区,需要详细到每个区放什么。JVM 分为堆区和栈区,还有方法区,初始化的对象放在堆里面,引用放在栈里面,class 类信息常量池(static 常量和 static 变量)等放在方法区new: 方法区:主要是存储类信息,常量池(static 常量和 static 变量),编译后的代码(字节码)等数据 堆:初始化的对象,成员变量 (那种非 static 的变量),所有的对象实例和数组都要在堆上分配 栈:栈的结构是栈帧组成的,调用一个方法就压入一帧,帧上面存储局部变量表,操作数栈,方法出口等信息,局部变量表存放的是 8 大基础类型加上一个应用类型,所以还是一个指向地址的指针 本地方法栈:主要为 Native 方法服务 程序计数器:记录当前线程执行的行号 2. 堆里面的分区:Eden,survival (from+ to),老年代,各自的特点。堆里面分为新生代和老生代(java8 取消了永久代,采用了 Metaspace),新生代包含 Eden+Survivor 区,survivor 区里面分为 from 和 to 区,内存回收时,如果用的是复制算法,从 from 复制到 to,当经过一次或者多次 GC 之后,存活下来的对象会被移动到老年区,当 JVM 内存不够用的时候,会触发 Full GC,清理 JVM 老年区当新生区满了之后会触发 YGC,先把存活的对象放到其中一个 Survice区,然后进行垃圾清理。因为如果仅仅清理需要删除的对象,这样会导致内存碎片,因此一般会把 Eden 进行完全的清理,然后整理内存。那么下次 GC 的时候,就会使用下一个 Survive,这样循环使用。如果有特别大的对象,新生代放不下,就会使用老年代的担保,直接放到老年代里面。因为 JVM 认为,一般大对象的存活时间一般比较久远。 3. 对象创建方法,对象的内存分配,对象的访问定位。new 一个对象 4. GC 的两种判定方法:引用计数法:指的是如果某个地方引用了这个对象就+1,如果失效了就-1,当为 0 就会回收但是 JVM 没有用这种方式,因为无法判定相互循环引用(A 引用 B,B 引用 A)的情况引用链法: 通过一种 GC ROOT 的对象(方法区中静态变量引用的对象等-static 变量)来判断,如果有一条链能够到达 GC ROOT 就说明,不能到达 GC ROOT 就说明可以回收 5. SafePoint 是什么比如 GC 的时候必须要等到 Java 线程都进入到 safepoint 的时候 VMThread 才能开始执行 GC, 循环的末尾 (防止大循环的时候一直不进入 safepoint,而其他线程在等待它进入safepoint) 方法返回前 调用方法的 call 之后 抛出异常的位置 **6. GC 的三种收集方法:标记清除、标记整理、复制算法的原理与特点,分别用在什么地方,如果让你优化收集方法,有什么思路?**先标记,标记完毕之后再清除,效率不高,会产生碎片复制算法:分为 8:1 的 Eden 区和 survivor 区,就是上面谈到的 YGC标记整理:标记完毕之后,让所有存活的对象向一端移动 7. GC 收集器有哪些?CMS 收集器与 G1 收集器的特点。并行收集器:串行收集器使用一个单独的线程进行收集,GC 时服务有停顿时间串行收集器:次要回收中使用多线程来执行CMS 收集器是基于“ 标记— 清除”算法实现的,经过多次标记才会被清除G1 从 整体来看是基于“ 标记— 整理”算法实现的收集器,从 局部(两个 Region 之间)上来看是基于“ 复制”算法实现的 8. Minor GC 与 Full GC 分别在什么时候发生?新生代内存不够用时候发生 MGC 也叫 YGC,JVM 内存不够的时候发生 FGC 9. 几种常用的内存调试工具:jmap、jstack、jconsole、jhatjstack 可以看当前栈的情况,jmap 查看内存,jhat 进行 dump 堆的信息mat(eclipse 的也要了解一下) 10. 类加载的几个过程:加载、验证、准备、解析、初始化。然后是使用和卸载了通过全限定名来加载生成 class 对象到内存中,然后进行验证这个 class 文件,包括文件格式校验、元数据验证,字节码校验等。准备是对这个对象分配内存。解析是将符号引用转化为直接引用(指针引用),初始化就是开始执行构造器的代码 1. 数据库三范式是什么? 第一范式(1NF):字段具有原子性,不可再分。(所有关系型数据库系统都满足第一范式数据库表中的字段都是单一属性的,不可再分) 第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。要求数据库表中的每 个实例或行必须可以被惟一地区分。通常需要为表加上一个列,以存储各个实例的惟一标识。这个惟一属性列被称为主关键字或主键。 满足第三范式(3NF)必须先满足第二范式(2NF)。简而言之,第三范式(3NF)要求一个数据库表中不包含已在其它表中已包含的非主关 键字信息。 >所以第三范式具有如下特征: >>1. 每一列只有一个值 >>2. 每一行都能区分。 >>3. 每一个表都不包含其他表已经包含的非主关键字信息。 2. 有哪些数据库优化方面的经验? 用 PreparedStatement, 一般来说比 Statement 性能高:一个 sql发给服务器去执行,涉及步骤:语法检查、语义分析, 编译,缓存。 有外键约束会影响插入和删除性能,如果程序能够保证数据的完整性,那在设计数据库时就去掉外键。 表中允许适当冗余,譬如,主题帖的回复数量和最后回复时间等 UNION ALL 要比 UNION 快很多,所以,如果可以确认合并的两个结果集中不包含重复数据且不需要排序时的话,那么就使用 UNION ALL。 >>UNION 和 UNION ALL 关键字都是将两个结果集合并为一个,但这两者从使用和效率上来说都有所不同。 >1. 对重复结果的处理:UNION 在进行表链接后会筛选掉重复的记录,Union All 不会去除重复记录。 >2. 对排序的处理:Union 将会按照字段的顺序进行排序;UNION ALL 只是简单的将两个结果合并后就返回。 3. 请简述常用的索引有哪些种类? 普通索引: 即针对数据库表创建索引 唯一索引: 与普通索引类似,不同的就是:MySQL 数据库索引列的值必须唯一,但允许有空值 主键索引: 它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引 组合索引: 为了进一步榨取 MySQL 的效率,就要考虑建立组合索引。即将数据库表中的多个字段联合起来作为一个组合索引。 4. 以及在 mysql 数据库中索引的工作机制是什么?数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。索引的实现通常使用 B 树及其变种 B+树 5.MySQL 的基础操作命令: MySQL 是否处于运行状态:Debian 上运行命令 service mysqlstatus,在 RedHat 上运行命令 service mysqld status 开启或停止 MySQL 服务 :运行命令 service mysqld start 开启服务;运行命令 service mysqld stop 停止服务 Shell 登入 MySQL: 运行命令 mysql -u root -p 列出所有数据库:运行命令 show databases; 切换到某个数据库并在上面工作:运行命令 use databasename; 进入名为 databasename 的数据库 列出某个数据库内所有表: show tables; 获取表内所有 Field 对象的名称和类型 :describe table_name; 6.mysql 的复制原理以及流程。Mysql 内建的复制功能是构建大型,高性能应用程序的基础。将 Mysql 的数据分布到多个系统上去,这种分布的机制,是通过将 Mysql 的某一台主机的数据复制到其它主机(slaves)上,并重新执行一遍来实现的。 * 复制过程中一个服务器充当主服务器,而一个或多个其它服务器充当从服务器。主服务器将更新写入二进制日志文件,并维护文件的一个索引以跟踪日志循环。这些日志可以记录发送到从服务器的更新。 当一个从服务器连接主服务器时,它通知主服务器在日志中读取的最后一次成功更新的位置。从服务器接收从那时起发生的任何更新,然后封锁并等待主服务器通知新的更新。 过程如下 1. 主服务器把更新记录到二进制日志文件中。 2. 从服务器把主服务器的二进制日志拷贝到自己的中继日志(replay log)中。 3. 从服务器重做中继日志中的时间,把更新应用到自己的数据库上。 7.mysql 支持的复制类型? 基于语句的复制: 在主服务器上执行的 SQL 语句,在从服务器上执行同样的语句。MySQL 默认采用基于语句的复制,效率比较高。 一旦发 现没法精确复制时,会自动选着基于行的复制。 基于行的复制:把改变的内容复制过去,而不是把命令在从服务器上执行一遍. 从 mysql5.0 开始支持 混合类型的复制: 默认采用基于语句的复制,一旦发现基于语句的无法精确的复制时,就会采用基于行的复制。 **8.mysql 中 中 varchar 与 与 char 的区别以及 varchar(50) 中的 50 代表的涵义?** varchar 与 char 的区别: char 是一种固定长度的类型,varchar 则是一种可变长度的类型. varchar(50)中 50 的涵义 : 最多存放 50 个字节 int(20)中 20 的涵义: int(M)中的 M indicates the maximum width (最大显示宽度)for integer types. The maximum legal display width is 255. **9. 表中有大字段 X (例如:text 类型),且字段 X 不会经常更新,以读为为主,将该字段拆成子表好处是什么?**如果字段里面有大字段(text,blob)类型的,而且这些字段的访问并不多,这时候放在一起就变成缺点了。 MYSQL 数据库的记录存储是按行存储的,数据块大小又是固定的(16K),每条记录越小,相同的块存储的记录就越多。此时应该把大字段拆走,这样应付大部分小字段的查询时,就能提高效率。当需要查询大字段时,此时的关联查询是不可避免的,但也是值得的。拆分开后,对字段的 UPDAE 就要 UPDATE 多个表了 **10.MySQL 中 中 InnoDB 引擎的行锁是通过加在什么上完成(或称实现)的?**InnoDB 行锁是通过给索引上的索引项加锁来实现的,这一点 MySQL 与Oracle 不同,后者是通过在数据块中对相应数据行加锁来实现的。InnoDB 这种行锁实现特点意味着:只有通过索引条件检索数据,InnoDB 才使用行级锁,否则,InnoDB 将使用表锁! 欢迎大家一起交流,喜欢文章记得点个赞哟,感谢支持!

资源下载

更多资源
优质分享App

优质分享App

近一个月的开发和优化,本站点的第一个app全新上线。该app采用极致压缩,本体才4.36MB。系统里面做了大量数据访问、缓存优化。方便用户在手机上查看文章。后续会推出HarmonyOS的适配版本。

腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。