Android的Java 7语言功能


188

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


10
另外,也许您可​​以使用Java 7语言功能,但可以编译为Java 6字节码?
MatrixFrog 2011年

2
现在,Android Studio在创建新项目时会通知您:“如果minSdkVersion小于19,则不能使用try-with-resources,但是其他Java 7语言功能也可以”
IgorGanapolsky 2013年

1
是的,我知道:)我们终于在项目中使用Java 7。
Daniel Ryan

Answers:


165

如果您使用的是Android Studio,则应自动启用Java 7 语言,而无需任何补丁。尝试资源要求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等”)

在IntelliJ上启用Java 7

这仅允许Java 7 语言功能,并且您几乎无法从中受益,因为一半的改进也来自库。您可以使用的功能是那些不依赖于库的功能:

  • 钻石操作员(<>
  • 弦开关
  • 多次捕获(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和传统接口,如可关闭不从AutoCloseable继承(SafeVarargs真的丢失,虽然)。我们可以通过反思来确认它的存在。它们之所以被隐藏仅仅是因为Javadoc具有@hide标签,从而导致“ android.jar”不包含它们。

已经存在一个问题,如何使用隐藏的和内部的API构建Android SDK?关于如何找回这些方法的知识。您只需要用我们自定义的平台替换当前平台的现有“ android.jar”引用,那么许多Java 7 API将可用(该过程类似于Eclipse中的过程。请检​​查项目结构→SDK。)

除了自动关闭功能之外,(仅)还显示了以下Java 7 库功能

  • ConcurrentModificationException,LinkageError和AssertionError中的异常链接构造函数
  • 用于原语的静态.compare()方法:Boolean.compare(),Byte.compare(),Short.compare(),Character.compare(),Integer.compare(),Long.compare()。
  • 货币:.getAvailableCurrencies()、. getDisplayName()(但不带 .getNumericCode())
  • BitSet:.previousSetBit()、. previousClearBit()、. valueOf()、. toLongArray()、. toByteArray()
  • 集合:.emptyEnumeration()、. emptyIterator()、. emptyListIterator()
  • 自动关闭
  • Throwable:.addSuppressed()、. getSuppressed()和四参数构造函数
  • 字符:.compare()、. isSurrogate()、. getName()、. highSurrogate()、. lowSurrogate()、. isBmpCodePoint()(但不包括 .isAlphabetic()和.isIdeographic())
  • 系统:.lineSeparator()(未记录?)
  • java.lang.reflect.Modifier:.classModifiers()、. constructorModifiers()、. fieldModifiers()、. interfaceModifiers()、. methodModifiers()
  • NetworkInterface:.getIndex()、. getByIndex()
  • InetSocketAddress:.getHostString()
  • InetAddress:.getLoopbackAddress()
  • 记录器:.getGlobal()
  • 并发链接双端队列
  • AbstractQueuedSynchronizer:.hasQueuedPredecessors()
  • DeflaterOutputStream:3个带有“ syncFlush”的构造函数。
  • Deflater:.NO_FLUSH,.SYNC_FLUSH,.FULL_FLUSH,.deflate()用4个参数

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


2
好答案。我希望在不久的将来能获得对jvm级别的全面支持,nio2而其他好东西肯定是个好消息。
SD

4
值得一提的是,AutoCloseable直到ICS(或直到HoneyComb),Android运行时中才存在接口。因此,即使您使用修补的android.jar,也会NoClassDefFoundError在2.x系统上收到。
Idolon

2
@deviant:这需要修改Dalvik VM,因为Java 8 lambda使用invokedynamic了Java 6的JVM不支持的
lambda。– kennytm

2
如果您要针对KitKat
JRaymond,2013年

4
现在可以在SDK 19(Android Kitkat)上使用资源进行尝试。参见tools.android.com/recent/androidstudio032released
Mohamed El-Nakib

70

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

  • 实际答案

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

  • 首先,我在未安装其他JDK的计算机上安装了JDK7-Eclipse和Android均未安装:

7是此计算机上唯一安装的

  • 然后,我安装了一个全新的Eclipse Indigo,并检查它是否实际上是在使用JDK 7(因为这是唯一的一个,并且因为这是我选择的那个,所以我会感到惊讶)

7是此Eclipse唯一使用的

  • 然后,我安装了最新版本的Android SDK(撰写本文时,编辑:Honeycomb,API13)。它找到了我的JDK 7并正确安装。ADT也是如此。

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

兼容性仅限于Java 6

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

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

因此,我不得不的Hello World的工作,以及其它的应用程序,更复杂和使用SQLiteListviewSensorCamera,但是这只能证明兼容性处理Java 7的似乎做得很好,与Android合作。

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

  • 理论答案

无论如何,SDK被设计成与Java 5或6一起使用,作为解释在这里

我们可能有一些使用Java 7的东西,但是它会“偶然地”工作。DEX的构建可能会正常工作或无法正常工作,DEX一旦构建,便可能会正常工作。这是因为使用不合格的JDK会产生无法预测的结果。

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

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


1
感谢您的详细审查。因此,您似乎无法使用Java 7语言功能,但仍将Java 7用作Java6。希望这种情况很快会有所改变:)
Daniel Ryan

这是在Eclipse中。使用Ant,这可能是可能的。我希望有人会做测试,我怪我自己太懒了:)
Shlublu 2011年

