RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1095461
Accepted
pepsicoca1
pepsicoca1
Asked:2020-03-16 23:41:07 +0000 UTC2020-03-16 23:41:07 +0000 UTC 2020-03-16 23:41:07 +0000 UTC

是否可以在 Windows 上从 Google Play Market 安装 Java 应用程序?

  • 772

突然,一个奇怪的想法浮现在脑海。如果 Google Play Market 上有 Java 应用程序,那么理论上它应该可以在任何有 Java 机器的地方工作。它也应该适用于 Windows。

问题:

是否可以在 Windows 上从 Google Play Market 安装 Java 应用程序?

java
  • 3 3 个回答
  • 10 Views

3 个回答

  • Voted
  1. StateItPrimitive
    2020-03-17T02:32:49Z2020-03-17T02:32:49Z

    免责声明:

    我不是 Android 开发专家,因为 我几乎将所有时间都花在了 Web 应用程序上,然而,这个话题对我来说非常有趣,所以我将尝试详细描述它(尽可能多地对我个人感兴趣)。

    Java作为一种编程语言:

    Java是一种编程语言,即 一些合同/规范的描述(描述和相关行为(例如,未定义行为的不可接受性)),可以通过各种方式实现。

    例如,没有人禁止在 Java 语言之上编写自己的运行时环境,即 类似于 Java 的运行时环境,即 作为源代码将使用来自特定版本的 Java 语言的特性(特征)。在这种情况下,您将面临一项艰巨的任务:保持与各种(至少是最流行的)处理器架构和操作系统 API 的兼容性。

    此外,在特定情况下,您自己的实现甚至不必类似于 JVM:它不必编译为字节码(见下文),而是直接将源代码编译为机器码(native machine code),即 使用在许多其他语言中使用的更传统的方法(例如Go, C, C++, Swift, ...)。

    为了了解所有功能和复杂性(由于系统的实现方式有所不同),您需要了解应用程序如何在 Android 及其他系统上运行的原理:

    经典的类 JVM 实现:

    一个典型的经典(非Android)Java应用程序的生命周期可以描述如下:

    source code -(compiler)-> bytecode -(JVM)-> native machine code.

    让我们详细说明一个具体的例子:

    .java -(javac)-> .class -(HotSpot)-> native machine code:

    • java作为源代码;
    • javac作为用Java编写的源代码的编译器bytecode;
    • HotSpot(来自 Oracle)作为 JVM,即 将字节码命令运行时/解释为特定 CPU 的机器码命令,即 一个特定的处理器,其核心执行native machine code应用程序的机器代码 ( );
    • machine code- 针对特定处理器架构和操作系统 API 的一组指令。

    让我们更详细地分析一下:

    1. source code(源代码)——基于 JVM 编程语言的程序代码:

      1. .java-file - Java 代码;
      2. .kt-file - Kotlin 代码;
      3. .clj-file - Clojure 代码;
      4. .scala-file - Scala 代码;
      5. .groovy-file - Groovy 代码;
      6. 等等...
    2. compiler- 源代码bytecode的编译器(编译器的选择肯定取决于源代码中使用的编程语言):

      1. Java - javacCLI 工具;
      2. Kotlin - kotlincCLI 工具
      3. Clojure- leiningen CLI 工具或标准编译工具;
      4. Scala - scalacCLI 工具
      5. Groovy - groovycCLI 工具
      6. 等等...
    3. bytecode-规范中描述的一组指令,由 JVM 执行:

      • 只有256 条指令(见第 7 章),目前实际使用的只有大约 200 条;
      • .class-file - 将源代码编译成字节码的一组指令;
        • 如果我们看 Java 代码的例子,那么每个 Java 类都落入一个单独的.class文件中,不管它是否Top Level Class存在;
    4. native machine code(机器代码)- 由处理器执行的一组指令(针对特定的处理器架构和 OS API):

      • 在特定处理器架构的指令中解释字节码的结果;

        • 一般情况下,在一个JVM的框架内,需要支持所有用于执行代码的CPU的命令;

        • 通常,为了支持跨操作系统的 API,JVM 提供商(例如 Oracle)通常为每个操作系统发布单独的 JVM 发行版,每个发行版仅支持其发布的操作系统的 API(以最小化单个 JVM 发行版的大小)。

    JVM实现:

    您可能已经猜到有许多 JVM 实现,每个实现都独立负责将所有标准bytecode转换为每个处理器架构的特定标准native machine code。

    为清楚起见,我将为您提供最流行的 JVM 实现的大致列表:

    1. HotSpot VM(来自甲骨文);
    2. OpenJVM;
    3. MSJVM/ Microsoft VM;
    4. IBM JVM;
    5. JRockit;
    6. Dalvik(来自安卓公司):
      • 后来,Android, Inc. (连同他们早期版本的 Android 产品)被谷歌收购;
    7. Android Runtime,又名,ART(来自谷歌):
      • 来自 Google 的开发,旨在取代购买时继承的 Android DalvikVM (Dalvik被ARTAndroid 5.0 “Lollipop”取代);
    8. ...

    在 JVM 规范的每一个实现中,都独立解决了以下问题:

    1. 对各种操作系统的 API 支持:
      • 为每个受支持的操作系统提供单独的发行版(这可以在Oracle 的 JVM 示例中看到);
    2. 支持各种处理器架构(CISC、RISC、MISC)的命令:
      • 在每个处理器架构内,支持各种处理器线的命令。

    经典类JVM应用的打包(打包):

    在打包(打包)经典的类JVM应用方面,有以下几种选择:

    • 罐:
      • 不可执行(用作链接库);
      • 表演;
        • 有一个包含方法的类public static void main(String[] args),其指示在 中描述META-INF/MANIFEST.MF;
        • 随着 SpringBoot、MicroProfile.IO 和类似解决方案的出现,可执行 JAR 正在取代其他打包选项(当然,不可执行 JAR 库除外);
      • EJB JAR 是在 Jakarta EE(前 Java EE)中归档 EJB 模块(作为 JAR 文件)的标准:
        • META-INF/ejb-jar.xml通过注解(通过 Java SPI(服务提供者接口),特别是Java Annotation Processing API )将 EJB 模块的描述添加到中;
    • WAR(Web 应用程序存档):
      • 是 Jakarta EE(前 Java EE)中的 Web 模块归档标准;
      • 是加载到Application Server'a(应用服务器)内的Web Container中的模块;
      • 可能包含多个 EJB JAR;
      • WEB-INF/web.xml通过注解(通过 Java SPI(服务提供者接口),特别是Java Annotation Processing API )向 中添加 Web 模块的描述;
    • EAR(企业应用归档):
      • 是 Jakarta EE(以前的 Java EE)中企业应用程序的归档标准;
      • 由几个 WAR 组成。

    有关更多详细信息,请参见此处和此处。

    Android 类 JVM 实现:

    在为 Android 开发应用程序时,来自 Android, Inc. 的人。(Android 的创造者,后来被 Google 吸收)选择使用已经非常流行的 Java 编程语言,从某个版本(例如 java 6)实现其功能,并以一种或另一种方式定期更新它们(例如,爪哇 8). 在此处、此处和此处查看更多信息。

    因此,他们并没有从头开始发明一种编程语言(就像 Apple 在创建自己的语言时所做的那样Swift),但他们极大地改变了执行环境。

    现在代码的生命周期开始根据具体实现有所不同。考虑一个使用标准 Android 构建工具的示例:

    source code -(classic JVM compiler)-> bytecode -(dexer)-> dex -(Android JVM)-> machine code.

    让我们详细说明一个具体的例子java -(javac)-> .class -(dexer)-> classes.dex -(Dalvik / ART)-> machine code:

    • java作为源代码;
    • javac作为经典 JVM 的经典源代码编译器bytecode;
    • .class- 以经典 JVM 字节码格式存储命令的文件(JVM 规范中描述的标准指令);
    • dexer作为将经典 JVM 字节码转换为专有字节码格式的实用程序 - dex(Dalvik 可执行文件);
    • classes.dex(Dalvik 可执行文件)- 一个文件(通常是一个),它以 JVM Dalvik 和 ART 的专有字节码格式存储命令;
    • Android Runtime(ART) 和Dalvik(by Google) 作为 JVM,即 将 dex(专有字节码)命令运行时/解释为机器码(详见此处):
      • Dalvik使用范式JIT(Just-In-Time),即 在程序执行期间编译为机器代码;
        • Dalvik已被Android RuntimeAndroid 5.0“棒棒糖”取代;
      • Android Runtime(ART) 使用AOT( Ahead-Of-Time ) 范式,即 在程序执行之前编译为机器代码(在 Android 的情况下 - 在.apk从 play 市场安装期间):
        • Android Runtime使用文件dex(Dalvik 可执行文件),因此向后兼容DalvikAndroid 中的专有字节码应用程序;
    • machine code- 针对特定处理器架构的一组指令。

    注意:应该理解,例如使用 tools 工具包Jack时,构建过程看起来会有点不同: .java -> .jack -> .dex,但是在这个答案的框架内,我们可能不会偏离标准工具的考虑,所以我们将省略它的使用。

    Android中的应用程序生命周期:

    在 Android JVM 中执行前的打包(打包)和安装(安装)应用程序方面,与经典的类 JVM 版本有许多不同之处。该过程可以描述如下:

    1. 源码编译:

      • .java -(javac)-> .class -(dexer)-> classes.dex;
    2. 程序集apk(Android 包):

      • classes.dex+ resources files -(aapt)-> .apk;
    3. 签名apk:

      • .apk -(jarsigner + zipalign)-> signed .apk;
    4. 安装apk:

      1. 达尔维克:

        • classes.dex -(dexopt)-> odex(优化的 dex)或quickened dex:
          • dex文件的优化版本:优化操作码,从虚拟方法表(vtable)中替换被调用方法的地址/索引,等等;
      2. Android 运行时 (ART):

        • classes.dex -(dex2oat)-> OAT version of classes.dex( dex+ native machine code),即 专有字节码格式被转换为特定于处理器 (CPU) 的机器代码,该处理器 (CPU) 安装在执行安装的设备(例如,移动设备)中。结果放入ELF(Executable and Linkable Format)共享对象中;
    5. 应用启动:

      1. 单击应用程序时,服务进程(ActivityManagerService)将应用程序启动命令写入传入命令的套接字;
      2. linux process Zygote,其中加载了Android JVM(Dalvik / ART),侦听此套接字并在fork()收到启动应用程序的命令时执行其进程;
        • 该进程Zygote出于优化原因预加载核心 Android 库,因此子进程将获得一个预热的VM:
          • 从头开始创建一个进程,将所有必要的库加载到其中并预热JVM 将花费更多时间;
        • 换句话说,每个 Android 应用程序都在其自己的 JVM 实例中运行,并且在相对子进程中运行Zygote(进程的名称,可以说是提示);
        • Android 运行在轻量级 Linux 操作系统之上,因此 Zygote 进程由操作系统初始化脚本(init.rc,详见此处)启动;
      3. 将相应的运行 Android 应用程序加载到forkedELF 共享对象的子进程中(参见上文段落)。

    请参阅此处、此处和此处了解更多详细信息。

    结论:

    真希望在研究了经典JVM兼容和Android应用的运行原理之后,你自己已经得出了以下结论(整个答案导致你自己意识到这一点):

    • 使用一些抽象/中间代码(字节码)基于概念创建应用程序,它本身只会让您有机会为适当的 CPU 架构和 OS API 实现该字节码的解释;
    • .apkAndroid 文件不再包含标准 JVM 可以解释的经典 JVM 字节码(如 HotSpot),而是一些专用于 Android 特定 JVM(Dalvik 和 ART)的字节码 - classes.dex;
    • 程序入口点:
      • 经典的 JVM 可执行应用程序 (JAR) 有一个明确的入口点:
        • 创建一个包含该方法的类public static void main(String[] args),其指示必须在中描述META-INF/MANIFEST.MF;
      • Android 应用没有明确的入口点:
        • 他们描述了自己的文件AndroidManifest.xml,因此他们“订阅”某些事件(例如,到onCreatein Activity),即 系统是事件驱动的;
    • 从理论上讲,您可以尝试编写程序的源代码,在此基础上您将组装一个可执行的 jar 文件(见上文)和 Andorid .apk(见上文),但这将是两个独立的文件,具有不同的内容:
      • 例如,通过为同一个项目中的两个不同程序集准备配置(当然,不要分离通用的、可重用的源代码和资源文件):
        1. 为 Android 和 Classic JVM 分隔资源文件;
        2. 分隔一些源文件:
          1. 带有经典 JVM 入口点及其配置的文件META-INF/MANIFEST.MF;
          2. 具有从 Android 内核订阅的事件(事件)和它们的配置的文件AndroidManifest.xml;
        3. 在构建系统中创建两个不同的配置文件(例如,在 maven 或 gradle 中),每个配置文件不仅会在构建过程中使用共享资源,还会使用专门为其分配的资源(参见上面的段落);
    • 理论上,如果你完全模仿 Andorid 系统环境,你可以在不同的操作系统上运行你的 Andorid 应用程序,即 如果您独立实现一个模仿 Android 操作系统行为的事件驱动引擎,并使用 Android API 处理来自 Andorid 应用程序的相应命令,即 将 Andorid API 命令转换为运行应用程序的操作系统(Linux、MacOS、Windows)的 API,或使用系统虚拟化工具:
      • 还有一些关于 VM 支持Dalvik和Android Runtime字节码命令转换为机器码命令的问题native machine code() ,还有台式机(Intel、AMD,即基于x86 和 x64架构的处理器,即CISC):
        • 所用处理器架构的这些差异是由于在解决方案的设计阶段确定的差异造成的:
          • 经典 JVM 是基于栈机(stack-based architecture)的概念;
          • Android JVM是基于注册机(register-based architecture)的概念;
            • 您可以在此处和此处阅读堆栈和寄存器机器之间的区别;
        • 也许解决这个问题最简单的方法是使用虚拟化工具;
        • 您可以在此处阅读有关处理器架构差异的更多信息;
      • 如您所知,这是一项相当费力的任务,因此,您已经为您的操作系统编写了自己的 Andorid 模拟器。

    可以在此处找到 Java 与 Android API 比较的简短描述。

    • 17
  2. Best Answer
    Alex_Skvortsov
    2020-03-17T01:27:44Z2020-03-17T01:27:44Z

    更新:StateItPrimitive 的回答提供了对 Java 和 Android 应用程序之间差异的更多技术理解。

    不可以,您不能在 Windows 上从 Google Play Market 安装 Java 应用程序。

    该问题的作者非常正确地指出,Java 应用程序在设备之间是 100% 可移植的,但来自 Play Market 的 Android 应用程序不能被视为(通常)Java 应用程序。

    Android 应用程序要正常工作,除了 Java 虚拟机外,还需要特定的操作系统环境、标准资源文件等等。

    如果您查看 Java 应用程序和 Android 应用程序的源代码,这很容易理解。在 Android 应用程序中,您不会找到实际启动应用程序的 main() 函数。Android 应用程序不是由用户启动,而是由操作系统完全控制应用程序的生命周期。在 Android 操作系统之外,为其编写的应用程序无法启动。

    但是,虽然这不是提问者的意思,但如果您想在 Windows 上安装应用程序以进行测试(或播放),那么您可以简单地使用模拟器。

    Ps 打个比方。我们可以说 Play Market 应用程序是应用程序的一部分。为了使这样的一块成为一个成熟的 Java 应用程序,它必须辅以一定的 Java 代码和资源。这部分存储在 Android 操作系统中(以及针对不同版本和设备制造商的自己的操作系统)。

    PPs 我找到了一个解释,其中单词更好javarush。从那里引用

    正如我已经提到的,Android 操作系统使用 Java 来开发应用程序。您可以使用 Google 提供的 Java API 编写 Android 应用程序代码,然后将其编译成类文件。这是相似性结束的地方。Android 不使用 Java 虚拟机 (JVM) 来执行类文件,而是使用 Dalvik 虚拟机,它不是真正的 JVM,并且不能使用 Java 字节码。为了在 Dalvik 虚拟机上运行,​​类文件被编译成 DEX 格式(Dalvik EXecutable - Dalvik 可执行文件)。转换为 DEX 格式后,类文件与其他资源一起组合成 Android 包 (APK),以便在各种设备上分发和安装。

    这篇文章已经很过时了,但它传达了主要思想。

    • 15
  3. user376386
    2020-03-16T23:53:02Z2020-03-16T23:53:02Z

    不,不幸的是它不会那样工作。应用程序最初是为 Android 编写的。该界面不仅不适用于操作系统 Windows,而且它们根本无法启动。如果你真的需要它,你可以通过模拟器(Bluestacks、Nox...)运行它。

    是的,导入和编译都是可能的,但代价是 Java 机器。但是,该程序本身是为 Android 编写的。如果您确定自己是对的,那么如果您现在已经为我回答了这个问题,那么问题的意义何在?

    • 0

相关问题

  • wpcap 找不到指定的模块

  • 如何以编程方式从桌面应用程序打开 HTML 页面?

  • Android Studio 中的 R.java 文件在哪里?

  • HashMap 初始化

  • 如何使用 lambda 表达式通过增加与原点的距离来对点进行排序?

  • 最大化窗口时如何调整元素大小?

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    如何从列表中打印最大元素(str 类型)的长度?

    • 2 个回答
  • Marko Smith

    如何在 PyQT5 中清除 QFrame 的内容

    • 1 个回答
  • Marko Smith

    如何将具有特定字符的字符串拆分为两个不同的列表?

    • 2 个回答
  • Marko Smith

    导航栏活动元素

    • 1 个回答
  • Marko Smith

    是否可以将文本放入数组中?[关闭]

    • 1 个回答
  • Marko Smith

    如何一次用多个分隔符拆分字符串?

    • 1 个回答
  • Marko Smith

    如何通过 ClassPath 创建 InputStream?

    • 2 个回答
  • Marko Smith

    在一个查询中连接多个表

    • 1 个回答
  • Marko Smith

    对列表列表中的所有值求和

    • 3 个回答
  • Marko Smith

    如何对齐 string.Format 中的列?

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5