Android 中的 Java 7 语言功能

发布于 2024-11-30 15:16:07 字数 104 浏览 1 评论 0原文

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

Just wondering if anyone has tried using new Java 7 language features with Android?
I know that Android reads the bytecode that Java spits out and turns it to dex. So I guess my question is can it understand the bytecode of Java 7?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

箹锭⒈辈孓 2024-12-07 15:16:07

如果您使用的是 Android Studio,则应自动启用 Java 7 语言,无需任何补丁。 Try-with-resource 需要 API 级别 19+,并且缺少 NIO 2.0 的东西。

如果您无法使用 Java 7 功能,请参阅 @Nuno 关于如何编辑 build 的答案。 gradle

以下内容仅供历史参考。


Java 7 的一小部分当然可以与 Android 一起使用(注:我只在 4.1 上测试过)。

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

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

  • 文件→项目结构→模块→(在第二个窗格中选择模块)→语言级别→(选择“7.0 - Diamonds、ARM、multi-catch 等”)

< img src="https://i.sstatic.net/1z7iH.png" alt="在 IntelliJ 上启用 Java 7">

这仅允许 Java 7 语言功能,你几乎无法从中受益任何事情的一半改进也来自于图书馆。您可以使用的功能是那些不依赖于库的功能:

  • Diamond 运算符 (<>)
  • 字符串切换
  • Multiple-catch (catch (Exc1 | Exc2 e))
  • 数字文字中的下划线 (1_234_567)
  • 二进制文字 (0b1110111)

尚无法使用:

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

...“还”:) 事实证明,虽然 Android 的库的目标是 1.6,但 Android 源代码确实包含类似 AutoCloseable 和传统Closeable 确实继承来自 AutoCloseable(不过确实缺少 SafeVarargs)。我们可以通过反射来确认它的存在。它们被隐藏只是因为 Javadoc 具有 @hide 标记,这导致“android.jar”不包含它们。

已经存在问题 如何构建具有隐藏和可用内部 API 的 Android SDK? 了解如何恢复这些方法。您只需要将当前平台现有的“android.jar”引用替换为我们自定义的引用,然后许多 Java 7 API 就可以使用了(过程与 Eclipse 中的过程类似。检查一下)项目结构 → SDK。)

除了 AutoCloseable 之外,(仅)还揭示了以下 Java 7 库功能

  • ConcurrentModificationException、LinkageError 和 AssertionError 中的异常链构造
  • 函数基元的 .compare() 方法:Boolean.compare()、Byte.compare()、Short.compare()、Character.compare()、Integer.compare()、Long.compare()。
  • 货币:.getAvailableCurrency()、.getDisplayName () (但没有 .getNumericCode())
  • BitSet:.previousSetBit()、.previousClearBit()、.valueOf()、.toLongArray()、.toByteArray()
  • 集合: .emptyEnumeration(), .emptyIterator(), .emptyListIterator()
  • 自动关闭
  • Throwable: .addSuppressed()、.getSuppressed() 和 4 参数构造函数
  • 字符:.compare()、.isSurrogate()、.getName()、.highSurrogate()、 .lowSurrogate()、.isBmpCodePoint()(但没有 .isAlphabetic() 和 .isIdegraphic())
  • 系统: .lineSeparator() (未记录?)
  • java.lang.reflect.Modifier: .classModifiers()、.constructorModifiers()、.fieldModifiers()、.interfaceModifiers()、.methodModifiers()
  • 网络接口: .getIndex(), .getByIndex()
  • InetSocketAddress: .getHostString()
  • InetAddress: .getLoopbackAddress()
  • 记录器:.getGlobal()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer: .hasQueuedPredecessors()
  • < a href="http://docs.oracle.com/javase/7/docs/api/java/util/zip/DeflaterOutputStream.html" rel="noreferrer">DeflaterOutputStream:带有“syncFlush”的 3 个构造函数。
  • Deflater:.NO_FLUSH、.SYNC_FLUSH 、 .FULL_FLUSH、 .deflate() 带 4 个参数

基本上就这些了。特别是,NIO 2.0 还不存在,Arrays.asList 仍然不是 @SafeVarargs。

If you are using Android Studio, the Java 7 language should be enabled automatically without any patches. Try-with-resource requires API Level 19+, and NIO 2.0 stuff are missing.

If you can't use Java 7 features, see @Nuno's answer on how to edit your build.gradle.

The following is for historical interest only.


A small part of Java 7 can certainly be used with Android (note: I have only tested on 4.1).

First of all, you could not use Eclipse's ADT because it is hard-coded that only Java compiler 1.5 and 1.6 are compliant. You could recompile ADT but I find there is no simple way to do that aside from recompiling the whole Android together.