是的,Varga,但我认为编译器版本限制不是来自Ant,而是来自Eclipse。
Shlublu 2011年

2
还要注意,如果您使用的是多个Java版本,则提供的工具不兼容。我的意思是,如果您首先使用Java 6工具中的jarsigner对应用程序进行了签名,然后又安装了Java 7,并使用Java 7附带的jarsigner和与以前相同的密钥库对我们的应用程序进行了新版本签名将不匹配。 !
2012年

38

来自dalvikvm.com的报价:

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

这意味着.java源文件没有关系,只是.class字节码。

据我所知,在Java 7中仅将invokedynamic添加到JVM字节码中,其余与Java 6兼容。Java语言本身不使用invokedynamic。其他新功能,例如使用Stringswitch语句或multi- catch只是语法糖,不需要更改字节码。例如,多捕获仅针对每个可能的异常复制catch -block。

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

对此有何评论?我想念什么吗?


2
现在的问题是,如何配置Java 7源代码以将其编译为Java 6类文件,尤其是在eclipse中?
兰迪·苏吉安托

剩下的唯一问题是,您为什么还要打扰?
Warpzit 2011年

@Warpzit更大的问题应该是:为什么开发人员不会为所有这些混乱而烦恼?
阿米特(Amit)2012年

@Amit,因为他开始意识到Android与Java不同,并且为了使用Android,他必须使用所提供的工具。
Warpzit 2012年

2
@Warpzit他唯一的问题是“ Android可以理解Java 7吗? ”无知永远不是解决方案/答案...
Amit 2012年

12

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

Android要求编译器符合级别5.0或6.0。发现“ 1.7”。请使用Android工具>修复项目属性。


5

要扩展@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

另外值得注意的是,在过去的几个月里,埃利奥特·休斯已经取得了几次提交到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到您的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及更高版本的设备上构建并正常运行。对于已安装到500k +设备中的应用程序,我没有遇到任何问题。

Android Studio错误

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

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

1
我发现有趣的是,Android Studio代码警告说try-with-resources是API 13中的新增功能,我应该使用它。虽然没有时间实际测试它是否正常工作。
Daniel Ryan

1

看起来让它与纯蚂蚁一起工作似乎有点麻烦。

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


1
我寻找了很长时间。为了通过过滤文章来减少人们的麻烦,您需要在android提供的build.xml中更改`<property name =“ java.source” value =“ 1.5” />`行(而不是android中提供的您的项目!)。对我而言,它位于/opt/android-sdk-update-manager/tools/ant/build.xml中
Mateusz Kowalczyk

不,你不会。您可以使用来覆盖这些属性custom_rules.xml,请在这里查看我的答案:stackoverflow.com/a/24608415/194894
Flow

1

为了在基于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>

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.