20210410のJavaに関する記事は10件です。

[問題]スマホアプリにお試し期間の概念は必要か?

はじめに 本題に入る前に、マネタイズについてお話します。 スマホアプリでマネタイズするには、大きく2つパターンがあります。 1. 利用料無料で、広告代で得る 2. 有料(買い切り、サブスクリプション、追加課金制) (自分が知らないだけで、他にもあるかも知れませんが、ここでは触れません) 1. の利用料無料の場合は特に問題ありません。ずっと無料ですから、飽きたり気に入らなかったら、アプリを削除すれば問題無いと思います。 問題は、2.です。 2. の有料の場合、買わないとそのアプリが遊べない・利用できないわけですから、自ずと買わざるを得ません。ですが、買ってつまらなかった・想像していたものと違うなど理由によってはお金を出し惜しみして買ってくれない人も少なくありません。そこで登場するのが、お試し期間です。 お試し期間とは? 有料アプリを使わせるために、無料のお試し期間を設け、その間のみ有料時のサービスが利用できる仕組みのこと。 ※ただし、ここで無料期間としていましたが、無料ポイント、初回のみチケット無料のようなものも含まれます。 何が問題か ここまでの話だけでは、特に問題ないのではないか? と思う人も居るでしょう。 アプリ運用する側(メーカー)が困ること・・・ それは何か・・・ 無料期間(無料ポイント、初回のみ無料、1週間無料)が何度も利用できてしまう ってことです。 ????? 何を言っているのか、分からない人もいると思います。 ゲームアプリでよくあるのですが、いわゆるリセマラ(リセットマラソン)を指します。 リセマラとは リセットマラソン(Reset Marathon)とは、主にソーシャルゲームにおいて、ソフトのインストールとアンインストールを何度も繰り返すこと、及びそれにより自分が目的とするアイテムを入手する方法のこと (Wikipediaより) ゲームアプリだとなじみのある行為だと思いますが、一般的なツールアプリ・ライフスタイルアプリなどにおいては、ガチャではなく、無料期間(無料ポイント、初回のみ無料、1週間無料)を言います。そして、企業側からすると無料期間(無料ポイント、初回のみ無料、1週間無料)が何度も利用できてしまうと、損失につながります。 そして、この「無料期間(無料ポイント、初回のみ無料、1週間無料)が何度も利用できてしまう」問題をエンジニアは解決しなくてはいけません。 どうやって? 実際にアプリを制作してみるとぶち当たる壁が存在します。 このアプリをアンインストールしたとしても、過去にインストールされた経歴があることを判断しなくてはいけません。 ですが、端末内データに何かしらのフラグをキャッシュとして保存したとしてもアプリ削除したら消えてしまいます。また、メールアドレスで判断しようとしても複製できてしまうため、意味がありません。 そこで登場するのが、端末固有IDです! 端末固有IDとは? 端末それぞれに不変のIDとして存在する識別子のことを指します。そして、その識別子を元にインストール経歴があるのか判断します。 一般的に多くのAndroid/iOSアプリにおいては以下の識別子を利用します。 Android ANDROID_ID iOS AdvertisingIdentifier ただし、これらのIDは端末を継続して利用している間のみ値が変更されないです。 各詳細について見てみましょう。 ANDROID_ID The value may change if a factory reset is performed on the device or if an APK signing key changes. デバイスで出荷時設定へのリセットが実行された場合、またはAPK署名鍵が変更された場合、値は変更される可能性があります。 AdvertisingIdentifier Unlike the identifierForVendor property of the UIDevice, the same value is returned to all vendors. This identifier may change. For example, if the user erases the device. For this reason you should not cache it. UIDeviceのidentifierForVendorプロパティとは異なり、すべてのベンダーに同じ値が返されます。 この識別子は変更される可能性があります。 たとえば、ユーザーがデバイスを消去した場合などです。 このため、キャッシュしないでください。 と記載されています。 つまり、端末を工場出荷状態(端末リセット)に戻すことで、これらのIDが初期化されてしまいます。 では、工場出荷状態に戻しても変わらないIDを利用すればよいのではないか・・・? と思う方が居ると思います。 残念ながら、それはできません。 Androidに関しては、永続的なデバイス ID(IMEI / MEID、IMSI、SIM、ビルドシリアル)はJava/Kotlinから取得できない制限がかかっています。そのため利用できないのです。 また、iOSも同様でMACアドレスは取得できません。 こんなものも・・・ 工場出荷状態に戻して、端末固有IDをリセットするのがめんどうである時にこんなアプリもあります。 同じ端末で2つのLINEアカウントが使い分けられるようにできる禁断のアプリ「並行世界」の使い方 このアプリを利用するとこのアプリ自体が仮想OSの役割を果たし、同じアプリを2つ起動することができます。 つまり、並行世界を起動した上でLINEを起動すると、1端末で2つのアカウントを利用することができます。 これは実質、端末固有IDを複製しています。 このアプリを利用すると簡単に端末固有IDを複製できてしまうので、何かしら対策しないといけません。 では、どうするか? 対策として考えられることが、Android/iOSアプリで決済する時のカード情報をサーバー側で管理しておき、同じカード情報であった場合、無料期間(無料ポイント、初回のみ無料、1週間無料)を利用できなくすれば問題ないと思います。 ですが、無料期間(無料ポイント、初回のみ無料、1週間無料)リセマラのために、カード情報を入力するアプリは多くありません。 そもそもの問題として、お試し期間という概念は必要でしょうか。という問題定義に戻ります。 無料期間(無料ポイント、初回のみ無料、1週間無料)の機能を追加したが故に、無限に悪用できてしまい、本来有料ユーザーを増やしたいがためにやった行為なのに、逆に減らしてしまうのではないか。と懸念されます。 そこまでのリスクを追うくらいであれば、無料期間(無料ポイント、初回のみ無料、1週間無料)は要らないのではないか。と私は思います。 以上です。 参考 iOS/Androidで端末を識別するIDまとめ https://iridge.jp/blog/201404/4836/ デバイス ID https://source.android.google.cn/devices/tech/config/device-identifiers?hl=ja 一意の識別子に関するベスト プラクティス https://developer.android.com/training/articles/user-data-ids?hl=ja ANDROID IDがどのように生成されているかざっくり調べた https://qiita.com/operandoOS/items/b41fa4a1c6c009c64a10 SSAID取得 https://gist.github.com/Koronaa/d204bc29a122f9adef857d8935fd7cbc
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java11の開発環境構築 まとめ

