Javaを使ったオブジェクト指向プログラミング総まとめ
勉強会に向けて作った資料が、「まぁ自分の割にはそこそこなの作れたのかな」と思ったので、これを期に初投稿。といいつつ、これで間違った内容を書いていたらとてもとても恥ずかしい。
クラスとは
オブジェクト指向では、__振る舞い__と__属性__を持つ1の単位を__オブジェクト__と呼び、このオブジェクトの種類を__クラス__と呼ぶ。もう少し話を砕くと、
- 振る舞い:ある動作。メソッド
- 属性:ある情報。フィールド
- オブジェクト: メソッド+フィールド(つまり__メンバ__)
- クラス:オブジェクトの種類
である。
クラスの定形構文は以下の通りである。
class sandbox {
public int field;
public void method() {
// Write anything process.
}
}
基本的なクラスの使い方
インスタンス化
クラスオブジェクトを生成すること。別名「new
する」。インスタンス化は以下のように行う。インスタンス化することで、インスタンス化したクラスのメンバやメソッドが使える。
class sandbox {
public static void main(String[] args) {
Class cls = new Class(); // Create instance.
cls.method(); // You can action method() of Class.
}
}
class Class {
public int field;
public void method() {
// Write anything process.
}
}
コンストラクタ
コンストラクタとは__インスタンス化された際に一度だけ実行されるメソッド__。コンストラクタを生成する際は、メソッド名をクラス名と同じにすれば良い。
class sandbox {
public static void main(String[] args) {
Class cls = new Class();
// Create instance and action constructor.
}
}
class Class {
public int field;
public Class() {
System.out.println("Action constructor.");
}
public void method() {
// Write anything process.
}
}
実行結果
Action constructor.
修飾子
1. アクセス修飾子
アクセス修飾子をつけることで、外部からのアクセスを制限することができる。
アクセス修飾子 | アクセス可能範囲 |
---|---|
public |
すべて |
protected |
同一パッケージ内・自クラス・サブクラス |
なし | 同一パッケージ内・自クラス |
private |
自クラス |
簡単なアクセス例は以下の通り。
class sandbox {
public static void main(String[] args) {
Class cls = new Class(); // Create instance.
System.out.println("You can access " + cls.public_fld + " field.");
System.out.println("You can access " + cls.protected_fld + " field.");
System.out.println("You can access " + cls.nothing_fld + " filed.");
// Compile err.
// System.out.println("You can " + cls.private_fld + " field.");
}
}
class Class {
public String public_fld = "public";
protected String protected_fld = "protected";
String nothing_fld = "nothing";
private String private_fld = "private";
}
実行結果
You can access public field.
You can access protected field.
You can access nothing field.
最後のSystem.out.println("You can " + cls.private_mbr + "member");
をコメント解除してコンパイルしようとすると、アクセス制限でコンパイルエラーが起きる。
2. static
修飾子
static
修飾子をつけると、実行時にメモリ上に展開されてインスタンス化しなくてもアクセスできるようになる。
class sandbox {
public static void main(String[] args) {
System.out.println("You can access " + Class.static_fld + " field.");
}
}
class Class {
static String static_fld = "static";
}
実行結果
You can access static field.
3. final
修飾子
final
修飾子を使用することで、定数とし、値の変更ができなくなる。
class sandbox {
public static void main(String[] args) {
System.out.println("You can access " + Class.static_fld + "member.");
// Compile err.
// Class.static_fld = "final";
}
}
class Class {
static final String static_fld = "static";
}
カプセル化
フィールドとメソッドをひとまとめにして、保護したいメンバにprivate
をつけてアクセスできないようにすること。カプセル化は基本、
- 値を取得する:
getter
- 値を代入する:
setter
がよく使われている。この2つのメソッドのことは__アクセサメソッド__と呼ぶ。
class sandbox {
public static void main(String[] args) {
Class cls = new Class();
cls.setField("hoge");
System.out.println(cls.getField());
}
}
class Class {
private String field = "";
/**
* Accessor method.
* setField(String param) -> Setter
* getField() -> Getter
**/
void setField(String param) {
field = param;
}
String getField() {
return field;
}
}
実行結果
hoge
しかし、getter
とsetter
を作って、せっかくprivate
をつけたフィールドにアクセスできてしまうと意味がないという話もあって、純粋なgetter
やsetter
はカプセル化を実現しないと、この記事に書いていた。
ちなみにカプセル化は、データや処理を気にせずに目的を達成できるようにしたものという意味もある(コメントで教えていただき、記事にもしてくれました。)。
発展的なクラスの使い方
継承
クラスに__親子関係をもたせる__こと。親クラスを継承した子クラスは、親クラスの機能が受け継がれる。
class sandbox {
public static void main(String[] args) {
Child cld = new Child();
cld.sayCommentByPerson();
cld.sayCommentByChild();
}
}
// Super class.
class Person {
void sayCommentByPerson() {
System.out.println("I am Person.");
}
}
// Sub class.
class Child extends Person {
void sayCommentByChild() {
System.out.println("I am Child.");
}
}
実行結果
I am Person.
I am Child.
親クラスのコンストラクタを呼ぶには
もし、親にコンストラクタがあり、それを呼びたいときは、super();
とすれば良い。
class sandbox {
public static void main(String[] args) {
Child cld = new Child();
cld.sayCommentByChild();
}
}
// Super class.
class Person {
Person() {
System.out.println("I am Person.");
}
}
// Sub class.
class Child extends Person {
//Call constructor of super class.
Child() {
super();
}
void sayCommentByChild() {
System.out.println("I am Child.");
}
}
実行結果
I am Person.
I am Child.
オーバーロード
オーバーロードとは__異なる引数を持つ同じ名称のメソッドを複数生成する__こと。
class sandbox {
public static void main(String[] args) {
Class strClass = new Class("hoge");
Class intClass = new Class(1);
}
}
class Class {
Class(String param) {
System.out.println("String: " + param);
}
Class(int param) {
System.out.println("Integer: " + param);
}
}
実行結果
String: hoge
Integer: 1
オーバーライド
オーバーライドは、__親クラスから継承されたメソッドを子クラスで上書きする__こと。
class sandbox {
public static void main(String[] args) {
Child cld = new Child();
cld.sayComment();
}
}
// Super class.
class Person {
void sayComment() {
System.out.println("I am Person.");
}
}
// Sub class.
class Child extends Person {
@Override
void sayComment() {
System.out.println("I am Child.");
}
}
多態性(ポリモーフィズム)
オーバーロードやオーバーライド、インタフェース(後述)によって、用途によって振る舞いを変えることができること。
抽象クラス
親クラスの用途のみを考えたクラス。したがって、直接インスタンス化することはできない。
class sandbox {
public static void main(String[] args) {
// Compile err.
// Person prson = new Person();
Child chld = new Child();
chld.sayCommentByPerson();
chld.sayCommentByChild();
}
}
abstract class Person {
void sayCommentByPerson() {
System.out.println("I am Person.");
}
}
class Child extends Person {
void sayCommentByChild() {
System.out.println("I am Child.");
}
}
実行結果
I am Person.
I am Child.
インタフェース
抽象クラスをさらに抽象化したもの。インタフェースではメソッドの宣言はできるが、処理は原則書かない。__普通に__処理を書こうとするとコンパイルエラーが起きる。
class sandbox {
public static void main(String[] args) {
Class cls = new Class();
cls.sayComment();
}
}
class Class implements Interface {
public void sayComment() {
System.out.println("I am Class.");
}
}
interface Interface {
void sayComment();
}
また、interface
内のメソッドはpublic
として扱われるため、Class
でinterface
のsayComment()
を使うときは、public
を付けなければならない。また、interface
内のメンバはpublic static final
として扱われる。
interface
内で処理を記述するとき
default
修飾子をつける。
class sandbox {
public static void main(String[] args) {
Class cls = new Class();
cls.sayComment();
}
}
class Class implements Interface {
}
interface Interface {
default void sayComment() {
System.out.println("I am Interface.");
}
}
実行結果
I am Interface.
クラスは複数のinterface
を取り込むことができる
class sandbox {
public static void main(String[] args) {
Class cls = new Class();
cls.sayComment1();
cls.sayComment2();
}
}
class Class implements Interface1, Interface2 {
}
interface Interface1 {
default void sayComment1() {
System.out.println("I am Interface1.");
}
}
interface Interface2 {
default void sayComment2() {
System.out.println("I am Interface2.");
}
}
実行結果
I am Interface1.
I am Interface2.