Java7语言与 Android 的特性

只是想知道是否有人尝试过在 Android 中使用新的 Java7语言特性? 我知道 Android 读取 Java 吐出的字节码并将其转换为 dex。所以我的问题是它能理解 Java7的字节码吗?

49864 次浏览

编辑: 在写这篇文章的时候,最新的版本是 Android 9和 Eclipse 靛蓝。从那以后,一切都变了。

  • 实用的回答

是的,我试过了。但是这并不是一个很好的测试,因为兼容性仅限于级别6,没有办法(至少没有简单的方法)真正使用 java 7:

  • 首先,我在一台没有安装其他 JDK 的机器上安装了一个 JDK7—— Eclipse 和 Android 也没有安装:

The 7 is the only installed on this machine

  • 然后我安装了一个全新的 Eclipse 靛蓝,并检查它实际上使用的是 JDK 7(好吧,因为这是唯一的一个,因为这是我选择的一个,我会感到惊讶)

The 7 is the only used by this Eclipse

  • 然后我安装了 Android SDK 的最新版本(编辑: Honeycomb,API13,在写这篇文章的时候)。它找到了我的 JDK7并正确安装。ADT 也一样。

  • 但是当我尝试编译并运行一个 Hello Word Android 应用程序时,我感到很惊讶。兼容性被设置为 Java6,没有办法强制它到 Java7:

Compatibility is limited to Java 6

  • 我尝试了一个非 Android 项目,一个普通的 Java 项目,我得到了解释。兼容性级别似乎受到 Eclipse 的限制(参见下图底部的消息) :

Eclipse limits itself to level 6 compatibility

所以我让 你好,世界和其他应用程序运行,它们更复杂,使用的是 SQLiteListviewSensorCamera,但这只能证明 Java 7的兼容性处理看起来做得很好,可以与 Android 一起工作。

那么,是否有人尝试使用老式的 Ant 来绕过上面看到的 Eclipse 限制呢?

  • 理论上的答案

无论如何,SDK 被设计成与 Java5或 Java6一起使用,正如 给你所解释的那样。

我们可能有一些东西可以与 Java7一起工作,但它可能是“偶然”工作的。DEX 的建设可能工作正常或不,一旦 DEX 建设,它可能工作或不。这是因为使用非限定的 JDK 会根据定义产生不可预测的结果。

即使有人已经成功地在普通的 Java7下构建了 Android 应用程序,这也不能使 JDK 合格。应用于其他应用程序的相同进程可能会失败,或者产生的应用程序可能有与该 JDK 的使用相关的 bug。不推荐。

对于那些参与 webapps 开发的人来说,这完全等同于部署一个基于 Java5或 Java6构建的 web 应用程序,而这个应用程序服务器只适用于 Java4(例如 Weblogic 8)。这可能有效,但是除了尝试之外,不建议将其用于其他目的。

引自 dalvikvm.com:

Dx,包含在 Android SDK 中,将由常规 Java 编译器编译的 Java 类的 Java Class 文件转换为另一种类文件格式(。索引格式)

这意味着,. java 源文件并不重要,它只是. class 字节码。

据我所知,在 Java7中只有 InvokedDynamic被添加到 JVM 字节码中,其余的与 Java6兼容。Java 语言本身不使用 InvokedDynamic。其他新特性,如使用 绳子开关语句或多 接住只是语法糖,不需要修改字节码。例如,multi-接住只是为每个可能的异常复制 接住块。

唯一的问题应该是 Java 7中引入的新类在 Android 中缺失了,比如 自动关闭,所以我不确定您是否可以使用 试试看-with-resources 特性(有人试过吗?).

有什么意见吗,我漏掉了什么吗?

从 Android SDK v15开始,与 Eclipse 3.7.1一起,Java 7在 Android 开发中得到了 不是的支持。将源兼容性设置为1.7。类文件兼容到1.7,这导致 Android 编译器出现以下错误:

Android 需要编译器符合级别5.0或6.0。找到“1.7”代替。请使用 Android Tools > Fix Project Properties。

如果您使用的是 安卓工作室,那么应该自动启用 Java7语言,而不需要任何补丁。使用资源尝试需要 API 级别19 + ,而缺少 NIO 2.0内容。

如果不能使用 Java7特性,请参阅 @ Nuno关于如何编辑 build.gradle的答案。

以下内容仅供参考。


Java7的一小部分当然可以用于 Android (注意: 我只在4.1上测试过)。

首先,您不能使用 Eclipse 的 ADT,因为只有 Java 编译器1.5和1.6兼容的 是硬编码的。您可以重新编译 ADT,但是我发现除了重新编译整个 Android 之外,没有其他简单的方法可以做到这一点。

但是您不需要使用 Eclipse。例如,< strong > Android Studio 0.3.2 IntelliJ IDEA CE 和其他基于 javac 的 IDE 支持编译到 Android 还有,你甚至可以通过以下方式设置符合性到 Java 8:

  • 文件→项目结构→模块→(在第二个面板选择模块)→语言级别→(选择“7.0-钻石,ARM,多捕获等”)

Enabling Java 7 on IntelliJ

这只允许 Java7语言特色,而且您几乎不可能从任何事情中受益,因为一半的改进也来自于这个库。您可以使用的特性是那些不依赖于库的特性:

  • 钻石操作员(<>)
  • 字符串开关
  • 多捕获(catch (Exc1 | Exc2 e))
  • 在数字字面值中加下划线(1_234_567)
  • 二进制文字(0b1110111)

