korechi’s diary

とあるVR/ARエンジニアのブログ

JavaとC#の違い

自分はメインでC#を使っているのですが、とある理由でJavaもやらないといけなくなったのでまず両者の違いを知る意味も含めて簡単にまとめてみます。(適切ではないかもしれない)

C#とは

オブジェクト指向言語で、マイクロソフトの提唱する.NET Frameworkという実行環境での実行を前提とする。

メモリ管理

.NET Frameworkは自動メモリ管理で、ガベージコレクション(GC)が使われているためメモリを明示的に開放する処理が必要ない。
Javaも同様である。(C++は手動でメモリ管理する必要あり) これは仮想実行環境(VES)で提供される。

C# Java
実行環境 .Net Frameworkなど JRE(Java Runtime Environment)
仮想実行システム CLR(共通言語ランタイム) JVM(Java Virtual Machine)
共通中間言語 CIL バイトコード

アクセス修飾子

修飾子 Java C#
protected 同一のパッケージ、または派生したクラスからアクセスが可能 派生したクラスからアクセスが可能
internal 存在しない 同一のアセンブリ(DLL)内でアクセスが可能
(default) 同一のパッケージ内でアクセスが可能 同じクラス内からのみアクセスが可能(private)

データ構造

変数 C C++ Java
char 1byte 1byte 2byte
short 2byte 2byte 2byte
int 2byte 4byte 4byte
long 4byte 4byte 8byte
float 4byte 4byte 4byte
double 8byte 8byte 8byte
データを保持する場所
値型 スタック上
参照型 ヒープ上

基本構文

メインの書き方が微妙に異なる。
C#:

static void main(string[] args)

c++:

int main (int argc, char* argv[])

java:

public static void main(String[] args)

名前空間

C++: namespace
C#: namespace(.をつけて階層化可) Java: パッケージ(ソースコードを置いてある物理パスの構造がそのまま名前空間に相当する階層。ソースコード中にはパッケージ名を書かない)
ちなみに、名前空間の外をグローバルスコープという。

暗黙的な型指定

C#:

var i = 10; // i はint型になる

C++ではauto

動的型付け

static void Main() {
  Add(1, 2);
  Add("a", "b");
}
static void Add (dynamic x, dynamic y) {
  x = x + y;
}

ローカル定数

constをつければローカル定数を作れる

+演算子

C#では、+演算子を文字列の連結やデリゲートの結合に使える。

フォークスルー

C#でのみ、case文でのフォークスルーが禁止されている。使いたいならgoto文を使う

switch(x) {
  case 0:
    // breakなどを書かないとコンパイルエラー
  case 1:
    goto case 2;
  case 2:
    break;
  default:
    break;
}

※goto はブロック内から外に抜けられるが、逆はできない
Javaにgotoはない(今のところ)

foreach

C++, C#は使えるが、Javaで使いたいなら

for (int i : intArray) {
}

のようにfor文をつかって実現可

isとas

C#には両方あり、C++にはどちらもなく、Javaにはasがありisのかわりにintanceofがある。

lock

同時に複数スレッドの実行を許さない。
C++にはない、Javaあsynchronizedを使う。
C#はlockステートメントがMonitorクラスを使って実装されるがJavaではJVMの機能として実装される。

とりあえずこんなところかな。今日のところはこれまでにしておきます

SmartEyeGlass用アプリを1から作る

  1. Android Studioで適当な名前のプロジェクトを作成

  2. Target DeviceをGlassにする f:id:korechi:20160325134524p:plain

  3. あとはNextを選択してFinishでサンプルプロジェクトが立ち上がる

  4. Android Manifestをインクルード
    AndroidManifest.xmlをプロジェクトにインクルードする。
    すでにAndroidManifest.xmlがある場合は、サンプルプロジェクト内のapp/manifesestsにこのファイルが入っているのが確認できるのでそれを真似する

  5. File/New/Import Moduleを選択
    SmartExtensionAPIとSmartExtensionUtilsとSmartEyeGlassAPIをプロジェクトにインポートする

  6. build.gradleの一番下に以下を記述

dependencies {
    compile project(':SmartExtensionAPI')
    compile project(':SmartExtensionUtils')
    compile project(':SmartEyeglassAPI')
}

これを記述しないとimportができないので注意

ここまででひと段落。
次はjavaクラスを追加していきます

その際に最低限必要なクラスは
Constants
BroadcastReseiver
ExtensionService
RegistrationInformation
ControlExtension
PreferenceActivity

あると便利なクラスとして
ScreenSize
があります。これらを

  1. 基本となるクラスを継承する Constantsクラスはそのままjavaフォルダ下にコピー
    BroadcastReseiver、ExtensionService、RegistrationInformation、ScreenSizeはそれぞれを継承したクラスがあるはずなので、それらをうまい名前に変えてコピー

