Javaの列挙型について(1)
Javaの列挙型について。
public static final int DIRECTION_NORTH = 0; public static final int DIRECTION_EAST = 1; public static final int DIRECTION_SOUTH = 2; public static final int DIRECTION_WEST = 3; private static void showDirection(int direction) { switch (direction) { case DIRECTION_NORTH: System.out.println("北"); break; case DIRECTION_EAST: System.out.println("東"); break; case DIRECTION_WEST: System.out.println("西"); break; case DIRECTION_SOUTH: System.out.println("南"); break; default: break; } } public static void main(String[] args) { showDirection(DIRECTION_NORTH); }
方角として定数を定義。
その方角を引数して取る(ことを想定した)メソッドと,
それをつかったmain関数。
しかし,こんなコードも書けてしまう。
public static void main(String[] args) { showDirection(0); showDirection(-1); }
showDirectionメソッドは引数として方角を取ることを想定している。
しかし,実際はint型の引数だから,方角の定数以外も引数にできてしまう。
そのため,北の入力としてDIRECTION_NORTHでなく0を入れることもできる。
また,0,1,2,3,以外の値も入力にできる。
良くない。
実際には上のようなソースコードを書くことは無いと思うけれど。
結果的にそうなってしまうパターンもあるのでは。(あるかな?)
そこで,列挙型を使ってみた。
Direction.java
package com.rmstar.enumsample; public enum Direction { NORTH, EAST, SOUTH, WEST, }
Main.java
package com.rmstar.enumsample; public class Main { private static void showDirection(Direction direction) { switch (direction) { case NORTH: System.out.println("北"); break; case EAST: System.out.println("東"); break; case WEST: System.out.println("西"); break; case SOUTH: System.out.println("南"); break; default: break; } } public static void main(String[] args) { showDirection(Direction.NORTH); } }
列挙体を使えば,showDirectionの中に0や-1みたいな想定外の入力が入ることも無い。
Javaの 列挙型は他の言語と違ってクラス。
次はこの当りを確認したいと思います。
それでは,また会えることを祈りつつ。
C#で継承とかポリモーフィズムとか(2) 抽象クラスとかインターフェースとか
抽象クラスを使ってみた。
abstract class AbstractSuper { public void Process() { Prepare(); Execute(); } abstract protected void Prepare(); abstract protected void Execute(); } class ImplA : AbstractSuper { protected override void Prepare () { Console.WriteLine ("Prepare ImplA"); } protected override void Execute () { Console.WriteLine ("Execute ImplA"); } } class ImplB : AbstractSuper { protected override void Prepare () { Console.WriteLine ("Prepare ImplB"); } protected override void Execute () { Console.WriteLine ("Execute ImplB"); } } class MainClass { public static void Main (string[] args) { new ImplA().Process(); Console.WriteLine (); new ImplB().Process(); } }
特に違うところは無いのかな?
Prepare ImplA Execute ImplA Prepare ImplB Execute ImplB
インターフェースを使ってみた。
interface IHogeHoge { void Hello(); void HogeHoge(); } interface IFugaFuga { void Hello(); void FugaFuga(); } class Impl : IHogeHoge, IFugaFuga { public void Hello () { Console.WriteLine ("Hello"); } public void FugaFuga () { Console.WriteLine ("FugaFuga"); } public void HogeHoge () { Console.WriteLine ("HogeHoge"); } } class MainClass { public static void Main (string[] args) { Impl impl = new Impl(); impl.FugaFuga(); impl.HogeHoge(); impl.Hello(); } }
override書かないんだ。
実行結果は,
FugaFuga HogeHoge Hello
次みたいなこともできる。
interface IHogeHoge { void Hello(); void HogeHoge(); } interface IFugaFuga { void Hello(); void FugaFuga(); } class Impl : IHogeHoge, IFugaFuga { void IHogeHoge.Hello () { Console.WriteLine ("HogeHoge Hello"); } void IFugaFuga.Hello () { Console.WriteLine ("FugaFuga Hello"); } public void FugaFuga () { Console.WriteLine ("FugaFuga"); } public void HogeHoge () { Console.WriteLine ("HogeHoge"); } } class MainClass { public static void Main (string[] args) { Impl impl = new Impl(); impl.FugaFuga(); impl.HogeHoge(); ((IHogeHoge)impl).Hello(); ((IFugaFuga)impl).Hello(); } }
なるほど。
要キャスト。
C#で継承とかポリモーフィズムとか(1) 仮想関数?
class Super { public void Hello () { Console.WriteLine ("Hello, this is Super class."); } } class Sub : Super { public void Hello () { Console.WriteLine ("Hello, this is Sub class."); } } class MainClass { public static void Main (string[] args) { Super super = new Super(); super.Hello(); Sub sub = new Sub(); sub.Hello(); Super subInSuper = new Sub(); subInSuper.Hello(); } }
C#で継承。
よくある例。だと思う。
実行結果は,こうなりました。
Hello, this is Super class. Hello, this is Sub class. Hello, this is Super class.
3行目が,期待していたのと違う。
Superクラスのメソッドが呼び出されていて,
オーバーライドされていない?
オーバーライド"される"側にvirtual
オーバーライド"する"側にoverride
が必要らしい。
書き換えると,
class Super { public virtual void Hello () { Console.WriteLine ("Hello, this is Super class."); } } class Sub : Super { public override void Hello () { Console.WriteLine ("Hello, this is Sub class."); } } class MainClass { public static void Main (string[] args) { Super super = new Super(); super.Hello(); Sub sub = new Sub(); sub.Hello(); Super subInSuper = new Sub(); subInSuper.Hello(); } }
ちゃんと動いた。
Hello, this is Super class. Hello, this is Sub class. Hello, this is Sub class.
仮想関数。
サブクラスでオーバーライドして挙動を変更することが出来る関数。
wikipedia先生が教えてくれました。
C++やC#だとvirtualって書いて仮想関数にしないと,
オーバーライドしても挙動が変わらないらしい。
ちなみにJavaは全ての関数が仮想関数らしい。
virtual書かなくて,はまることがありそうだから気をつけないと。
以上です。
それでは,また会えることを祈りつつ。
Hello Widget! (1) 最小構成のWidget
Androidを持ち始めてそろそろ1年と半年だけど,
正直しっかりとWidgetを使い始めたのは最近。
作ってみた経験が無かったので,
とりあえずHello WorldなWidgetを作ってみようと思います。
Hello worldプログラムはHello Worldって表示するだけで,何もしない。
だから今回つくるWidgetもとりあえず,
ホーム画面に置けて,Hello Widget Worldって書いてある。
それだけの最小公正なWidgetを作ってみたいと思います。
Eclipseで,普通のアプリケーションを作るようにプロジェクトを作成
パッケージ名:com.rmstar.hellowidget
プロジェクト名:HelloWidget
まずは,Widgetのレイアウトを定義。
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#FF777777" > <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:layout_margin="10dip" android:background="#FFFFFFFF" android:gravity="center" android:text="@string/hello_world" android:textColor="#FF000000" android:textSize="12sp" /> </RelativeLayout>
widgetのホーム画面上でのサイズ,更新間隔,レイアウト指定をするファイルを作成。
res/xml/hello_widget.xml
<?xml version="1.0" encoding="utf-8"?> <appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android" android:initialLayout="@layout/hello_widget_layout" android:minHeight="72dip" android:minWidth="72dip" android:updatePeriodMillis="0" > </appwidget-provider>
マニフェストファイルを編集。
Activityなし。
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.rmstar.hellowidget" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="15" /> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" > <receiver android:name=".HelloWidgetProvider" android:label="@string/widget_name" > <intent-filter> <action android:name="android.appwidget.action.APPWIDGET_UPDATE" /> </intent-filter> <meta-data android:name="android.appwidget.provider" android:resource="@xml/hello_widget" /> </receiver> </application> </manifest>
やっと,Javaの編集。
だけど空っぽ。
src/com/rmstar/hellowidget/HelloWidgetProvider
package com.rmstar.hellowidget; import android.appwidget.AppWidgetProvider; public class HelloWidgetProvider extends AppWidgetProvider{ }
これと各種サイズのアイコンic_launchar.pngと,
文字列定義ファイルstrings.xmlを書き換えて,不要な物は消しました。
res/values/strings.xml
<resources> <string name="app_name">HelloWidget</string> <string name="hello_world">Hello\nwidget\nworld!</string> <string name="widget_name">HelloWidget</string> </resources>
実機につなげて,Eclipseで実行するも応答なし。
えっ?
出てこない。
そりゃそうでした。
Widgetなんで。
Widget選択画面で普通にありました。
HelloWidgetが。
うっかり。
とりあえず,最小構成
HelloWorldがでるだけのWidgetはできました。
それではまた会えることを祈りつつ。
C#のプロパティを使ってみた。
class Person { private string name; private int age; public Person (string name, int age) { this.name = name; this.age = age; } public string GetName () { return name; } public int GetAge () { return age; } public void SetAge (int age) { this.age = age; } public override string ToString () { return string.Format ("[{0} : age {1}]", name, age); } }
というクラスをプロパティを使って書き換えてみました。
こんなかんじですかね。
class Person { public Person(string name, int age) { this.Name = name; this.Age = age; } public string Name { private set; get; } public int Age{ set; get; } public override string ToString () { return string.Format ("[{0} : age {1}]", Name, Age); } }
短い!
いいですね。これ。
ただ外からこれを使う時に,
person.GetName()
でなくて,
person.Name
とするのが,今は違和感を感じます。
考察?とか
プロパティは,
使う側から見るとインスタンス変数に見えて,
実装する側から見るとメソッドと同じように実装が出来る
だそうで。
実装が変わった時その影響範囲が広くなってしまうため,
publicなフィールド(インスタンス変数)でなく,
privateなフィールドで,それに対するアクセッサメソッドを定義するべき,
というのは,いろいろな本で言及されています。
プロパティーを使うと非常に短く,アクセッサーを実装できていいですね。
プロパティーの細かい実装も定義できるようで,以下のようにも書けるようです。
class Person { private string name; public Person(string name, int age) { this.name = name; this.Age = age; } public string Name { get{ return name; } } public int Age{ set; get; } public override string ToString () { return string.Format ("[{0} : age {1}]", Name, Age); } }
以上です。
また会えることを祈りつつ。
C#で単純なクラスを定義してみた。
名前と年齢を表すフィールドと,そのアクセッサー。
そして,toStringをオーバーライド。
これだけの単純なクラスをC#で作りたいと思います。
Javaだとこんな感じですかね。
public class Person { private String mName; private int mAge; public Person(String name, int age) { mName = name; mAge = age; } public String getName() { return mName; } public int getAge() { return mAge; } public void setAge(int age) { mAge = age; } @Override public String toString() { return String.format("[%s : age %d]", mName, mAge); } }
使う側。
public static void main(String[] args) { Person taro = new Person("Taro", 24); System.out.println(taro); System.out.println(String.format("%s is %d years old.", taro.getName(), taro.getAge())); taro.setAge(taro.getAge() + 1); System.out.println("A year later."); System.out.println(String.format("%s is %d years old.", taro.getName(), taro.getAge())); System.out.println(taro); }
C#で書いてみました。
こんな感じですかね。
class Person { private string name; private int age; public Person (string name, int age) { this.name = name; this.age = age; } public string GetName () { return name; } public int GetAge () { return age; } public void SetAge (int age) { this.age = age; } public override string ToString () { return string.Format ("[{0} : age {1}]", name, age); } }
使う側は,
public static void Main (string[] args) { Person taro = new Person ("taro", 24); Console.WriteLine (taro); Console.WriteLine (string.Format ("{0} is {1} years old.", taro.GetName(), taro.GetAge())); taro.SetAge(taro.GetAge() + 1); Console.WriteLine ("A year later."); Console.WriteLine ("{0} is {1} years old.", taro.GetName(), taro.GetAge()); Console.WriteLine (taro); }
フィールド・インスタンス変数の命名規約
Code Style Guidelines for Contributorsに沿ってJavaを書く際自分は,
privateで否staticなフィールド名には,「m」をつけています。
C#の方は,
技術評論社さんの"読みやすく効率的なコードの原則 C#ルールブック"の56ページ。
「2.12.3 public 以外のインスタンス変数はCamel形式にする」に従い,
フィールド(C#だからインスタンス変数か)Camel形式にしました。
C#とJavaのHello worldを見比べて。
package com.mrstar; public class Main { public static void main(String[] args) { System.out.println("Hello world!"); } }
using System; namespace HelloCSWorld { class MainClass { public static void Main (string[] args) { Console.WriteLine ("Hello World!"); } } }
見比べて思ったこと。
中括弧「{」の位置にすごい違和感が...
業務では,JavaでAndroidを開発していて,
コントリビューター用のコーディングスタイルですが,
Code Style Guidelines for Contributors
http://source.android.com/source/code-style.html#use-standard-brace-style
に沿うようなスタイルで開発しています。
このスタイルでは,中括弧は改行していません。
(上記のページのBrace Style参照)
一方で,C#の手元にある参考書は全て中括弧は「{」で改行していました。
Visual StudioのC#コーディング規則でも,中括弧を改行する形式で書かれていました。
http://msdn.microsoft.com/ja-jp/library/vstudio/ff926074.aspx
中括弧
違和感ありまくり。
まぁ書いているうちになれるか。
namespace
Javaのpackageに該当するのかな?
C#のnamespaceはJavaのpackageと違って,
ソースコードの物理パスとか考えなくていいんですね。
それから,ファイル名とクラス名が一致する必要も無いんですね。
下記のソースコードみたいに,
一つのファイルに,複数のnamespaceも定義出来れば,
namespace入れ子による階層化も出来れば,
.による階層化も出来るみたいですね。
でも,単一ファイルでこんなに定義はしないか。
using System; namespace HelloCSWorld { class MainClass { public static void Main (string[] args) { NameSpaceA.Util.ShowMessage(); NameSpaceB.Util.ShowMessage(); NameSpaceA.Sub.Util.ShowMessage(); NameSpaceB.Sub.Util.ShowMessage(); } } } namespace NameSpaceA { class Util { public static void ShowMessage () { Console.WriteLine("NameSpaceA.Util"); } } namespace Sub { class Util { public static void ShowMessage () { Console.WriteLine("NameSpaceA.Sub.Util"); } } } } namespace NameSpaceB { class Util { public static void ShowMessage () { Console.WriteLine("NameSpaceB.Util"); } } } namespace NameSpaceB.Sub { class Util { public static void ShowMessage () { Console.WriteLine("NameSpaceB.Sub.Util"); } } }
そういえば,もう何年前かは忘れたけど初めてJavaをやったころ
クラス名を変えたんだけど,
ファイル名を変え忘れて
はまったことを思い出しました。
以上です。
それでは,また会えることを祈りつつ。