而且这些特性不能使用 还没有:

  • try-with-resources 语句ーー因为它需要不存在的接口“ java.lang. AutoCloseable”(这可以在4.4 + 中公开使用)
  • @ SafeVarargs 注释ーー因为“ java.lang. SafeVarargs”不存在

事实证明,尽管 Android 的库目标是1.6,但 Android 源代码确实包含像 自动关闭这样的接口,而像 可以关闭这样的传统接口确实继承了 AutoCloseable (但 SafeVarargs 确实缺失了)。我们可以通过反射来确认它的存在。它们被隐藏仅仅是因为 Javadoc 有 @hide标记,这导致“ android.jar”不包含它们。

关于如何找回这些方法,已经存在一些问题。您只需使用定制的平台对当前平台的现有“ android.jar”引用进行 更换,然后就可以使用许多 Java 7 API (该过程类似于 Eclipse 中的过程)。检查项目结构→ SDK)

除了 AutoCloseable 之外,(只)还显示了以下 Java7图书馆特色:

  • 异常链/修改/异常、 LinkageError 和断言/错误中的构造函数
  • 用于基元的静态. ゑ()方法: Boolean. ゑ()、 Byte.ゑ()、 Short.ゑ()、 Personter.ゑ()、 Integer.ゑ()、 Long.ゑ()。
  • Currency : . getUtiableCurrences () ,. getDisplayName ()(但是 没有.getNumericCode ())
  • BitSet : . previousSetbit () ,. previousClearbit () ,. valueOf () ,. toLongArray () ,. toByteArray ()
  • 集合 : . empty枚举()、 . emptyIterator ()、 . emptyListIterator ()
  • 自动关闭
  • Throwable : . addSuppress()、 . getSuppress()和4参数构造函数
  • 字符 : . ゑ() ,. isSurgate () ,. getName () ,. highSurgate () ,. lowSurgate () ,. isBmpCodePoint ()(但是 没有. isAlphabetic ()和. isIdeography ())
  • 系统: . line 分离器()(未记录?)
  • 反射. 修饰符 : . class修饰符() ,. structor修饰符() ,. field修饰符() ,. interface修饰符() ,. method修饰符()
  • NetworkInterface : . getIndex () ,. getByIndex ()
  • InetSocketAddress : . getHostString ()
  • InetAddress : . getLoopbackAddress ()
  • Logger : . getGlobal ()
  • 并发 LinkedDeque
  • AbstractQueuedSynchronizer : . hasQueuedPredecors ()
  • DeflaterOutputStream : 带有“ syncFlush”的3个构造函数。
  • Deflater : . NO _ FLUSH,. SYNC _ FLUSH,. FULL _ FLUSH,. flate ()带有4个参数

这基本上就是全部了,特别是 NIO 2.0不存在,而且 Arrays.asList 仍然不是@SafeVarargs。

有些人可能对我发现的这个 git 项目感兴趣,它似乎允许在 android 上运行 Java7。 Https://github.com/yareally/java7-on-android

然而,如果我在当前工作的项目中添加这个,风险就太大了。所以我会等到 Google 正式支持 Java7。

要通过@KennyTM 扩展上面的答案,如果您的目标是4.0.3及以上版本(MinSdkVersion = 15) ,您可以通过向目标 SDK android.jar 添加几个类来使用隐藏的 API。

这样做之后,您就可以在任何 Closeable 上使用 try-with-resources,以及在自己的类中实现 AutoCloseable。

我做了一个压缩包,其中包含所有需要在 android.jar 中修改的类的源代码和二进制文件,以使这些 API 可用。您只需要将其解压缩并将二进制文件添加到您的 < br > android-sdk/Platform/android-NN/android.jar 中

你可以从这里下载: http://db.tt/kLxAYWbr

另外值得注意的是,在过去的几个月里,Elliott Hughes 已经对 Android 树做出了一些承诺: 完成自动关闭添加了 SafeVarargs不隐藏的各种 API固定 Throwable 的受保护构造函数增加了对 dx 中51版类文件的支持。所以,终于有了一些进展。

编辑(2014年4月) :

随着 SDK 19的发布,不再需要用附加的 API 来修补 android.jar。

对于目标为4.0.3及以上(MinSdkVersion = 15)的应用程序,在 Android Studio 中使用 try-with-resources 的最佳方法是在 build.gradle中添加以下 compileOptions:

android {
compileSdkVersion 19
buildToolsVersion '19.0.3'


defaultConfig {
minSdkVersion 15
targetSdkVersion 19
}


compileOptions {
sourceCompatibility JavaVersion.VERSION_1_7
targetCompatibility JavaVersion.VERSION_1_7
}
}

Android Studio 会抱怨在这个 API 级别无法使用 try-with-resources,但我的经验是它可以。该项目将在4.0.3及以上版本的设备上构建和运行,没有问题。我没有经历过这个问题,有一个应用程序已经安装到50万以上的设备。

Android Studio error

若要忽略此警告,请在 lint.xml中添加以下内容:

<issue id="NewApi">
<ignore regexp="Try-with-resources requires API level 19"/>
</issue>

看起来让这个工作与纯蚂蚁是一个有点拼凑。

但对我来说很有效: http://www.informit.com/articles/article.aspx?p=1966024

为了在 Android 的基于 ant 的构建系统的代码构建中使用 Java7特性,只需在你的项目根目录中的 custom_rules.xml中放入以下内容:

Custom_ rules. xml:

<project name="custom_android_rules">
<property name="java.target" value="1.7" />
<property name="java.source" value="1.7" />
</project>