20210508のJavaに関する記事は7件です。

【Java】AtCoderのABC-200に参加しました(レート:278→264)。

こんばんは。 2021/5/8に、AtCoderのABC-200に参加しました。 レートは以下の通りとなっています。 C問題でつまづきました。 レートは278→264にダウン!順位は6646/8577でした。 おーっ、あーっ、ぐぅーっ、という感じですね。 A問題 世紀を求めるプログラム。念入りにテストしてしまいましたが、まあ何とか。 Main.java import java.util.Scanner; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); int n = sc.nextInt(); System.out.println((n-1)/100+1); } } B問題 ある数字、Nについて、K回以下の処理を繰り返す。 ・Nが200の倍数だったら、200で割る。 ・200の倍数でなかったら、末尾に200を付与する(123だったら、123200にする) ここは言われたとおりに、まあなんとか。 でも、200を付与するのに、文字列型に変換して付与するのはださいですね。 1000倍して、200を足す方がスマートですね。 後で振り返るのも大事です。 Main.java import java.util.Scanner; public class Main{ public static void main(String args[]){ Scanner sc = new Scanner(System.in); long n = sc.nextLong(); long k = sc.nextLong(); long nwk = n; String nwks = String.valueOf(n); for(int i=0;i<k;i++){ if(nwk%200==0){ nwk = nwk/200; }else{ nwks = nwks + "200"; nwk = Long.parseLong(nwks); } nwks = String.valueOf(nwk); } System.out.println(nwk); } } C問題 Nこの文字列Ai~Anを入力。 Ai-Ajが200の倍数、が成り立つ組み合わせはいくつあるか。 タイムアウトだってわかってはいたけれど、いいロジックが思いつかず・・入力時に、入力済みの全文字列を比較する処理をまずは組んでみました。 当然TLE。 次に、下2桁が同じものは、「条件が成立する可能性がある組み合わせ」と考え100個の配列に、下2桁が同じものを分類し、最期にまとめて計算する方法を取ってみましたが、タイムアウトに加え実行時エラーで発生し終了3分前に敗北。 でした。 感想 解けなかったC問題を、例えば明日解説を参考に解いてみるとか、もっとした方が良いんだろうなと思うのですが、時間も限られているので気の向くまま学習を進めます。 会社でも、競技プログラミングの本をおすすめされていたので、やっぱり読んでみようかな。 ではまた。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Ruby と Java と Crystal と C++ で解く プログラマーにしか解けない! #実行時間クイズ の1問目

はじめに プログラマーにしか解けない! #実行時間クイズ をやってみました。 FoH6ESorz79IWhk さん、kuizy さん、ありがとうございます。 また、実行環境としてAtCoder のコードテストをお借りしました。 AtCoder さん、ありがとうございます。 C++ c.c #include <iostream> using namespace std; int ret[10009]; int main() { int N = 10000, sum = 0; for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { ret[i] += i * j; ret[i] %= 10007; } } return 0; } 元の問題より、出力部分を省略しています。 316 ms Ruby ruby.rb n = 10000 sum = 0 ret = Array.new(10009, 0) n.times do |i| n.times do |j| ret[i] += i * j ret[i] %= 10007 end end 9294 ms Java java.java class Main { public static void main(String[] args) { int ret[] = new int[10009]; int N = 10000, sum = 0; for (int i = 1; i <= N; i++) { for (int j = 1; j <= N; j++) { ret[i] += i * j; ret[i] %= 10007; } } } } 392 ms Crystal Crystal.cr n = 10000 sum = 0 ret = Array.new(10009, 0) n.times do |i| n.times do |j| ret[i] += i * j ret[i] %= 10007 end end 671 ms まとめ 遅い遅いと言われていますが、本当に遅いのを実感しました 競技プログラミングでRubyを使用している方は、何かの修行なのかもしれませんね
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Javaのクラス内で画像を取得する