これらは基本的に中身はそんなに変えなくていいはず
2. ControlExtensionとPreferenceActivityを継承したjavaクラスを作る

public class SampleControlExtension extends ControlExtension {}
public class MainActivity extends PreferenceActivity {}

ControlExtensionclassを継承することで、defineやディスプレイのレイアウト、イベントリスナーの作成、イベントハンドラーの定義、デバイスセンサーからのデータ取得を行える
(具体的にはSmartEyeglassControlUtilsを使えば大体の操作ができる)

もし、Android端末では何も行わないならばPreferenceActivityには何も記述しない
ここまで出来れば下の図のような配置になっているはず
f:id:korechi:20160325142850p:plain 3. layoutを作る
app/res/にlayout.xmlを作り、テキストなど適当に配置する
(ここはスルーしてもいい)
4. SampleControlExtensionを作る ここではグラスにHello Worldを表示するだけの機能を持たせたクラスとする

public class SampleControlExtension extends ControlExtension {

    private final SmartEyeglassControlUtils utils;
    private static final int SMARTEYEGLASS_API_VERSION = 1;

    public SampleControlExtension(Context context, String hostAppPackageName) {
        super(context, hostAppPackageName);

        // utilの初期化
        utils = new SmartEyeglassControlUtils(hostAppPackageName, null);
        utils.setRequiredApiVersion(SMARTEYEGLASS_API_VERSION);
        utils.activate(context);
        updateLayout();
    }

    @Override
    public void onResume() {
        updateLayout();
        super.onResume();
    }

    @Override
    public void onDestroy() {
        utils.deactivate();
    }

    @Override
    public void onTouch(final ControlTouchEvent event) {
        super.onTouch(event);
    }

    private void updateLayout() {
        showLayout(R.layout.layout, null);
        sendText(R.id.sample_text, "Hello World!");
    }
}

以上!これで動くものは作れます(はず)

+α

UIの作成

SmartEyeGlassで一番上のレイヤーはcard layerと呼ばれる層で、アプリケーションを選択することができる。
WidgetAPIを使うことで、アプリの最初のアイコンを作ることができる。
詳しくはここWidgets | Sony Developer Worldを見る。

例)HelloLayouts サンプル
XML Layout definitionで使うディスプレイのサイズを定義する。
data Bundle with run-time data を作成。
ControlExtensionを継承したクラス内でSmartEyeglassControlUtils.showLayout()を使うことでディスプレイに表示させている。

イベントハンドラの追加

次に、いつ表示するかを決めなければいけない。その方法は2つあり

・built-in event callbackをoverrideする  
・イベントリスナーを作成し、ハンドラーのコールバックを定義する  

があります。

built-in event callbackをoverride

onTap()onKey()などの基本操作は備わっており、たとえばメニュー画面からアプリがタップされたら起動します。
その動作を改造したい場合は、改造したい関数をoverrideすればよい。

イベントリスナーの作成

SmartEyeglassEventListenerを継承することで、独自のリスナーやハンドラを定義できる。
ここでいうリスナーとハンドラは、
イベントハンドラー: イベントに対して処理を定義したメソッド
イベントリスナー: イベントに対して処理を結びつける仕組み。
であると考えます。(自分は)
例としては

private final SmartEyeglassEventListener mSmartEyeglassEventListener = new MySmartEyeglassEventListener();
 
class MySmartEyeglassEventListener extends SmartEyeglassEventListener {
 
     @Override
     public void onCameraReceived(CameraEvent event) {
          }
 
     @Override
     public void onCameraErrorReceived(int error) {
          }
 
     @Override
     public void onCameraReceivedFile(String filePath) {
          }
 
     @Override
     public void onRecordingStatus(long timeInMs, long frames) {
          }
 
}

のように各イベントごとに処理をoverrideする。
3. テストする 実機でもエミュレータでもいいのでテストしてみる。
GooglePlayに公開する際には、説明に“SmartEyeglass”を記載する。

以上で簡単なプロジェクト作成に必要なものたちを紹介しました。

SmartEyeGlass開発記 〜サンプルapkをビルド〜

久しぶりの更新です。
英語の論文を書いていたり、就活となかなかコードを書かない日が続いていました。

それらがひと段落つき(つつあり)、ちょうど新しいおもちゃである
SonyのSmartEyeGlassf:id:korechi:20160210152557j:plain
を手に入れたので、それのアプリでも作ろうかと思います。

まだまだ画面が小さいなど、制限はありますが何か面白い便利なものでも作りたいなと。

自分の開発環境は、
MacBook Pro15inch(2015モデル)
SmartEyeGlass
GalaxyS2 (Android4.4.2)
を使います。