背景 Javaの開発環境を整えようとして少し苦戦したので、その手順を自己理解のためにまとめてみました。 必要のなさそうな箇所や間違いがあればご教授頂けると幸いです。 手順 ① homebrewのインストール /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" ② homebrew-caskのインストール brew install alfred 参考資料: https://github.com/Homebrew/homebrew-cask ③ homebrew-cask-versionsのインストール brew tap homebrew/cask-versions 参考資料: https://qiita.com/morioheisei/items/ef8eb5d75c07b4d280f4#homebrew-cask-versions%E3%81%AE%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB ④ Javaのインストール https://www.java.com/ja/ ⑤ OpenJDKのインストール brew install java11 echo 'export PATH="/usr/local/opt/openjdk@11/bin:$PATH"' >> ~/.zshrc export CPPFLAGS="-I/usr/local/opt/openjdk@11/include" source ~/.zshrc 参考資料: https://qiita.com/ponsuke0531/items/9be8dee67a91c6c78d4f 補足 brew install alfredが上手く行かない場合は、homebrewをアンインストールしてインストールし直す。 おまけ OpenJDKを手動でダウンロードする方法 [Mac]Big Surでhomebrew-caskを使うときの注意 いつの間にかbrew caskが使用できなくなっていた話 謝辞 ここで参考にさせて頂いた記事を作成した皆様に深く感謝致します。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