概要 Javaのクラス内で、HTTP通信を使って外部から画像データなどを取得する方法について、HttpURLConnectionを使ってデータを取得していました。 このHttpURLConnectionについて、今まではただ必要な設定として認識していたものを、それぞれどのような事を設定しているのかを改めて確認をしたいと自分用にまとめようと思いました。 ソースコード 今回は、外部から画像データを取得して、それがPNGの画像データであればそのInputStreamを生成するという部分のみ抜粋しました。 String targetContentType = "image/png"; DataInputStream inputStream = null; try { // フォーマットがPNGの画像を指定 URL url = new URL("https://dummyimage.com/570x150"); HttpURLConnection conn = (HttpURLConnection) url.openConnection(); conn.setAllowUserInteraction(false); conn.setUseCaches(false); conn.setInstanceFollowRedirects(true); conn.setRequestMethod("GET"); conn.connect(); if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { if (conn.getContentType().equals(targetContentType)) { inputStream = new DataInputStream(conn.getInputStream()); } } } catch (MalformedURLException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } if (inputStream != null) { // 画像のInputStreamに対してやりたい事 } HttpURLConnectionに設定したフィールド 上記で設定したフィールドのみ列挙しています。 フィールド 修飾子と型 説明 allowUserInteraction protected boolean 接続時にユーザー名やパスワードの入力を求められたとき、許可をするかどうか url protected URL HTTP通信をしたい対象のURL useCaches protected boolean キャッシュを使用を許可するかどうか method protected String HTTPに使用するメソッド(GETやPOSTなど) instanceFollowRedirects protected boolean プロトコルがリダイレクトに従うかどうか
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

読みやすいコードって?① - if条件を書くとき

プログラミングをする際に良く耳にする「可読性」という言葉があります。 私はプログラミング未経験から縁があってIT企業に入社し今はSEとして働いていますが、 ほぼ独学で身につけたスキルのため、「可読性の高いコード」や「読みやすいコード」と言われても、正直どういうコードが読みやすいの?というのが分かりませんでした。 この記事では、具体的な例を挙げながら、なぜ読みやすいのか?なぜ読みにくいのか?について考えたいと思います。 「可読性ってどうやって考えたらいいの?」と思っている昔の私(今もですが・・)のような方の引き出しの一つに加えてもらえたら嬉しいです。 具体例 例えば、映画のチケット料金を計算するプログラムを書く時、 以下のようなクラスがあったと仮定します。 上映映画クラス(MovieOnPlay)・・・チケットを計算する元になる上映時間等を含んだ映画のクラス。 料金計算クラス(PriceCalculator)・・・上映映画を引数にとって、上映映画クラスの情報を元にチケット料金を計算する。 MovieOnPlay.java /** * 上映映画クラス. */ class MovieOnPlay { /** 映画の名前. */ private String name; /** 上映開始時間. */ private LocalDateTime startTime; /** 上映開始時間getter. */ public LocalDateTime getStartTime() { return thie.startTime; } // この下にgetter、setterが続く想定(今回の記事には関係ないので省略) } priceCalculatro.java /** * チケット料金を計算する. * @param movie 上映映画 * @return チケット料金 */ public Integer calculate(MovieOnPlay movie) { LocalDateTime now = LocalDateTime.now(); // 引数で受け取ったmovieがnullの場合と、 // movieの上映開始時間がシステム日付(now)より後だった場合は // RuntimeExceptionを投げるコードをここに記述する // 料金計算ロジック calculatePrice(movie); } エラーチェックを行うコードを書くことを考えてみる 料金計算クラス(PriceCalculator)で、料金計算を行う前に以下のエラーチェックを行う場合を考えます。 引数に受け取った上映映画クラスがnullだった場合はエラー 料金計算しようとしている映画の上映開始時間が、現在の時間より前だった場合(すでに上映開始時間が過ぎている場合)はエラー 上記のチェックを行うコードを書く場合、以下の2つの書き方は同じ動きをします。 // 書き方の候補① LocalDateTime now = LocalDateTime.now(); if( !(movie != null && movie.getStartTime().isBefore(now)) ) { throw new RuntimeException("正しい上映映画が選択されていません。") } // 料金計算ロジック calculatePrice(movie); // 書き方の候補② LocalDateTime now = LocalDateTime.now(); if(movie == null || movie.getStartTime().isAfter(now)) { throw new RuntimeException("正しい上映映画が選択されていません。") } // 料金計算ロジック calculatePrice(movie); では、どちらが”可読性が高い”と言えるでしょうか? 実は可読性が高いのは①であると考えることができます。 なぜ①の方が可読性が高いと言えるのか? エラーにならない条件から考えてみる 後から別の担当者がこのコードを見た場合、おそらく「どうしたらcalculate(movie)が実行されるのかな?」という観点で見ることが多いと思います。 RuntimeExceptionがスローされる条件より、calculate(movie)が実行される条件の方が、実際の業務においては重要だからです。 movieがnullではない startTimeがnowより前である 上記の2つの条件を満たせば、ifブロックをスルーしてcalculatePrice(movie)を実行することができます。 逆に、”そうでない場合”はRuntimeExceptionをスローします。 それをそのままコードに落とし込んだのが①です。 // movieがnullではない movie != null // startTimeがnowより前である movie.getStartTime().isBefore(now) // ”そうでない場合”はRuntimeExceptionをスロー if( !(movie != null && movie.getStartTime().isBefore(now)) ) { throw new RuntimeException("正しい上映映画が選択されていません。") } 上記の!( ) をはずした「movie != null && movie.getStartTime().isBefore(now)」を満たしたものがcalculate(movie)を実行できます。 ②をもう一度見てみる ②をのコードを「どうしたらcalculate(movie)が実行できるか?」という観点で見てみます。 if分の中のコードに”当てはまらない”条件であれば実行できるのですが、 「movie == null」 の逆はすぐわかるとしても、「movie.getStartTime().isAfter(now)」でない条件とは何か?を考えた時に、少し時間がかかるのではないでしょうか? // 書き方の候補② LocalDateTime now = LocalDateTime.now(); if(movie == null || movie.getStartTime().isAfter(now)) { throw new RuntimeException("正しい上映映画が選択されていません。") } // 料金計算ロジック calculatePrice(movie); そのため、①の方が可読性が高いと考えられます。 まとめ 今回はif文でエラーチェックを行う際の”読みやすさ”について考えてみました。 実際の業務では上記のようなケースはよくありますし、私も仕事をしていく中でif文に”当てはまらない”条件を考えるのに苦労したことは何度もあります。 プログラミングを勉強していく中で、こういった考え方でコードを書けば後々わかりやすいのか!と納得したうちの一つだったので記事にしてみました。 プログラミングは奥が深いので必ずしもこの書き方が100%正しいとは言えないのですが、こういった考え方を知っていくことで少しでも”読みやすい”コードを書けるようになりたいなと思います。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Azure DevOps で Java ライブラリのパイプラインを組んだりホストしたりする

Azure DevOps で Javaライブラリパイプラインを組んだりホストしたりする 以前、Azure DevOps から Maven Central Repository へデプロイするための、パイプラインを組んだことがあるのですが、その頃からはAzure DevOps の機能も変ったりしているので、復習ついでにBLOGを書こうと思います。当時は確か、マルチステージパイプラインがなかったりたきがします。 取りあえずひな形的なものは、試行錯誤して組まざるをえないので、パイプラインを組んでみたいと思います。 今回の想定としては、プロジェクト共通のライブラリを、ローカルのMaven Repository にデプロイするというところを目標にパイプラインを組みます。Azure DevOpは、Artifactの機能をつかって、 Maven やら npm やら nuget に対応してライブラリをホストすることができます。企業内、プロジェクト内でプライベートなリポジトリとして使用できます。 Azure DevOps は無料出始めることが出来ますので、詳細は以下を参照してください。 Azure DevOps Services | Microsoft Azure リポジトリを用意する Azure DevOpsでプロジェクトを作成し、リポジトリを用意します。作り方によって、デフォルトブランチが main になったりすることがありますので、ご注意を。適当なライブラリ的なコード(テスト含む)を書いて、リポジトリにプッシュしておきましょう。 以下は既にパイプラインファイル作ってしまった後ですが、スクリーンショットです。 パイプラインを組む 手順としては簡単で2つです。これを YAMLファイルで記述します。 mvn package する mvn deploy する パイプラインタブの右上で新規作成できます。以下は既に作成済の画面です。 新規作成すると、対象のリポジトリを選択します。Azure DEvOps内のリポジトリ以外にも選ぶことが出来ますがここでは、Azure DevOpsないのリポジトリを使います。 選択していくと、パイプラインの構成画面がでてきます。Maven を選ぶと簡単なひな形が展開されます。 最初のひな形はこんな感じですが、マルチステージになっていないので、steps以降はざっくりと消します。 先頭にあるtrigger はパイプラインを実行するためのトリガです。ここでは、master 基点でパイプラインを実行しますが、色々条件を付けることができます。実際にビルドを走らせるVMは、ubuntu-latest を選んでおけばよいでしょう。Javaですし、どこでコンパイルしても同じですし。 trigger: - master pool: vmImage: ubuntu-latest ビルドステップ ビルドステップには、mvn packageするタスクを設定します。オプションはドキュメント参照していただくとして、ポイントはオプションに、--no-transfer-progress を付けないと、延々とダウンロードプログレスが表示されてログが見にくくなるくらいでしょうか。あとは、Java のバージョンに気をつけてください。1.11 が JDK11となっています。 Azure DevOps ポータルのパイプライン編集画面で編集すると、プロパティの補完があって、ダイアログベースでも設定を変更できます。また、リスト選択もできますので、慣れないうちはポータルでやると便利です。 Maven のビルドおよびリリースタスク - Azure Pipelines | Microsoft Docs - stage : build displayName : build jobs: - job: displayName: build job steps: - task: Maven@3 inputs: mavenPomFile: 'pom.xml' options: '--no-transfer-progress' publishJUnitResults: true testResultsFiles: '**/surefire-reports/TEST-*.xml' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.11' mavenVersionOption: 'Default' mavenAuthenticateFeed: false effectivePomSkip: false sonarQubeRunAnalysis: false goals: package package まで走らせますので、テストコードがあれば実行されます。テスト結果は、統計情報をして蓄積されるので、Azure DevOps ポータルでモニタすることができます。 Azure DevOpsの フィード準備 作成したJARをデプロイするには、Aritifactの機能を使います。Create New Feed から新しいフィードを作成できます。フィードを作成したら、Connect Feed で、pom.xml に埋め込む情報を取得します。 Mavenを選択すると、repositoriesとdistributionManagement に配置する情報と、外部からアクセスする際に認証する情報が表示されます。ここでは割愛しますが、適当にpoml.xml の修正と、~/.m2~ に資格情報を置いてください。今回のシナリオでは後者は使わないです。 設定例としては以下の通りです。 <distributionManagement> <repository> <id>SandboxProject</id> <url>https://pkgs.dev.azure.com/foo/bar/_packaging/SandboxProject/maven/v1</url> <releases> <enabled>true</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots> </repository> </distributionManagement> デプロイステップ 次は、mvn deploy するタスクを配置します。dependsOn で前ステップに依存していることを明示します。前タスクが失敗すると、こちらは実行されません。また、認証タスク MavenAuthenticate@0 を設定しておかないとデプロイで失敗しますのでご注意を。フィードを指定するだけで特に特殊な設定は必要ないです。 - stage : deploy displayName : deploy dependsOn: build jobs: - job: displayName: deploy library steps: - task: MavenAuthenticate@0 inputs: artifactsFeeds: 'SandboxProject' - task: Maven@3 inputs: mavenPomFile: 'pom.xml' options: '--no-transfer-progress' publishJUnitResults: true testResultsFiles: '**/surefire-reports/TEST-*.xml' javaHomeOption: 'JDKVersion' jdkVersionOption: '1.11' mavenVersionOption: 'Default' mavenAuthenticateFeed: false effectivePomSkip: false sonarQubeRunAnalysis: false goals: deploy パイプラインの実行 今回の設定ですと、masterに変更があるたびにパイプラインが実行されます。成功しますと以下の表示になるでしょう。 各ステップの詳細をログを見ることも出来ます。 確認 最終的にArtifactタブからパッケージがデプロイされているのが確認できればOKでしょう。com.example.moris以外は、アップストリームのものがキャッシュされている感じです。 改善点 今回のパイプライン構成ですと、ビルドステップでパッケージングまでしたバイナリファイル群が、後続のデプロイステップで再利用されません。それはリポジトリが毎回クローンされ利用されるからです(クローンしない設定もできます) そのために、パイプライン中の成果物を一時的に保存しておくことができます。これを、ビルドステップとデプロイステップの間に入れることによって、ビルドステップで生成したバイナリファイル群を引き継ぐことが出来ます。 パイプラインでの成果物の発行と使用 - Azure Pipelines and TFS | Microsoft Docs 色々試行錯誤したんですが、この機能を使うとダウンロードしたファイル群はファイル日付がかわっていて、mvn pakcageすると ソースファイルが変更されたとして、ビルド->テスト->パッケージと再度実行されてしまいました。テスト程度ならスキップできますが、結局色々ビルドプロセスが走ってしまい、無駄なCPUを使ってしまいます。ビルドそのものをスキップする事も出来そうでしたが、試していません。 次に、mvn deploy:deploy しようと思い立ったんですが build artifact が含まれていないとエラーが出てデプロイできない感じでしたので、自分の知識不足でよい解決案が浮かびませんでした。大きなプロジェクトだと、ビルド時間も馬鹿にならないですし、無料枠、料金にも影響してきそうです。 補足として、ビルドステップとデプロイステップの間に、承認を設定することもできますので、実際にデプロイするのになんらかのチェックが必要でしたら、そういうことをすることも出来ます。ただ、もう少しトリガを真面目に設計したほうがよいのかもしれません。 Javaのバージョンについて ちなみに、Java のバージョンは以下の通りです。shタスクでjava -versionを実行して表示させました。Zulu かと思ったら、 AdoptOpenJDK でした。近い将来は、Microsoft謹製のOpenJDKに置き換わるのかもしれません。 /usr/bin/bash --noprofile --norc /home/vsts/work/_temp/2c28180c-347e-4efe-8a59-234727097245.sh openjdk version "11.0.11" 2021-04-20 OpenJDK Runtime Environment AdoptOpenJDK-11.0.11+9 (build 11.0.11+9) OpenJDK 64-Bit Server VM AdoptOpenJDK-11.0.11+9 (build 11.0.11+9, mixed mode) Finishing: Bash 試したことはありませんが、外部からJDKを持ち込めるようです。Java ツールインストールタスクを利用すると、外部のストレージからインストールできそうでした。ライセンスあることが前提だと思いますが、Oracle VM とか持ち込めるのかもしれません。あとマイナーバージョンまで固定で勝手に変って欲しくない場合、JDKのバージョンをフルコントロールしたいSIな環境ですと、役に立つかもしれません。 Java ツールインストーラータスク - Azure Pipelines | Microsoft Docs
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Payara MicroのWebアプリケーションをAzure App Serviceで動かす

以下のドキュメントを参考にPayara MicroのWebアプリをAzure App Serviceで動かしてみました。 プロジェクトをMicroProfile Starterで作成します。 プロジェクトに含まれるコードはDemoRestApplication.javaとHelloController.javaのみです。 package com.example.demo; import javax.enterprise.context.ApplicationScoped; import javax.ws.rs.ApplicationPath; import javax.ws.rs.core.Application; /** * */ @ApplicationPath("/data") @ApplicationScoped public class DemoRestApplication extends Application { } package com.example.demo; import javax.inject.Singleton; import javax.ws.rs.GET; import javax.ws.rs.Path; /** * */ @Path("/hello") @Singleton public class HelloController { @GET public String sayHello() { return "Hello World"; } } コードは特に変更せず、そのまま使いました。 pom.xmlのbuildセクションに以下を追加します。 <plugin> <groupId>com.microsoft.azure</groupId> <artifactId>azure-webapp-maven-plugin</artifactId> <version>1.14.0</version> </plugin> 以下のコマンドを実行して、Linux、Java 11、Tomcat 9.0を選びました。 mvn com.microsoft.azure:azure-webapp-maven-plugin:1.14.0:config その後、pom.xmlに以下の変更を加えます。 webContainerをTomcatからjava11(またはJava SE)に変更 appSettingsを追加 includeのwarをjarに変更 実際のpom.xmlはこちらです。 <?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>demo</artifactId> <version>1.0-SNAPSHOT</version> <packaging>war</packaging> <properties> <maven.compiler.target>11</maven.compiler.target> <failOnMissingWebXml>false</failOnMissingWebXml> <maven.compiler.source>11</maven.compiler.source> <payaraVersion>5.2020.2</payaraVersion> <final.name>demo</final.name> </properties> <dependencies> <dependency> <groupId>org.eclipse.microprofile</groupId> <artifactId>microprofile</artifactId> <version>3.3</version> <type>pom</type> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>demo</finalName> <plugins> <plugin> <groupId>com.microsoft.azure</groupId> <artifactId>azure-webapp-maven-plugin</artifactId> <version>1.14.0</version> <configuration> <schemaVersion>v2</schemaVersion> <subscriptionId>xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxx</subscriptionId> <resourceGroup>demo-xxxxxxxxxxxxxx-rg</resourceGroup> <appName>demo-xxxxxxxxxxxxxx</appName> <pricingTier>P1v2</pricingTier> <region>westeurope</region> <runtime> <os>Linux</os> <javaVersion>java11</javaVersion> <webContainer>java11</webContainer> </runtime> <appSettings> <property> <name>PORT</name> <value>8080</value> </property> <property> <name>WEBSITES_PORT</name> <value>8080</value> </property> <property> <name>WEBSITES_CONTAINER_START_TIME_LIMIT</name> <value>600</value> </property> </appSettings> <deployment> <resources> <resource> <directory>${project.basedir}/target</directory> <includes> <include>*.jar</include> </includes> </resource> </resources> </deployment> </configuration> </plugin> </plugins> </build> <profiles> <profile> <id>payara-micro</id> <activation> <activeByDefault>true</activeByDefault> </activation> <build> <plugins> <plugin> <groupId>fish.payara.maven.plugins</groupId> <artifactId>payara-micro-maven-plugin</artifactId> <version>1.0.5</version> <executions> <execution> <phase>package</phase> <goals> <goal>bundle</goal> </goals> </execution> </executions> <configuration> <payaraVersion>${payaraVersion}</payaraVersion> </configuration> </plugin> </plugins> </build> </profile> </profiles> </project> あとはビルドしてデプロイするだけです。 mvn clean package mvn com.microsoft.azure:azure-webapp-maven-plugin:1.14.0:deploy アクセスすると以下の表示になります。 helloエンドポイントにアクセスるとHello Worldが表示されます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

プリキュアで覚えるポリモーフィズム

まえがき みなさんはプリキュアは好きですか? 私?えぇもちろん大好きですよ。 好きなプリキュアはキュアミューズ、キュアハート、キュアエール、キュアミルキーです。 まぁそんな事は置いといてですね? ある日思ったんですよ。 「プリキュアってポリモーフィズムの説明に使えるくない?」って なので今回はそんな記事です。 前提環境 これから登場するお話は全て以下の環境を前提に書いています。 OS: Windows 10 20H2(19042) Java: OpenJDK 16 開発環境: Eclipse 2021-03 まぁJavaなのでOSとか開発環境とか特に気にしなくても大丈夫ですよ。Javaのバージョンさえ合わせていればね。 Javaのバージョンも8くらいからなら動きます(多分) 1.ポリモーフィズムとは? この記事執筆時点でのWikipediaには以下のように記されています。 プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。ポリモルフィズム、多態性、多相性、多様性とも呼ばれる。対義語はモノモーフィズム (Monomorphism)、単態性、単相性で、プログラミング言語の各要素が唯一つの型に属するという性質を指す。 はて?何を言ってるのかさっぱりわからん。 まぁ筆者がそんな事を言ってたらこの記事が成り立たないのでそんなことは無いです。 つまりですね? インスタンス(クラスをnewしたもの)をインスタンスの型の他、様々な型の中に入れることができる!ってこと。 StringクラスのインスタンスはObjectの型の中に入れる事ができる! Object a = "aaa"; StringクラスのインスタンスはCharSequenceの型の中に入れる事ができる! CharSequence b = "bbb"; なぜこんな事ができるのか? Stringクラスのjavadoc(Javaのドキュメント)にはこう書かれています。 クラスString java.lang.Object java.lang.String すべての実装されたインタフェース: Serializable, CharSequence, Comparable<String> つまりこれは、Stringクラスは Objectを継承してて、 Serializableと、CharSequenceと、Comparableってインタフェースを実装している って事。 インスタンスは継承してたり、実装されてたりしたクラス、インタフェースを型にしてインスタンスを代入することができる! なのでObjectに入れる事ができるんですね~~~ 補足 データ型が親クラスのだったりするとそのクラスで初めて書かれたメソッドやフィールドを呼び出す事ができません。 つまり、Objectに入れたStringのインスタンスはStringクラスのメソッドを呼び出せないということです。 Object a = "abc"; a.substring(0,2);//これは無理! じゃぁどうすれば良いのか 答えは「キャスト」するんです! Object a = "abc"; ((String)a).substring(0,2);//OK こんなふうに、変数の前に括弧でStringって書ことをキャストって言います。 それで、(String)aをもう一つ括弧で囲ってあげると、「((String)a)」これ自体がStringになるので、 これに対してsubstring()というStringクラスのメソッドが実行できるようになるわけですね~ 本題 話がダイブそれてしましました… さて、プリキュアの話に戻りましょう。 1番可愛いプリキュアがキュアミューズな事は周知の事実なのですが、今回は最新のプリキュア、トロピカルージュプリキュアでやりましょう。 まずポリモーフィズムでは上の項目で話した通り、親クラスや実装しているインタフェースが必要です。 そこで今回はインタフェース「Precure」を作って各プリキュアクラスに実装しましょう。 サンプルなのであまり複雑にならないようにメソッドを2つだけにします。 //Precure.java package com.sakurai_shinya.precure_polymorphism; public interface Precure { void transform(); void lastAttack(); } はい、これで実装するインタフェースが完成しました。 次にトロピカルージュプリキュアの4人を作っていきましょう //CureSummer.java package com.sakurai_shinya.precure_polymorphism; public class CureSummer implements Precure { @Override public void transform() { System.out.println("ときめく常夏!キュアサマー!"); } @Override public void lastAttack() { System.out.println("プリキュア!おてんとサマーストライク!"); System.out.println("ビクトリー!"); } } 他3人は省略してメソッドの部分のみを記載します。 //CureCoral.java @Override public void transform() { System.out.println("きらめく宝石!キュアコーラル!"); } @Override public void lastAttack() { System.out.println("プリキュア!もこもこコーラルディフュージョン"); System.out.println("ビクトリー!"); } //CurePapaya.java @Override public void transform() { System.out.println("ひらめく果実!キュアパパイヤ!"); } @Override public void lastAttack() { System.out.println("プリキュア!ぱんぱかパパイアショット!"); System.out.println("ビクトリー!"); } //CureFlamingo.java @Override public void transform() { System.out.println("はためく翼!キュアフラミンゴ!"); } @Override public void lastAttack() { System.out.println("プリキュア!ぶっとびフラミンゴスマッシュ!"); System.out.println("ビクトリー!"); } それでは今回起動するプログラムを書いていきます。 //Main.java package com.sakurai_shinya.precure_polymorphism; public class Main { public static void main(String[] args) { // インスタンス作成 Precure precure = new CureSummer(); // 変身 precure.transform(); // 極め技 precure.lastAttack(); } } さて、ここまで書けたらぜひ実行してみてください。 ときめく常夏!キュアサマー! プリキュア!おてんとサマーストライク! ビクトリー! こんなように出力されれば成功です! 次にMainクラスの「//インスタンス作成」って書いてある行の newの後ろのクラス名の部分だけを別のプリキュアクラスに変更して実行してみてください。 Precure precure = new CureCoral(); //CureSummer → CureCoral さて、どうなるでしょうか。 きらめく宝石!キュアコーラル! プリキュア!もこもこコーラルディフュージョン ビクトリー! こんなように出力されれば成功です! さて、ここまで来て理解できればこの記事を私が書いたのにも意味があったというものですよ。 ここで気づいて欲しいのは、 「インスタンスが変わると挙動が変わる」ということ。 new の後ろのクラス名を変えるということはインスタンスを変えているということです。 「インスタンスが変わると」ってところが大事なんですよ。 例えばifとかswitchで結果的な挙動が変わってるという事ではポリモーフィズムとは言えません。 このポリモーフィズムを応用すると、引数としてインスタンスを渡すと処理が変わるメソッドなんてのも作れるようになります。 (マルチスレッドプログラミングを行う時に使うThreadクラスとRunnableインタフェースもその例ですね) 最後に プリキュアは良いぞ。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む