But you don't need to use Eclipse. For instance, Android Studio 0.3.2, IntelliJ IDEA CE and other javac-based IDEs supports compiling to Android and you could set the compliance even up to Java 8 with:

  • File → Project Structure → Modules → (pick the module at the 2nd pane) → Language level → (choose "7.0 - Diamonds, ARM, multi-catch, etc.")

Enabling Java 7 on IntelliJ

This only allows Java 7 language features, and you can hardly benefit from anything since a half of improvement also comes from the library. Features you could use are those which do not depend on the library:

  • Diamond operator (<>)
  • String switch
  • Multiple-catch (catch (Exc1 | Exc2 e))
  • Underscore in number literals (1_234_567)
  • Binary literals (0b1110111)

And these features cannot be used yet:

  • The try-with-resources statement — because it requires the non-existing interface "java.lang.AutoCloseable" (this can be used publicly in 4.4+)
  • The @SafeVarargs annotation — because "java.lang.SafeVarargs" does not exist

... "yet" :) It turns out that, although Android's library is targeting for 1.6, the Android source does contain interfaces like AutoCloseable and traditional interfaces like Closeable does inherit from AutoCloseable (SafeVarargs is really missing, though). We could confirm its existence via reflection. They are hidden simply because the Javadoc has the @hide tag, which caused the "android.jar" not to include them.

There is already as existing question How do I build the Android SDK with hidden and internal APIs available? on how to get those methods back. You just need to replace the existing "android.jar" reference of the current Platform with our customized one, then many of the Java 7 APIs will become available (the procedure is similar to that in Eclipse. Check Project Structure → SDKs.)

In additional to AutoCloseable, (only) the following Java 7 library features are also revealed:

  • Exception chaining constructors in ConcurrentModificationException, LinkageError and AssertionError
  • The static .compare() methods for primitives: Boolean.compare(), Byte.compare(), Short.compare(), Character.compare(), Integer.compare(), Long.compare().
  • Currency: .getAvailableCurrencies(), .getDisplayName() (but without .getNumericCode())
  • BitSet: .previousSetBit(), .previousClearBit(), .valueOf(), .toLongArray(), .toByteArray()
  • Collections: .emptyEnumeration(), .emptyIterator(), .emptyListIterator()
  • AutoCloseable
  • Throwable: .addSuppressed(), .getSuppressed(), and the 4-argument constructor
  • Character: .compare(), .isSurrogate(), .getName(), .highSurrogate(), .lowSurrogate(), .isBmpCodePoint() (but without .isAlphabetic() and .isIdeographic())
  • System: .lineSeparator() (undocumented?)
  • java.lang.reflect.Modifier: .classModifiers(), .constructorModifiers(), .fieldModifiers(), .interfaceModifiers(), .methodModifiers()
  • NetworkInterface: .getIndex(), .getByIndex()
  • InetSocketAddress: .getHostString()
  • InetAddress: .getLoopbackAddress()
  • Logger: .getGlobal()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer: .hasQueuedPredecessors()
  • DeflaterOutputStream: the 3 constructors with "syncFlush".
  • Deflater: .NO_FLUSH, .SYNC_FLUSH, .FULL_FLUSH, .deflate() with 4 arguments

That's basically all. In particular, NIO 2.0 does not exist, and Arrays.asList is still not @SafeVarargs.

别念他 2024-12-07 15:16:07

编辑:在撰写本文时,最新版本是 Android 9 和 Eclipse Indigo。从那以后事情发生了变化。

  • 实用答案

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

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

The 7 is the onlyinstalled on this machine

  • 然后我安装了一个全新的 Eclipse Indigo 并检查它实际上是使用JDK 7 (好吧,因为这是唯一的一个,而且这是我选择的一个,所以我会感到惊讶)
  • 然后我安装了最新版本的 Android SDK(编辑:Honeycomb,API13,在撰写本文时)。它找到了我的 JDK 7 并正确安装。 ADT 也是如此。

  • 但是当我尝试编译和运行 Hello Word Android 应用程序时,我感到惊讶。兼容性设置为 Java 6,无法强制其为 Java 7:

Compatibility is Limited to Java 6

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

Eclipse 将自身限制为级别 6 兼容性

因此,我可以使用 Hello World 以及其他更复杂的应用程序,并使用 SQLiteListviewSensor相机,但是这只能证明 Java 7 的兼容性处理似乎做得很好并且可以与 Android 配合使用。

那么,有人尝试使用旧的 Ant 来绕过上面看到的 Eclipse 限制吗?

  • 理论答案