GitHub Actionsについて何もわからないやつがなんちゃってCIを設定するまで(Spring Boot)

はじめに 久しぶりに書くので短めに。 GitHub Actionsが出て1年以上になるが、周りがすごいすごいという割に自分で使ったことがなかったので触ってみた。 環境 Java 11 IntelliJ IDEA 2020.3.2 (Community Edition) Build #IC-203.7148.57, built on January 26, 2021 設定 以降の内容は下記リポジトリに置いた。 https://github.com/Ikeponias/SpringBootCI 以下の実装とテストコードを書いて、これをCIで実行するようにしてみた。実装とテストは適当なのでご容赦ください。 TestController.java @RestController @RequestMapping("/test") public class TestController { @RequestMapping(method = RequestMethod.GET) public String getMessage() { return "Hello World!"; } } TestControllerTest.java @Test public void successTest() throws Exception { MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/test")) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn(); Assertions.assertEquals(mvcResult.getResponse().getContentAsString(), "Hello World!"); } @Test public void failedTest() throws Exception { MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get("/test")) .andExpect(MockMvcResultMatchers.status().isOk()) .andReturn(); Assertions.assertEquals(mvcResult.getResponse().getContentAsString(), "Hello World"); } GitHubリポジトリのタブ中にActionsという欄がいつの間にやらできている。 これを押してみるとGitHub Actionsの初期設定画面が出てくる。 ふむふむ、デプロイするためのワークフローサンプルもあるのは良い。 今回は本当に簡単にテストしたいだけなので、Suggestされている Simple workflow を選択。 すると以下のような画面が表示された。 なるほど、このymlを編集することでCIの設定ができるわけか。 JenkinsにおけるJenkinsfileと思っておけば良いだろうか。 今回はpush時にテストを実行してほしかったので、プルリクエスト時の設定を削除し、Run tests として mvn test を追加してみた # This is a basic workflow to help you get started with Actions name: CI # Controls when the action will run. on: [push] # A workflow run is made up of one or more jobs that can run sequentially or in parallel jobs: # This workflow contains a single job called "build" build: # The type of runner that the job will run on runs-on: ubuntu-latest # Steps represent a sequence of tasks that will be executed as part of the job steps: # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - uses: actions/checkout@v2 # Runs a single command using the runners shell - name: Run a one-line script run: echo Hello, world! # Runs a set of commands using the runners shell - name: Run a multi-line script run: | echo Add other actions to build, echo test, and deploy your project. - name: Run tests run: mvn test いきなり出てきた actions/checkout@v2 ってナンダコレと思ったが https://github.com/actions/checkout のことのようだ。 具体的な構文や設定方法は公式のドキュメントを参照するのが良い。 特に今回はJavaのバージョンなど設定していないが、その場合pomの値が使われるのだろうか(わからん)。 https://docs.github.com/ja/actions 実行結果 テストがすべて実行成功すると下記のようになることが確認できた。 テストが失敗すると下記のようになることが確認できた。 ついでにGitHubに登録してあるメールアドレスにジョブ結果が届いていることも確認できた。 感想 初めてでも20分くらいで設定できたので、Jenkinsなどと比べると導入コストが非常に低い。 簡単にCIを回したいとかであればこれは非常に楽でありがたいと思う。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

再帰呼び出し Method Class

