- 公開日: 2017年12月05日
【初心者向け】Javaクラスの概要から使い方まで徹底解説
Java学習がオブジェクト指向のステージに入ってくると「継承」や「多様性」などやたら複雑な決まりを学ばなければなりませんよね。
気がつけば学習初期には public class ・・・
と決まっていた文句もいろいろな言い方に。
そこで今回は、Java初学者を悩ませる『class(クラス)』の種類と使い方についてまとめてみました。
コードと画像付きなので、今までスッキリ理解できなかった方もこれで理解できるのでは。
【初心者向け】Javaクラスの概要から使い方まで徹底解説
Javaのクラス(class)とは
Javaプログラムの冒頭決まり文句で登場する public class Main
の class
は、「ここからプログラム処理が始まりますよ」という意味を持ちます。
ちなみに class
の後の Main
はファイル名、public
はアクセスレベルを表していますね。
Java学習をはじめたころは、この決まり文句 public class Main
は変わらないのですが、オブジェクト指向の学習段階に入ってくると、この文句が変わってきます。
そこで今回は class
の種類や使い方をご紹介し、Javaのオブジェクト指向の理解をサポートできればと思います。
【基本的な class
の使い方】
ファイル名 Main.java
public class Main{
public static void main(String[] args){
System.out.println("サンプル");
}
}
>> 結果 それではここからオブジェクト指向で登場するクラスについてご紹介していきます。
継承
継承の概要
継承は、Javaに限らずRubyやPHP、Pythonなどオブジェクト指向型プログラミング言語で登場してくる機能です。
継承を使うことで、プロジェクトのスケーラビリティ(拡張性)が容易になり、メンテナンスも楽に。「インタフェース」というかっこいい言葉もこの継承機能の一つになりますので、「継承」理解しておきたいですよね。
継承の特徴(メリット)
- 似たコードのプログラムの量産が楽になる
- プログラムの追加、上書きが楽になる
- 複数人で開発した場合の人的なミスを防げる
- Javaベースのアプリ開発で使う
- オブジェクト指向3大要素の「多様性」を理解する上で必須
参考までに哺乳類の動物を紹介するプログラムを「継承」を使って表現してみます。
【サンプルコード】
今回登場するファイル
- Main.java
- Animal.java
- Lion.java
- Rabbit.java
【Main.java】
public class Main {
public static void main(String[] args) {
Animal animal = new Animal();
Lion li = new Lion();
Rabbit ra = new Rabbit();
System.out.println();
System.out.println("-----------------------");
li.eat();
li.move();
li.sleep();
System.out.println("-----------------------");
ra.eat();
ra.move();
ra.sleep();
}
}
【Animal.java】 ※親クラス
//子クラスの元となるプログラム(親クラス)
public class Animal {
public Animal() {
System.out.println("【新たな動物の登場】");
}
public void eat() {
System.out.println("【食べ方】");
}
public void move() {
System.out.println("【動き方】");
}
public void sleep() {
System.out.println("横になって寝ます");
}
}
【Lion.java】 ※子クラス
//Animalクラスを継承した子クラス
public class Lion extends Animal {
public Lion() {
super();
System.out.println("新しいライオンさんの登場");
}
public void eat() {
System.out.println("ライオンはかぶりついています");
}
public void move() {
System.out.println("ライオンは歩いています");
}
}
【Rabbit.java】 ※子クラス
public class Rabbit extends Animal {
public Rabbit() {
super();
System.out.println("新しいうさぎさんの登場");
}
public void eat() {
System.out.println("うさぎさんはかじっています");
}
public void move() {
System.out.println("うさぎさんは跳ねています");
}
}
>> 結果
親クラスの Animal.java
をもとに、食べ方 eat();
と動き方 move();
は動物毎に違うので上書きプログラム。
寝方は同じなので、子クラスで public void sleep();
を記述せず、親クラスの sleep();
を継承していることが分かります。
実際にプログラムしてみると分かるのですが、親クラスで子クラスに記述してもらいたい項目(メソッド)を決めても、子クラスを作るプログラマがメソッドを忘れてしまうことも考えられます。
このような設計の意図と違ったプログラムを作成した場合でも、コンパイルできプログラムは動きます。 しかし、本来子クラスに記述しなければならないメソッドがないまま稼働しますので、案件によっては大きな被害を被ります。 このリスクを回避するテクニックとして、継承を発展させた「抽象クラス」があります。
抽象クラス
抽象クラスは、「継承」を使って開発を進めるときに用いられるクラスの一つです。 「継承」を使って開発を進めるとき、元のクラス(親クラス)の性格上、子クラスで絶対に定義したい項目が出てくることもあります。
例えば、ゲーム内に登場してくる敵キャラを量産する場合、『攻撃力』は外せない要素ですよね。 しかし、親クラスで『攻撃力』の項目を入れたいものの、敵キャラ毎に攻撃力は違います。 また子クラスの敵キャラで『攻撃力』を設定してくれればいいのですが、プログラマによっては忘れることも。 そんな時に「抽象クラス」が役立ちます。
今回抽象クラスのサンプルとしてご紹介する内容は、一つ前のセクション「継承」でご紹介した動物プログラムの抽象クラス版にします。「動物クラスをたくさん作りたい」と考えた時、親クラスには動物に欠かせない「食べる」「動く」「寝る」を設定。 「食べる」や「動く」といった行動は動物には欠かせませんが、動物毎に違う動きなので子クラスで設定する必要がありますね。
以下に親クラス(Animal.java)と子クラス(Lion)のサンプルをご紹介します。
実際に抽象クラスがうまくいているかどうかは、子クラスの move()
をコメントアウトしてみるとよくわかりますね。
【サンプルコード】
今回登場するファイル
- Main.java
- Animal.java
- Lion.java
- Rabbit.java
【Main.java】
public class Main{
public static void main(String args[]){
Lion li = new Lion();
Rabbit ra = new Rabbit();
li.eat();
li.move();
System.out.println("---------------------");
ra.eat();
ra.move();
System.out.println("-----------------------");
}
}
【Animal.java】 ※親クラス
public abstract class Animal{
abstract void eat();
abstract void move();
}
【Lion.java】 ※子クラス
//子クラス ライオンクラス
public class Lion extends Animal{
public void eat(){
System.out.println("ライオンは肉を食べる");
}
public void move(){
System.out.println("ライオンが獲物を追いかけています");
}
}
【Rabbit.java】 ※子クラス
//子クラス うさぎクラス
public class Rabbit extends Animal{
public void eat(){
System.out.println("うさぎは木の実を食べる");
}
public void move(){
System.out.println("うさぎが木を登ろうとしています");
}
}
>> 結果
>> 抽象クラスの確認
インタフェース
インタフェースは、継承機能の「抽象化」を発展させた機能です。 規模の大きいプロジェクト開発に用いられて、抽象クラスのまとめ役として使われる場面も。 今回は、シンプルなインタフェースを例にご紹介します。
【プログラムの内容】
チェーン展開しているクリーニング店の店舗毎の洗濯時間を、Javaのインタフェースを使って考えてみます。
- 各店舗共通メニューをインタフェースに書く
- 各店舗の洗濯時間は、各店舗プログラムに書く
【サンプルコード】
今回登場するファイル
- Main.java
- CleaningService.java
- KyotoCleaningShop.java
- OsakaCleaningShop.java
【Main.java】
public class Main{
public static void main(String[] args){
System.out.println("京都店のシャツ洗濯時間");
CleaningService k = new KyotoCleaningShop();
System.out.println(k.washShirt());
System.out.println("大阪のシャツ洗濯時間");
CleaningService o = new OsakaCleaningShop();
System.out.println(o.washShirt());
}
}
【CleaningService.java】 ※インタフェース
//インタフェース
public interface CleaningService {
int washShirt();
int washTowl();
int washCoat();
}
【KyotoCleaningShop.java】 ※インタフェースの実装コード
//インタフェースの実装コード
public class KyotoCleaningShop implements CleaningService {
public int washShirt(){
// シャツの洗濯時間10分
return 10;
}
public int washTowl() {
// タオルの洗濯時間
return 5;
}
public int washCoat() {
// コートの洗濯時間
return 30;
}
}
【OsakaCleaningShop.java】 ※インタフェースの実装コード
//インタフェースの実装コード
public class OsakaCleaningShop implements CleaningService {
public int washShirt(){
// シャツの洗濯時間15分
return 15;
}
public int washTowl() {
// タオルの洗濯時間
return 8;
}
public int washCoat() {
// コートの洗濯時間
return 60;
}
}
>> 結果
Main.java
と実行結果からも分かるように、インターフェースの利用で各店舗の機能を一括制御できます。
ただし、新機能を装備する場合は各店舗クラスに追加コード必要です。
今回はシンプルなインタフェースですが、インタフェースは普通の継承では不可能な「多重継承」を使うことができます。 またインタフェースは抽象クラスと似たようなイメージを持ちやすいですが、根本としては以下の図のようにクラス設計が大きく異なります。
ファイナルクラス
ファイナルクラス( final class
)は、「継承」の中で使われるクラスの一つです。
Java学習の最初の方を思い出してみると、final
は、定数宣言でも使われていて消費税率など値を固定したい時に使いました。
ここでご紹介する final class
は、「継承」を使うときに『継承されたくない』『上書きされたくない』時に使用する例です。
クラス宣言に final
をつけると継承禁止、メソッドに final
をつけると上書き禁止になります。
【今回登場するjavaファイル】
- Main.java
- Hero.java
- SuperHero.java
【Main.java】
public class Main{
public static void main(String[] args){
Hero h = new Hero();
SuperHero sh = new SuperHero();
sh.fly();
h.slip();
sh.slip();
h.run();
sh.run();
}
}
【Hero.java】 ※継承の親クラス
//継承 親クラス finalなしのベースコード
public class Hero{
String name;
int hp;
void sleep(){
this.hp = 100;
System.out.println(this.name + "は、寝て回復");
}
void sit(int sec){
this.hp += sec;
System.out.println
(this.name + "は、" + sec + "秒休憩");
System.out.println("HPが" + sec + "ポイント回復");
}
void slip(){
this.hp -= 5;
System.out.println(this.name + "は、こけた");
System.out.println("HP -5");
}
void run(){
System.out.println(this.name + "は、逃げた");
System.out.println("最終HPは" + this.hp + "だったよ");
}
Hero(){
this.hp = 110;
this.name = "たろう";
}
}
【SuperHero.java】 ※継承の子クラス
//継承 子クラス finalなしのベースコード
public class SuperHero extends Hero{
private boolean flying;
public void fly(){
this.hp -= 1;
System.out.println(this.name + "は、飛んだ");
System.out.println("1パワーが減った");
}
//上書き(オーバーライト)
public void run(){
System.out.println(this.name + "も、逃げ出した");
System.out.println("最終HPは" + this.hp + "だったよ");
}
SuperHero(){
this.hp = 500;
this.name = "S・Taro";
}
}
【クラスを継承されたくない場合】
Hero.java の1行目に final
を追記
public final class Hero{
>> 結果
【メソッドを継承されたくない場合】
Hero.javaの20行目に final
を追記
final void run(){
>> 結果
ラッパークラス
Javaでは、基本データ型に対応するクラスを用意していて、それを「ラッパークラス」といいます。 値をオブジェクトとして表現して扱いたい場合に、ラッパークラスを使いますね。
値をオブジェクトとして使う例としてはコレクションクラスが有名で、オブジェクトの集合を対象とするAPIでは基本データ型の値をそのまま使えないため、一度ラッパークラスを使ってオブジェクトにしてから、フレームワークでその値を処理することに。
ラッパークラスは、内部的なクラス処理になるのでチョットイメージしにくいですね。
【サンプルコード】
public class Demo{
public static void main(String[] args){
int i1 = 11;
//ラッパークラスに変更
Integer i2 = Integer.valueOf(i1);
//基本データ型に変更
int i3 = i2.intValue();
}
}
>> 結果
内部クラス(インナークラス)
内部クラスは難しそうな内容の割にはあまり使われないので、最初のうちは参考程度に知っておくといいでしょう。 使われるケースとしては、本格的GUI関数やJavaの資格試験など。オブジェクト指向のカプセル化の要素も絡む項目です。
今回は、基本的な内部クラスの概要をご紹介します。
内部クラスは、ご想像のとおりクラス宣言ブロックの中に更にクラス宣言を書く方法です。
クラスの内部にクラスを定義することで、クラス間の関係を、クラスの継承関係とはまた別に、従属関係,親子関係で表現する事が可能。
また、内部クラスに private
を付けることで、内部クラスの外側クラス(アウタークラス)からしかアクセスできないようにクラスを隠蔽するこもできます。
【今回登場するJavaファイル】
- Main.java
- Outer.java
【Main.java】
public class Main {
public static void main(String args[]) {
// 外部クラスのインスタン化
Outer outer = new Outer();
// 内部クラスにアクセス
outer.display_Inner();
}
}
【Outer.java】
public class Outer {
// インナークラス
private class Inner {
public void print() {
System.out.println("Javaのインナークラスのデモです");
}
}
// インナーにアクセス
void display_Inner() {
Inner inner = new Inner();
inner.print();
}
}
>> 結果 内部クラスは、メンバクラスやローカルクラス、匿名クラスの3種類あると言われますが、最初のイメージとしては「箱の中に箱がある」程度のイメージ、つまり2重の箱程度のイメージでいいと思います。
その他のクラス操作
今回「継承」や「抽象化」など代表的なクラスを紹介させていただきましたが、この他にもクラスには以下のような基本操作が可能です。 参考程度にご紹介させていただきますね。
- 複数のクラスの結合(非オブジェクト指向)
(スッキリわかるJava入門 P226) - クラス型変数
(スッキリわかるJava入門 P314) - フィールドへのクラス型変数宣言
(スッキリわかるJava入門 P340) - メソッドの引数としてクラス型を使用
(スッキリわかるJava入門 P343) - クラス変数(インスタンスの共有)
(スッキリわかるJava入門 P366)
\エンジニア最強言語のJavaスキルが身に付く/
まとめ
今回Javaのクラスを6種類紹介させていただきましたが、どのクラスでも「メソッド」や「フィールド」などJava特有の言葉が登場します。 クラスの中身を理解するだけでも大変なのに「メソッド」や「フィールド」など基本的な言葉も直感的に理解・イメージできなければ、かなりしんどいでしょう。
「Java、そういえば基礎学習も曖昧だな」という方は、CodeCampで理解を深めてみませんか? 現役エンジニアが、あなたのJavaスキルを後押ししますよ。
本稿は、CodeCamp社のJavaコースでも推奨している参考書「スッキリわかるJava入門シリーズ」を元に制作しています。
- この記事を書いた人
- オシママサラ