无论如何,该 SDK 设计为与 Java 5 或 6 一起使用,如此处所述。

我们可能有一些可以与 Java 7 配合使用的东西,但它会“意外”地工作。 DEX的建设可能正常,也可能不正常,DEX一旦建成,也可能正常,也可能不正常。这是因为使用不合格的 JDK 根据定义会产生不可预测的结果。

即使有人在普通 Java 7 下成功构建了 Android 应用程序,这也不符合 JDK 的要求。应用于另一个应用程序的相同过程可能会失败,或者生成的应用程序可能存在与该 JDK 的使用相关的错误。不推荐。

对于那些参与 Web 应用程序开发的人来说,这与在仅适用于 Java 4 的应用程序服务器(例如 Weblogic 8)下部署在 Java 5 或 6 下构建的 Web 应用程序完全相同。这可能有效,但是除了尝试之外,不能推荐将其用于其他目的。

EDIT: At the time this was written, the latest release was Android 9 and Eclipse Indigo. Thing have changed since then.

  • Practical answer

Yes, I have tried. But this is not a great test as the compatibility was limited to level 6 with no way (no simple way at least) to really use java 7:

  • First I installed a JDK7 on a machine that had no other JDK installed - Eclipse and Android are not installed either:

The 7 is the only installed on this machine

  • Then I installed a brand new Eclipse Indigo and checked it was actually using the JDK 7 (well, as this is the only one and as this is the one I've selected I would have been surprised)

The 7 is the only used by this Eclipse

  • Then I installed the latest version of the Android SDK (EDIT: Honeycomb, API13, at the time this post was written). It found my JDK 7 and installed properly. The same for ADT.

  • But I had a surprise when trying to compile and run a Hello Word Android app. The compatibility was set to Java 6 with no way to force it to Java 7:

Compatibility is limited to Java 6

  • I tried with a non-Android project, a regular Java one, and I had the explanation. The compatibility level seems to be limited by Eclipse (see the message at bottom of the following image):

Eclipse limits itself to level 6 compatibility

So I had Hello World working, and also other apps, more complicated and using SQLite, Listview, Sensor and Camera, but this only proves that the compatibility handling of Java 7 seems to be well done and working with Android.

So, did someone try with the good old Ant, to bypass the Eclipse limitation seen above?

  • Theroetical answer

Anyway, the SDK is designed to be used with Java 5 or 6, as explained here.

We may have something working with Java 7, but it would be working "by accident". The building of the DEX may work properly or not, and once the DEX built, it may work or not. This because using a non-qualified JDK gives unpredictable results by definition.

Even if someone has succesfully built an Android app under plain Java 7, this does not qualify the JDK. The same process applied to another application may fail, or the resulting application may have bugs tied to the use of that JDK. Not recommended.

For those who are involved on webapps development, this exactly the same as deploying a web application built under Java 5 or 6 under an application server qualified for Java 4 only (let's say Weblogic 8 for example). This may work, but this is not something that can be recommended for other purposes than trying.

寒尘 2024-12-07 15:16:07

引用自 dalvikvm.com:

dx包含在Android SDK中,将常规Java编译器编译的Java类的Java类文件转换为另一种类文件格式(.dex格式)

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

据我所知,Java 7中只有invokedynamic被添加到了JVM字节码中,其余的都兼容Java 6。Java语言本身并没有使用invokedynamic。其他新功能,例如使用 Stringswitch 语句或 multi-catch 只是语法糖,不需要更改字节码。例如,多重catch 只是为每个可能的异常复制catch 块。

唯一的问题应该是 Android 中缺少 Java 7 中引入的新类,例如 AutoCloseable,所以我不确定是否可以使用 try-with-资源功能(有人尝试过吗?)。

对此有何评论?我错过了什么吗?

Quote from dalvikvm.com:

dx, included in the Android SDK, transforms the Java Class files of Java classes compiled by a regular Java compiler into another class file format (the .dex format)

That means, the .java source file does not matter, it's only the .class bytecode.

As far as I know, only invokedynamic was added to the JVM bytecode in Java 7, the rest is compatible to Java 6. The Java language itself does not use invokedynamic. Other new features, like the switch statement using Strings or the multi-catch are just syntatic sugar and did not require byte code changes. For example, the multi-catch just copies the catch-block for each possible exception.

The only problem should be that the new classes introduced in Java 7 are missing in Android, like AutoCloseable, so I'm not sure if you can use the try-with-resources feature (somebody tried it?).

Any comments on that? Am I missing something?

眼趣 2024-12-07 15:16:07

从 Android SDK v15 以及 Eclipse 3.7.1 开始,Android 开发支持 Java 7。将源兼容性设置为 1.7 要求将生成的 .class 文件兼容性设置为 1.7,这会导致 Android 编译器出现以下错误:

Android 需要编译器合规级别 5.0 或 6.0。找到了“1.7”。请使用Android工具>修复项目属性。

As of the Android SDK v15, along with Eclipse 3.7.1, Java 7 is not supported for Android development. Setting the source compatibility to 1.7 mandates setting the generated .class file compatibility to 1.7, which leads to the following error by the Android compiler:

Android requires compiler compliance level 5.0 or 6.0. Found '1.7' instead. Please use Android Tools > Fix Project Properties.

软糯酥胸 2024-12-07 15:16:07

为了扩展 @KennyTM 的上述答案,如果您的目标是 4.0.3 及更高版本 (minSdkVersion=15),您可以通过向目标的 SDK android.jar 添加一些类来使用隐藏的 API 。

完成此操作后,您可以在任何 Closeable 上使用 try-with-resources,以及在您自己的类中实现 AutoCloseable。

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

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

另外值得注意的是,在过去的几个月里,Elliott Hughes 做了一些提交到 Android 树:完成 AutoCloseable添加了 SafeVarargs取消隐藏各种API, 修复了 Throwable 的受保护构造函数添加了对 dx 中版本 51 类文件的支持。所以,终于有了一些进展。

编辑(2014 年 4 月):

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

对于面向 4.0.3 及更高版本 (minSdkVersion=15) 的应用,在 Android Studio 中使用 try-with-resources 的最佳方法是将以下 compileOptions 添加到您的 < code>build.gradle:

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 会抱怨 try-with-resources 不能与此 API 级别一起使用,但我的经验是可以。该项目将在 4.0.3 及更高版本的设备上构建和运行,不会出现任何问题。我没有遇到任何问题,该应用程序已安装到超过 50 万台设备中。

Android Studio error

要忽略此警告,请将以下内容添加到您的 lint.xml 中:

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

To expand on the above answer by @KennyTM, if you are targeting 4.0.3 and above (minSdkVersion=15), you can use the hidden APIs by adding a few classes to your target's SDK android.jar.

Once you do this, you can use try-with-resources on any Closeable, as well as implement AutoCloseable in your own classes.

I've made a zip containing sources and binaries of all the classes that needed to be modified in android.jar to make these APIs available. You just need to unpack it and add the binaries to your
android-sdk/platforms/android-NN/android.jar

You can download it from here: http://db.tt/kLxAYWbr

Also of note is that, in the past couple of months, Elliott Hughes has made a few commits to the Android tree: finished off AutoCloseable, added SafeVarargs, unhidden various APIs, fixed Throwable's protected constructor and added support for version 51 class files in dx. So, there is finally some progress going on.

Edit (April 2014):

With the release of SDK 19 it is no longer necessary to patch android.jar with the additional APIs.

The best method to use try-with-resources in Android Studio for an app that targets 4.0.3 and above (minSdkVersion=15) is add the following compileOptions to your build.gradle:

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 will complain that try-with-resources can't be used with this API level, but my experience is that it can. The project will build and run without issue on devices with 4.0.3 and above. I've experienced no issues with this, with an app that has been installed into 500k+ devices.

Android Studio error

To ignore this warning, add the following to your lint.xml:

<issue id="NewApi">
    <ignore regexp="Try-with-resources requires API level 19"/>
</issue>
魄砕の薆 2024-12-07 15:16:07

似乎让这个与纯蚂蚁一起工作有点麻烦。

但它对我有用: http://www.informit.com/articles/article .aspx?p=1966024

It seems that getting this to work with pure ant is a bit of a kludge.

But it worked for me: http://www.informit.com/articles/article.aspx?p=1966024

时光瘦了 2024-12-07 15:16:07

为了在 Android 的基于 ant 的构建系统构建的代码中使用 Java 7 功能,只需将以下内容放入项目根目录的 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>

In order to use Java 7 features in code build by Android's ant based build system, simply put the following in your custom_rules.xml in your projects root directory:

custom_rules.xml:

<project name="custom_android_rules">
    <property name="java.target" value="1.7" />
    <property name="java.source" value="1.7" />
</project>
梦断已成空 2024-12-07 15:16:07

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

但是太多了如果我将其添加到我当前从事的项目中,则会存在风险。所以我会等到Google正式支持Java 7。

Some people might be interested in this git project I've found, that seems to allow to run Java 7 on android.
https://github.com/yareally/Java7-on-Android

However too much of a risk if I add this in the current project I work on. So I'll wait until Google to officially support Java 7.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文