基本はSony公式(http://developer.sonymobile.com/ja/smarteyeglass/developer-tools/#seg-header )をみて進めるつもりです。英語で書かれてるけどだけど意外と読みやすい

それでは、SmartEyeGlass上でHelloWorld!を表示させるぞーー!

Android Studioのインストール

これは開発を行ううえで必要となります。そんなに難しいことではないので、お使いの環境に合わせてインストールしてください。

Sony-SmartEyeGlass-SDKのインストール

  1. IDE を開いてAndroid SDK Managerを開く
  2. Android SDK ManagerのメニューにあるToolsから、Manage Add-on Sitesを選択
  3. User Defined Sitesをクリックして、newを選択
  4. URLに(http://dl.developer.sony.com/wearables/sdks/Sony-SmartEyeglass-SDK.xml)を入力してOK
  5. Android SDK Manager に戻り、Android 4.4.2 (API 19)の中にあるSmartEyeglass SDKにチェックをつけてインストール

SDK内は以下のようになっている
1. SDK_root/docs/reference/
APIリファレンスとライブラリが含まれる
2. SDK_root/samples/
Android Studio用 のサンプルが入ってる。デモ用 3. SDK_root/apks/
コンパイル済みのapkファイルが入っている 4. SDK_root/apks/SmartEyeglassEmulator.apk
実機テストするために必要なエミュレータ。実機にインストールする 5. SDK_root/apks/samples/
apkのサンプルが入っている

サンプルをAndroid Studioで開いてみる

  1. Android Studioを開き、既存のプロジェクトを開く
  2. ~/Library/Android/sdk/add-ons/addon-sony_smarteyeglass_sdk-sony-19/samples下にあるどれか開きたいやつを選択し、開いてみる
  3. いろいろ覗く

テスト環境を整え、サンプルapkを使ってテストしてみる

  1. SmartConnectとSmartEyeglassをGooglePlayをAndroid端末にインストール(Android4.4以上必要)
  2. 端末をPCにさして、コマンド
adb install SmartEyeglassEmulator.apk

をうつ。adbなんてないよ〜って言われたら、adbへのパスを通すため、
~/.bash_profileに

export PATH=$PATH:どこか/Android/sdk/platform-tools

を追記して、

source ~/.bash_profile

すればパスが通る。もちろん上にある”どこか”については各自の環境に合わせてください。 3. 適当なapkをインストールしてみる もうapkを使用できる準備は整った。たとえば他のサンプルである

adb install HelloWorld.apk

を行えば端末にアプリがインストールされ、SmartEyeGlassが端末と繋がっていればSmartEyeGlass上にも同じアプリが表示されるはずである。

SmartEyeGlass用エミュレータも存在しますが、自分はグラス端末を持っているので実機(グラス端末)を使ってデバッグでいきます。 Android端末にSmartEyeGlass-Emulaterというアプリが入っているはずなので、それを実行すればグラス端末と同じ画面が確認できるので非常に便利。

以上でビルドまでできるようになりました。
HelloWorldという文字をSmartEyeGlassで見るのはなかなか嬉しいものですね。

Macbookの中の容量を整理

フォルダの容量を調べる

ルート直下から深さ1のもののファイルの大きさを調べるコマンドがある。

sudo du -hxd 1 /

これを深さ5までとして一括検索するコマンドは

sudo du -gxd 5 / | awk '$1 >= 5{print}' 

であり、単位はGBで出てくる。
あとは、いらなそうなファイルを削除

条件分岐のいろいろ

フォークスルー

例えばswitch文はC, C++で使われているがC#では禁止されているらしい。
case内でのbreakのし忘れが頻繁におこったためだとか

goto

goto文はifやswitchと違い、無条件に処理の流れを変える命令。そのため、あまり推奨されない。以下の2つの場合にのみ使うことがある

switch文でのgoto文の使用

switch (hoge)
{
case 1:
  goto case 2;
case 2:
  // hogeが1か2だった場合の処理
  break;
default:
  break;
}

for文をぬけ出すための処理

以下のように、for文が2つ以上囲んである場合、その中から抜け出すにはgotを使う。なぜならbreakだとfor(j)からのみぬけ出すことになるから。

for (int i = 0;; i++) {
  for (int j = 0;; j++) {
    if (/*for文全部から抜け出したい*/) {
      goto LOOPEND;
    }
  }
}
LOOPEND:
;

Linuxで接続待ち(中)のポートを切る方法

netstat -a | grep localhost

とコマンドを打つと、接続がきれたsshを終了させるか待ち状態になっていることがある。
そのポートを閉じたいときは-pオプションをつけるとプロセスIDが左に表示されるので

kill <PID>

で閉じることができる