web-dev-qa-db-ja.com

Java Androidを含む7つの言語機能

Androidで新しいJava 7言語機能を使用しようとした人がいるのではないかと考えていますか? AndroidはJavaが吐き出すバイトコードを読み取り、dexに変換することを知っています。私の質問は、Java 7のバイトコードを理解できるのでしょうか?

188
Daniel Ryan

Android Studioを使用している場合、Java 7languageを有効にする必要がありますパッチなしで自動的に。 Try-with-resourceにはAPIレベル19+が必要で、NIO 2.0のものがありません。

Java 7機能を使用できない場合は、build.gradleの編集方法に関する @ Nuno の回答を参照してください。

以下は、歴史的関心のみを目的としています。


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まで設定できます。

  • ファイル→プロジェクト構造→モジュール→(2番目のペインでモジュールを選択)→言語レベル→(「7.0-ダイヤモンド、ARM、マルチキャッチなど」を選択)

Enabling Java 7 on IntelliJ

これはJava 7言語機能のみを許可し、改善の半分はライブラリからも得られるため、何の恩恵も受けられません。使用できる機能は、ライブラリに依存しない機能です。

  • ダイアモンド演算子(<>
  • ストリングスイッチ
  • マルチキャッチ(catch (Exc1 | Exc2 e)
  • 数字リテラルの下線(1_234_567
  • バイナリリテラル(0b1110111

そして、これらの機能は使用できませんyet

  • try- with-resourcesステートメント—存在しないインターフェイス "Java.lang.AutoCloseable"が必要なため(これは4.4以降でパブリックに使用できます)
  • @SafeVarargsアノテーション—「Java.lang.SafeVarargs」が存在しないため

... "まだ" :) Androidのライブラリは1.6をターゲットにしていますが、Androidソースには AutoCloseable などのインターフェースと Closeable はAutoCloseableから継承します(ただし、SafeVarargsは実際にはありません)。反射によってその存在を確認できました。 Javadocに@hideタグがあるため、「Android.jar」にそれらが含まれないため、これらは単に非表示になります。

既存の質問としてすでに存在します非表示および内部APIを使用してAndroid SDKをビルドするにはどうすればよいですか?これらのメソッドを元に戻す方法について。必要なのは、現在のプラットフォームの既存の「Android.jar」参照を、カスタマイズされたプラットフォームでreplaceするだけです。そうすると、Java 7 APIの多くが利用可能になります(手順はEclipseの手順と似ています。プロジェクト構造→SDKを確認してください。)

AutoCloseableに加えて、(のみ)次のJava 7library機能も公開されています。

  • ConcurrentModificationException、LinkageError、およびAssertionErrorの例外チェーンコンストラクター
  • プリミティブの静的な.compare()メソッド:Boolean.compare()、Byte.compare()、Short.compare()、Character.compare()、Integer.compare()、Long.compare()。
  • 通貨 :.getAvailableCurrencies()、.getDisplayName()(butwithout.getNumericCode())
  • BitSet :.previousSetBit()、. previousClearBit()、. valueOf()、. toLongArray()、. toByteArray()
  • コレクション :.emptyEnumeration()、.emptyIterator()、.emptyListIterator()
  • AutoCloseable
  • Throwable :.addSuppressed()、. getSuppressed()、および4引数コンストラクター
  • 文字 :.compare()、. isSurrogate()、. getName()、. highSurrogate()、. lowSurrogate()、. isBmpCodePoint()(しかしwithout.isAlphabetic()および.isIdeographic())
  • システム:.lineSeparator()(文書化されていない?)
  • Java.lang.reflect.Modifier :.classModifiers()、.constructorModifiers()、.fieldModifiers()、.interfaceModifiers()、.methodModifiers()
  • NetworkInterface :.getIndex()、.getByIndex()
  • InetSocketAddress :.getHostString()
  • InetAddress :.getLoopbackAddress()
  • ロガー :.getGlobal()
  • ConcurrentLinkedDeque
  • AbstractQueuedSynchronizer :.hasQueuedPredecessors()
  • DeflaterOutputStream :「syncFlush」を持つ3つのコンストラクター。
  • デフレーター :4つの引数を持つ.NO_FLUSH、.SYNC_FLUSH、.FULL_FLUSH、.deflate()

それが基本的にすべてです。特に、NIO 2.0は存在せず、Arrays.asListはまだ@SafeVarargsではありません。

164
kennytm

編集:これが書かれた時点で、最新リリースはAndroid 9およびEclipse Indigoでした。それ以来、物事は変わりました。

  • 実用的な答え

はい、試しました。しかし、これは優れたテストではありません。実際にJava 7を使用する方法がないため(少なくとも単純な方法ではない)互換性がレベル6に制限されていたためです。

  • 最初に、他のJDKがインストールされていないマシンにJDK7をインストールしました-EclipseとAndroidもインストールされていません:

The 7 is the only installed on this machine

  • 次に、新しいEclipse Indigoをインストールし、実際にJDK 7を使用していることを確認しました(これが唯一のものであり、これが私が選択したものなので驚いたでしょう)

The 7 is the only used by this Eclipse

  • 次に、Android SDKの最新バージョンをインストールしました(編集:この投稿の執筆時点で、Honeycomb、API13)。私のJDK 7が見つかり、正しくインストールされました。 ADTでも同じです。

  • しかし、Hello Word Androidアプリをコンパイルして実行しようとすると、驚きました。互換性はJava 6に設定され、強制的にJava 7にする方法はありませんでした。

Compatibility is limited to Java 6

  • Android以外のプロジェクト、つまり通常のJavaプロジェクトで試しましたが、説明がありました。互換性レベルはEclipseによって制限されているようです(次の画像の下部にあるメッセージを参照)。

Eclipse limits itself to level 6 compatibility

だから私はHello Worldが動作し、他のアプリも複雑で、SQLiteListviewSensorCameraを使用していましたが、これはJava 7はよくできており、Androidで動作しているようです。

では、上記のEclipseの制限を回避するために、古き良きAntを試してみましたか?

  • 理論的答え

とにかく、SDKは here で説明されているように、Java 5または6で使用するように設計されています。

Java 7で動作するものがあるかもしれませんが、「偶然」に動作するでしょう。 DEXの構築は適切に機能するかどうか、そしてDEXが構築されると機能するかどうかが決まります。これは、修飾されていないJDKを使用すると、定義上、予測できない結果が生じるためです。

誰かが正常なAndroid 7の下でJavaアプリを正常に構築したとしても、これはJDKを修飾しません。別のアプリケーションに適用された同じプロセスが失敗するか、結果のアプリケーションにそのJDKの使用に関連するバグがある可能性があります。推奨されません。

Webアプリケーションの開発に携わる人にとって、これはJava 5または6の下に構築されたWebアプリケーションをJava 4のみに対応するアプリケーションサーバーの下にデプロイするのとまったく同じです(Weblogic 8例えば)。これはうまくいくかもしれませんが、これは試してみる以外の目的に推奨できるものではありません。

70
Shlublu

Dalvikvm.comからの引用:

Android SDKに含まれるdxは、通常のJavaコンパイラーによってコンパイルされたJavaクラスのJavaクラスファイルを別のクラスファイルに変換します。形式(.dex形式)

つまり、.Javaソースファイルは問題ではなく、.classバイトコードだけです。

私の知る限り、 呼び出す Java 7のJVMバイトコードに追加されました。残りはJava 6と互換性があります。Java言語自体は使用しません 呼び出す。その他の新機能、 スイッチ ステートメントを使用して ひもsまたはmulti-キャッチ 単なる合成糖であり、バイトコードの変更を必要としませんでした。たとえば、マルチキャッチ ただコピーする キャッチ-考えられる例外ごとにブロックします。

唯一の問題は、Java 7で導入された新しいクラスがAndroidにないということです。 AutoCloseable、あなたが使用できるかどうかわからない 試してみる-with-resources機能(誰かが試してみた?).

それについて何かコメントはありますか?何か不足していますか?

38
Andi

Android SDK v15の時点で、Eclipse 3.7.1とともに、Java 7はnot Android開発でサポートされています。ソースの互換性を1.7に設定すると、生成される.classファイルの互換性が1.7に設定され、Androidコンパイラーによって次のエラーが発生します。

Androidには、コンパイラー準拠レベル5.0または6.0が必要です。代わりに「1.7」が見つかりました。 Android Tools> Fix Project Propertiesを使用してください。

12
Hosam Aly

@KennyTMによる上記の回答を拡張するために、4.0.3以上(minSdkVersion = 15)をターゲットにしている場合、次の方法で非表示APIを使用できます。ターゲットのSDK Android.jarにいくつかのクラスを追加します。

これを行うと、Closeableでtry-with-resourcesを使用したり、独自のクラスにAutoCloseableを実装したりできます。

これらのAPIを使用可能にするためにAndroid.jarで変更する必要があるすべてのクラスのソースとバイナリを含むZipを作成しました。解凍してバイナリを追加するだけです
Android-sdk/platforms/Android-NN/Android.jar

ここからダウンロードできます: http://db.tt/kLxAYWbr

また、ここ数か月で、エリオットヒューズはAndroidツリーに対していくつかのコミットを行いました。 AutoCloseableを終了しました。 SafeVarargs隠されていないさまざまなAPIThrowableの保護されたコンストラクター を修正、 バージョン51クラスファイルのサポートを追加dx 。だから、最終的にいくつかの進歩が進行中です。

編集(2014年4月):

SDK 19のリリースでは、Android.jarに追加のAPIをパッチする必要がなくなりました。

4.0.3以降をターゲットとするアプリにAndroid St​​udioでtry-with-resourcesを使用する最適な方法(minSdkVersion = 15)以下のcompileOptionsbuild.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は、このAPIレベルではtry-with-resourcesを使用できないと文句を言いますが、私の経験ではそれは可能であるということです。プロジェクトは、4.0.3以降のデバイスで問題なくビルドおよび実行されます。 500k +のデバイスにインストールされたアプリで、これに関する問題は発生していません。

Android Studio error

この警告を無視するには、lint.xmlに次を追加します。

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

これを純粋なアリで動作させるのは少し面倒だと思われます。

しかし、それは私のために働いた: http://www.informit.com/articles/article.aspx?p=1966024

1
mako

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>
1
Flow

私が見つけたこのgitプロジェクトに興味がある人もいるかもしれません。AndroidでJava 7を実行できるようです。 https://github.com/yareally/Java7-on-Android

ただし、現在作業中のプロジェクトにこれを追加すると、リスクが大きすぎます。 GoogleがJava 7を正式にサポートするまで待ちます。

0
Daniel Ryan