あるメソッド内で、再度同じメソッドを呼び出す事を再帰呼び出しを呼ぶ。 for&while文を使わずに繰り返し処理を行える if内でtestメソッドコピーをとって、num<10がfalseになるまで処理を繰り返し行える コピーをとって動かしている Method_Class_4_10.java public class Method_Class_4_10 { public static void main(String[] args) { var sample = new Method_Class_4_10(); sample.test(1); } public void test(int num){ System.out.println("test"); if(num < 10){ test(num +1); } } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

インクリメントとデクリメントについて

インクリメントデクリメントとは? 文字列"a"に対して 「a=a+1」 文字列"b"に対して 「b=b+1」 という記述を++aとかb++という風に短縮できる書き方と覚えましょう。 ++aのように先に記号を記述するやり方を前置インクリメントといい 以下のような計算をします。 ① b=++a この場合だと先にaに1を加えてbに代入します。 ②b=a++ この場合だとbにaを代入した後にaに1を加えます なので、先に置くか後に置くかでそのあとのa,bの値が変動してしまうのです。 文字列の連結 文字列の連結をする際、型に注意して連結していかなければなりません、 例① String,int型の連結 "FFA+J"+1+12 の場合""で囲まれている部分はString型、1,12がint型の確認 計算は左から行われていくためまず"FFA+J+1"+12 最後に"FFA+J+112"となります。 ご参考までに。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Eclipseでパッケージ構成を変更する

Eclipseでパッケージ構成を変更する方法について紹介していきます。 「名前変更」を選択 変更したいパッケージ構成が「com.example.demo」だとしたら、「demo」を選択し、 「リファクタリング」>「名前変更」をクリックします。 パッケージ名の変更 下記の3点にチェックを入れ、「プレビュー」をクリックします。 「参照の更新」:変更対象のパッケージ構成を使った参照を新しいパッケージ構成に変更します。 「サブパッケージの名前変更」:該当のパッケージ以下のサブパッケージを変更します。 「コメント及びストリング内のテキスト出現箇所の更新」:Javadocのタグ、コメント内に登場する変更対象のパッケージ構成を変更します。 今回変更するパッケージ配下には「非Javaテキスト」は無いため、 「非Javaテキスト・ファイル内の完全修飾名の更新」のチェックは外しています。 変更の継続 「継続」をクリック。 変更対処のパッケージの配下にmainクラスが含まれているとこの注意文がでてきます。 変更の実行 「OK」をクリック。 変更が実行されます。 これでパッケージ構成が変更されました。 アプリケーションを実行し動作確認を行うといいでしょう。 追記 テストケースの「パッケージ構成」の変更 実行クラスのパッケージ構成の変更後、テストケースが実行できない場合があります。 その時は、同様の手順で、テストケースが格納されているパッケージも実行クラスと同じパッケージ構成に変更しましょう。 「名前変更」を選択 変更したいパッケージ構成が「com.example.demo」だとしたら、「demo」を選択し、 「リファクタリング」>「名前変更」をクリックします。 パッケージ名の変更 下記の3点にチェックを入れ、「プレビュー」をクリックします。 「参照の更新」 「サブパッケージの名前変更」 「コメント及びストリング内のテキスト出現箇所の更新」 変更の継続 「継続」をクリック 変更した実行クラスのパッケージ構成と同名に変更しようとしているので、このような注意文が表示されます。 変更の実行 「OK」をクリック。 変更が実行されます。 この段階で、エラーが発生する場合があります。 今回変更する「com.example.demo」の1階層上のフォルダを右クリック。 「実行」>「実行の構成」でテストケースのパッケージ構成などが現在使用しているものと一致するか、 一致していない場合は、「テスト・ケース:」などを修正し、適用すると無事パッケージ構成の変更が実行できました。 *筆者の環境では、パッケージ構成の変更をする前に、テストケース名、テストメソッド名を変更し、実行の構成まで変更していなかったのが原因でエラーが発生しました。 テストケースを実行して、正常に実行されたら完了です。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Spring Framework】@Transactional のメソッドはクラス内から呼ぶとトランザクションが実行されない

やりたかったこと 下記のような感じで、1 メソッドでトランザクションを 2 回かけたかったです。 公式ドキュメントを読むと、public method に @Transactional が使えると書いてあるので、1 メソッドからトランザクションをかけるメソッドをそれぞれ呼び出しても大丈夫かと思い試してみたところ、どうやらこのサービスクラスをプロパティに持つクラスから registerA registerB をそれぞれ呼び出さないとトランザクションは効きませんでした。 @Service @RequiredArgsConstructor public class HogeHogeServiceImpl implements HogeHogeService { private final HogeHogeRepository hogehogeRepository; private final FugaFugaRepository fugafugaRepository; @Override public void registerAB(List<HogeHoge> hogehogeList) { List<FuaFuga> fugafugaList = registerA(hogehogeList); registerB(fugafugaList); } @Override @Transactional public List<FugaFuga> registerA(List<HogeHoge> hogehoegList) { try { ...いろいろな処理 hogehogeRepository.register(hogehogeList); ...いろいろな処理 return createSuccessFugaFugaList(); } catch (Exception e) { return createFailedFugaFugaList(); } } @Override @Transactional public void registerB(List<FugaFuga> hogehoegList) { ...いろいろな処理 fugafugaRepository.register(fugafugaList); } ... } @Transactional は Spring AOP を使ってる なぜ @Transactional をメソッドにつけると、トランザクションが実行されるのでしょうか。 おそらく TransactionManager をどこかのタイミングで実行しているのだと思います。 registerA の処理の始めにコールスタックを吐き出すようにして、 registerA をサービスクラス外から呼び出して調べてみました。 @Override @Transactional public List<FugaFuga> registerA(List<HogeHoge> hogehoegList) { Arrays.stream(Thread.currentThread().getStackTrace()).forEach(stackTraceElement -> { System.out.println("class name = " + stackTraceElement.getClassName()); System.out.println("method name = " + stackTraceElement.getMethodName()); System.out.println("-------------------------"); }); ... } 出力 class name = java.lang.Thread method name = getStackTrace ------------------------- class name = xxxx.xxxx.HogeHogeServiceImpl method name = registerA ------------------------- class name = xxxx.xxxx.HogeHogeServiceImpl$$FastClassBySpringCGLIB$$40a6490f method name = invoke ------------------------- class name = org.springframework.cglib.proxy.MethodProxy method name = invoke ------------------------- class name = org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation method name = invokeJoinpoint ------------------------- class name = org.springframework.aop.framework.ReflectiveMethodInvocation method name = proceed ------------------------- class name = org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation method name = proceed ------------------------- class name = org.springframework.transaction.interceptor.TransactionAspectSupport method name = invokeWithinTransaction ------------------------- class name = org.springframework.transaction.interceptor.TransactionInterceptor method name = invoke ------------------------- class name = org.springframework.aop.framework.ReflectiveMethodInvocation method name = proceed ------------------------- class name = org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation method name = proceed ------------------------- class name = org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor method name = intercept ------------------------- class name = xxxx.xxxx.HogeHogeServiceImpl$$EnhancerBySpringCGLIB$$8837d8e0 method name = registerA ------------------------- class name = yyyy.yyyy.HogeHogeController method name = run ------------------------- これだけだとTransactionManager をどのタイミングで使っているか分かりません。 出力されるまでに、 org.springframework.aop.framework.CglibAopProxy が使われているのが分かりました。パッケージパスを見た限り Spring AOP を使ってそうです。 Spring AOP Spring AOP は、アスペクト指向プログラミングを実現するフレームワークで、これにより Spring Bean でのクラス・メソッドの前後に処理を追加することができます。 例えば、すべてのコントローラのメソッドでリクエストを受け取るたびにリクエストの中身をログ出力する、といったことが簡単に実現できます。 Aspect Oriented Programming with Spring @Transactional は Spring AOP を使っています。というのも、コールスタックを確認して呼び出されているクラス・メソッドを追わなくても、公式ドキュメントに説明が書いてありました。 Understanding the Spring Framework’s Declarative Transaction Implementation @Transactionalを使うと、 AOP Proxy を介してトランザクションが有効になり TransactionInterceptor クラスによってトランザクション実行・コミット・ロールバックが制御されるようです。 トランザクションが有効にならないのは、AOP Proxy の制御が関係ありそうなので、AOP プロキシについて調べてみます。 AOP Proxy Spring AOP は Dynamic Proxy または CGLIB を使って Proxy をベースに作られています。 インターフェースを実装したクラスでは Dynamic Proxy が使われるようです。 Proxy とは何なのか調べてみます。 Proxying Mechanisms Proxy Proxy とは Java標準クラスの java.lang.reflect.Proxy のことです。 Proxy を使うことで、特定のクラス・メソッドの前後に処理を追加することが可能です。 InvocationHandler の実装クラスを用意して、対象のクラス・メソッドの前後での処理をメソッドで書きます。 handler を引数で渡して、Proxy を使って対象のクラスをインスタンス生成してメソッド呼び出すと、対象のメソッドに加えて前後の処理が実行されます。 public class ProxySample { public static void main(String[] args) { HogeHogeInvocationHandler handler = new HogeHogeInvocationHandler(new HogeHogeImpl()); HogeHoge hogeHoge = (HogeHoge) Proxy .newProxyInstance(HogeHoge.class.getClassLoader(), new Class<?>[]{HogeHoge.class}, handler); hogeHoge.run(); } } interface HogeHoge { void run(); } class HogeHogeImpl implements HogeHoge { @Override public void run() { System.out.println("hoge hoge"); } } class HogeHogeInvocationHandler implements InvocationHandler { private HogeHoge hogeHoge; HogeHogeInvocationHandler(HogeHoge hogeHoge) { this.hogeHoge = hogeHoge; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("before"); Object o = method.invoke(this.hogeHoge, args); System.out.println("after"); return o; } } 出力 before hoge hoge after 以下のように、public method から別の public method を呼び出すようにしても、クラス内から呼び出した場合は proxy を介さないので、前後の処理は run2 では実行されません。 class HogeHogeImpl implements HogeHoge { @Override public void run() { System.out.println("hoge hoge"); run2(); } @Override public void run2() { System.out.println("hoge hoge 2"); } } 出力 before hoge hoge hoge hoge 2 after Spring AOP もこの Proxy 同様に、前後の処理を呼び出すのに AOP Proxy を介さないといけないので、クラス内で @Transactional がついたメソッドを呼び出してもトランザクションは有効になりません。 Understanding AOP Proxies まとめ @Transactional は Spring AOP を、つまり Dynamic Proxy (または CGLIB) を使ってる Proxy によるメソッドの前後での処理を実行したいなら、クラス内から対象のメソッドを呼び出すのではなく、DIした他クラスから呼び出さないといけない なので、それぞれのメソッドでトランザクションを実行したいなら、DIされた他クラスからそれぞれ呼び出すか、別クラスに移してそれぞれ呼び出すと良い
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java初心者におすすめの本を一つ

はじめに 今年度からJava関係の仕事をする予定であることから、ずっとしていなかったJavaの勉強を本格的に始めました。これまでPython、JavaScript、phpのような比較的取り組みやすいと言われる言語は学んでいたのですが、いよいよJavaを学習する時がきました。Javaといえば、大学1年生の頃(もう8年前か...)に実は少しかじったのですが、とっかかりのpublic static void main(String[] args)のところでウワーってなって勉強をやめた記憶があります。(あと当時の私のノートパソコンでは統合開発環境の動作が重すぎていやになった記憶もある...) で、おすすめのJavaの本て結局何なの? そんなこんなで、どう勉強しようかと悩んでいたのですが、本屋さんにいったらなんと以前にはなかったなんか分かりやすそうな本があるじゃないですか?! そう...それは「スッキリわかるJava入門」です。いかにも分かりやすそうな表紙をしていますね。 www.amazon.co.jp/dp/4295007803 まあ、ここに来て私が言わなくても、どこで調べても一番に上がってくるので知ってますよね... 入門編と実践編、サーブレット・JSP編の3冊に分かれています。まあ、Java言語自体を学ぶのであればサーブレット・JSP編はいらないと思います。 で、なんでおすすめなの?根拠を言ってください まあ、私が勉強していて分かりやすかったから...なんですが、お勧めできる点を紹介しておきます。 図やイラストが多く視覚的に非常に分かりやすい 機能の概念の説明にとどまらず、なぜその機能があるのかや開発を意識した説明が随所にちりばめられている オブジェクト指向の説明が初学者向けに非常に工夫されている オブジェクト指向初学者にも学習のフローチャートが提示されており、ドツボにはまらないような工夫がある オブジェクト指向の概念が分かりやすい例に落とし込まれ説明されている なぜ、オブジェクト指向を使うのか、なぜ抽象クラスやインターフェースの概念が用意されているのかが説明されている 実践編では言語仕様の説明のみにとどまらず、実際の開発現場で必要となる周辺知識まで解説されている まとめ 以上、「スッキリわかるJava入門」のお勧めできる点をいくつか書きましたが、やっぱり一番ためになったなと思うのが、なぜその機能があるのかにしっかりと触れている点です。実際に開発者目線から解説してくれているので、分かりやすい上に非常にためになる書き方がされているなと感じます。今後、Javaを勉強しようというかたに胸を張っておすすめします!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java Silverの勉強で難しかった点まとめ

今日Java Silverの試験日なのでまとめてみた。 equalsメソッド equalsメソッドはObjectクラスに定義されている同値性を確かめるためのメソッド ただ、OBjectクラスに定義されているequalsメソッドは下記の通りthisを使用し同値性を確認している public boolean equals(Object obj) { return (this==obj); } そのため、Mainクラスなどでequalsメソッドをオーバーロードする場合には注意が必要です。 public class Main { private int sum; public static void main(String[] args) { Object a = new Main(10); Object b = new Main(10); System.out.println(a.equals(b)); → falseになる } public boolean equals(Main obj) { return this.sum == obj.sum; } public Main(int num){ this.sum = num; } } 6行目のequalsメソッドではobject型で呼んでいるため、9行目からのequalsメソッドではなく、 Objectクラスにもともと用意されているequalsメソッドを呼び出す。 Objectクラスにあるequalsメソッドは同一性を返すので、falseになる。 例外処理 try-catchの下にあるブロックはcatchされた場合呼び出されない public class Main { public static void main(String[] args) { System.out.println(test(null)); } public static String test(Object obj) { try { System.out.println(obj.toString()); }catch (NullPointerException e) { return "A"; }finally { System.out.println("B"); } return "C"; → もしぬるぽになったらこの行は呼び出されない } } catchとfinallyでreturnの記述があれば、finallyが優先される public class Main { public static void main(String[] args) { System.out.println(test(null)); } public static String test(Object obj) { try { System.out.println(obj.toString()); }catch (NullPointerException e) { return "A"; }finally { return "C"; → もしぬるぽになったら最終的にfinallyのCがreturnされる } } } tryとfinallyは一つずつしか書けない public class Main { public static void main(String[] args) { test(null); } public static void test(Object obj) { try { System.out.println(obj.toString()); }finally { System.out.println("A"); }finally { System.out.println("B"); → コンパイルエラーになる } } } 継承関係にないクラスにキャストしたらClassCastExcptionが発生する キャストの記述(クラス名)を書いていればコンパイル時に検出はされないので例外が発生する public class Sample { private int sum; public Sample(int num) { this.sum = num; } public boolean equals(Object obj) { Sample a = (Sample) obj; → キャストしていると例外が発生する return a.sum == this.sum; } } キャストしていないとコンパイルエラーになる public class Sample { private int sum; public Sample(int num) { this.sum = num; } public boolean equals(Object obj) { Sample a = obj; → コンパイルエラー return a.sum == this.sum; } } デフォルトパッケージ(無名パッケージ) デフォルトパッケージから他のパッケージに属するクラスにはアクセスできない デフォルトパッケージ内のクラスは同じデフォルトパッケージに属するクラスのみアクセス可能 // デフォルトパッケージに属するクラス public class Sample { public static final int sum = 30; } package ex6; public class Sample2 { public static final int sum = 30; } package ex6; public class Main { public static void main(String[] args) { System.out.println(Sample2.sum); → 同じパッケージなのでアクセス可能 System.out.println(Sample.sum); → 無名パッケージに属するクラスなのでアクセス不可 } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Java Silverの勉強のなかで難しかった点まとめ

今日Java Silverの試験日なのでまとめてみた。 equalsメソッド equalsメソッドはObjectクラスに定義されている同値性を確かめるためのメソッド ただ、OBjectクラスに定義されているequalsメソッドは下記の通りthisを使用し同値性を確認している public boolean equals(Object obj) { return (this==obj); } そのため、Mainクラスなどでequalsメソッドをオーバーロードする場合には注意が必要です。 public class Main { private int sum; public static void main(String[] args) { Object a = new Main(10); Object b = new Main(10); System.out.println(a.equals(b)); → falseになる } public boolean equals(Main obj) { return this.sum == obj.sum; } public Main(int num){ this.sum = num; } } 6行目のequalsメソッドではobject型で呼んでいるため、9行目からのequalsメソッドではなく、 Objectクラスにもともと用意されているequalsメソッドを呼び出す。 Objectクラスにあるequalsメソッドは同一性を返すので、falseになる。 例外処理 try-catchの下にあるブロックはcatchされた場合呼び出されない public class Main { public static void main(String[] args) { System.out.println(test(null)); } public static String test(Object obj) { try { System.out.println(obj.toString()); }catch (NullPointerException e) { return "A"; }finally { System.out.println("B"); } return "C"; → もしぬるぽになったらこの行は呼び出されない } } catchとfinallyでreturnの記述があれば、finallyが優先される public class Main { public static void main(String[] args) { System.out.println(test(null)); } public static String test(Object obj) { try { System.out.println(obj.toString()); }catch (NullPointerException e) { return "A"; }finally { return "C"; → もしぬるぽになったら最終的にfinallyのCがreturnされる } } } tryとfinallyは一つずつしか書けない public class Main { public static void main(String[] args) { test(null); } public static void test(Object obj) { try { System.out.println(obj.toString()); }finally { System.out.println("A"); }finally { System.out.println("B"); → コンパイルエラーになる } } } 継承関係にないクラスにキャストしたらClassCastExcptionが発生する キャストの記述(クラス名)を書いていればコンパイル時に検出はされないので例外が発生する public class Sample { private int sum; public Sample(int num) { this.sum = num; } public boolean equals(Object obj) { Sample a = (Sample) obj; → キャストしていると例外が発生する return a.sum == this.sum; } } キャストしていないとコンパイルエラーになる public class Sample { private int sum; public Sample(int num) { this.sum = num; } public boolean equals(Object obj) { Sample a = obj; → コンパイルエラー return a.sum == this.sum; } } デフォルトパッケージ(無名パッケージ) デフォルトパッケージから他のパッケージに属するクラスにはアクセスできない デフォルトパッケージ内のクラスは同じデフォルトパッケージに属するクラスのみアクセス可能 // デフォルトパッケージに属するクラス public class Sample { public static final int sum = 30; } package ex6; public class Sample2 { public static final int sum = 30; } package ex6; public class Main { public static void main(String[] args) { System.out.println(Sample2.sum); → 同じパッケージなのでアクセス可能 System.out.println(Sample.sum); → 無名パッケージに属するクラスなのでアクセス不可 } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む