iT-19-[Java💦Java💦]
復習
クラス(設計図)
・属性→何のデータを持っているのか。
(名前、教科、点数など)
・操作→何の処理ができるか。
(点数を表示する)
このような、クラスから作られる実体(モノ)を、object(オブジェクト)と呼ぶ。
このオブジェクトを中心にプログラムを作っていくことを、オブジェクト指向という。
・メリット
開発効率、保守性、メモリ効率、システム化など!!
・変数、メソッドの定義
class Student{
//メンバ変数(属性)
String name;
int engScore;
int mathScore;
以下はその下に続く
戻り値の型 メソッド名(引数リスト){
(処理)
}
//メソッド(操作)
void display(){
System.out.println(name + "さん");
System.out.println("英語" + engScore + "点・数学" + mathScore + "点");
}
void setScore(int eng, int math){
engScore = eng;
mathScore = math;
}
double getAvg(){
double avg = (engScore + mathScore) / 2.0;
return avg;
}
}
・引数・・呼び出し元から受け取る値のこと。
・戻り値・・メソッドの処理の後に、呼び出しもとに返す値。returnで指定することができる。何も返さない場合は、voidを記述する。
・オブジェクトの使い方
①オブジェクト生成
クラス名 オブジェクト名 = new クラス名();
Student stul = new Student( );
→このように、プログラムにおいて、オブジェクトを作ることを、
インスタンス化という。
②変数・メソッドを利用すること
オブジェクト名.変数名
オブジェクト名.メソッド名(引数)
stul.name = "菅原";
stul.setScore(80,90);
・オーバーロードとは
クラスにない、同じ名前で引数の型や数が違うメソッドを定義すること。
呼び出すメソッドは、名前と因数の組み合わせで決めている。
同じような機能を持つメソッドであっても引数のデータ型が異なれば別々のメソッドを用意する必要がある。
class Student {
void setData(String n){
(中略)
}
void setData(String n, int e, int m){
(中略)
}
main(~){
Student syu = new Student();
stu.setData("菅原");
stu.setData("菅原", 80, 90);
}
・メリット
・プログラム自体がわかりやすくなる。
→同じデータを設定するためのメソッドなので、setDataという同じ名前にした方が、同じような処理をしているのが見た目でわかる。
・名前をつけるのがラクになる
→同じ名前をつけても使えるから。
・メソッド名が変わらないので、とても使いやすい。例えば、printlnメソッドもクラスで使われているので、オーバーロードを使うとすごく便利になる。
・オーバーロードの例
class Student2{
String name;
int engScore;
int mathScore;
void setData(String n){
name = n;
}
void setData(String n, int e, int m){
name = n;
engScore = e;
mathScore = m;
}
void setScore(int e, int m){
engScore = e;
mathScore = m;
}
void display(){
System.out.println(name + "さん");
System.out.println("英語" + engScore + "点・数学" + mathScore + "点");
}
}
class StuSample2{
public static void main(String[] args){
Student2 stu1 = new Student2();
Student2 stu2 = new Student2();
stu1.setData("菅原");
stu1.setScore(90, 80);
stu1.display();
stu2.setData("村山", 75, 100);
stu2.display();
}
}
・コンストラクタ
construction(組み立てる)
オブジェクトの初期化のために使われる特殊なメソッド。
① 名前がクラス名と同じ
② 戻り値を持たない
③ newクラス名(コンストラクタへの引数)
コンストラクタを定義しない場合は、自動でデフォルトコンストラクタ(引数&処理なし)が生成される。
例 Student(){}
class Student{
Student(String n){
}
コンストラクタもメソッドの一つなので、オーバーロードできる。
class Student {
void setData(String n){
(中略)
}
void setData(String n, int e, int m){
(中略)
}
main(~){
Student syu = new Student("管原");
Student syu = new Student("村山", 75, 100);
}
最初、コンストラクタを定義していなかったので、コンパイル時に自動でデフォルトコンストラクタを生成されていた。なので、自分で設定いしてもいいということだ。
生成と同時に値を入れられるので、安全という訳だ。
・staticとは
作ったインスタンスの個数を知る方法は?
class Student{
int counter = 0;
Student(){
counter ++;
}
}
インスタンス内の変数では、むり。
前インスタンスが共通して使える変数が必要!
・static変数
class Student{
static int counter = 0;
Student(){
counter ++;
}
static void display(){
System.out.println(counter + "人です");
}
全インスタンス変数が使えるメンバ変数やメソッドを定義する時には、staticを指定する。
オブジェクトを生成していなくても利用できる。
利用方法
クラス名.変数[メソッド]名と書く。
・全部のインスタンスから共通して使う変数やメソッドを作りたいときに使う。
サンプルコード
class Student4{
String name;
static int counter = 0;
Student4(String n){
name = n;
counter++;
System.out.println(name + "さんをインスタンス化しました");
}
static void display(){
System.out.println(counter + "人です");
}
}
class StuSample4{
public static void main(String[] args){
Student4.display();
Student4 stu1 = new Student4("菅原");
Student4.display();
Student4 stu2 = new Student4("村山");
Student4.display();
}
}
勉強
カプセル化とは
アクセス修飾子でクラス・メンバ変数・メソッドの公開範囲を指定できる
修飾子・・public, protected, (なし), private
同クラス・ ○ ○ ○ ○
同パッケージ ○ ○ ○
サブクラス ○ ○
他 ○
メンバ変数は、隠蔽(private)して、クラスとメソッドは公開(publiv)する設計方針をカプセル化と呼ぶ。
→代入前処理、修正範囲
class Student{
private int score;
public void setScore(int s){
(中略)
score = s;
}
}
○ stu.setScore(80);
× stu.score = 80;
サンプルコード
public class Student5{
private String name;
private int score;
public Student5(String n){
name = n;
}
public void setScore(int s){
if(0 <= s && s <= 100){
score = s;
} else {
System.out.println(name + "さんの点数が範囲外です");
score = 0;
}
}
void display(){
System.out.println(name + "さん:" + score + "点");
}
}
class StuSample5{
public static void main(String[] args){
Student5 stu1 = new Student5("菅原");
stu1.setScore(80);
stu1.display();
Student5 stu2 = new Student5("村山");
stu2.setScore(-50);
// stu2.score = -50;
stu2.display();
}
}
練習問題
breakメソッドが、オーバーロード
同じメソッド名で、引数が違うものがあるので、それを確認する課題だ。
class Car1{
int no;
int speed;
void setNo(int n){
no = n;
}
void run(int s){
speed = s;
}
// brakeメソッドを定義する
void display(){
System.out.println("ナンバー" + no + "の速度は" + speed + "です");
}
}
class DriveCar1{
public static void main(String[] args){
Car1 c1 = new Car1();
c1.setNo(2525);
c1.run(30);
c1.display();
c1.brake(10);
c1.display();
}
}
戻り値の型→void
引数は、speed = speed -sで使用。
class Car1{
int no;
int speed;
void setNo(int n){
no = n;
}
void run(int s){
speed = s;
}
// brakeメソッドを定義する
void brake(){
speed = 0;
}
void break(int s){
speed = speed - s
}
//brakeメソッドを定義できた!
void display(){
System.out.println("ナンバー" + no + "の速度は" + speed + "です");
}
}
class DriveCar1{
public static void main(String[] args){
Car1 c1 = new Car1();
c1.setNo(2525);
c1.run(30);
c1.display();
c1.brake(10);
c1.display();
}
}
コンストラクタが、引数ありなしで宣言。
①コンストラクタを設定
→名前は、クラス名に合わせる。
→戻り値を持たない。
②setNoは削除する
class Car2{
int no;
int speed;
//コンストラクタをここに書けばいい↓
Car2(){
no = 0;
}
Car2(int n){
no = n
}
//ここまでがコンストラクタである。
void run(int s){
speed = s;
}
void brake(){
speed = 0;
}
void brake(int s){
speed = -s;
}
void display(){
System.out.println("ナンバー" + no + "の速度は" + speed + "です");
}
}
class DriveCar2{
public static void main(String[] args){
Car2 c1 = new Car2();
c1.run(30);
c1.display();
Car2 c2 = new Car2(2525);
c2.run(50);
c2.display();
}
}
コンストラクトをどこに設定すればいいかがわからない。
アクセス修飾子
→メンバ変数には、private
→コンストラクタとメソッドには、publicを設定すること。
class Car3{
//メンバ変数にはprivate
private int no;
private int speed;
//コンストラクタにはpublic
public Car3(){
no = 0;
}
public Car3(int n){
no = n;
}
//メソッドには、public
public void run(int s){
speed = s;
}
public void brake(){
speed = 0;
}
public void brake(int s){
speed = speed - s;
}
public void display(){
System.out.println("ナンバー" + no + "の速度は" + speed + "です");
}
}
ただし、↓の8行目のままやってしまうと、コンパイルエラーが出ることになる。
カプセル化のメリットである。
class DriveCar3{
public static void main(String[] args){
Car3 c1 = new Car3();
c1.run(30);
c1.display();
Car3 c2 = new Car3(2525);
c2.speed = 50;
// c2.run(50);
c2.display();
}
}
これを、8行目をコメントアウト、9行目を表示させてみる。
class DriveCar3{
public static void main(String[] args){
Car3 c1 = new Car3();
c1.run(30);
c1.display();
Car3 c2 = new Car3(2525);
//c2.speed = 50;
c2.run(50);
c2.display();
}
}
カプセル化をすることで、
変数への直接代入を禁止させることができる。
これを、代入前処理という。設計図クラスの中で、たとえばif文などを設定しておくことで、間違った値などを入れた時にエラーが出てくれるようにしてくれる。
例えば、100点満点のテストがあった時に、80点を入れれば何も問題はないが、180点を入れてしまった時にカプセル化をしていないとそのまま実行されてしまう。テストは100点なので、その範囲で入れてね〜というエラーを出すことができるようになるということだ。
メソッドのみで値を出すようにすることで、不正な値を減らせるし、ログをとっておける。
先ほどのDriveCar3クラスにて、8行目がc2.speedに直接代入している。
(下の状態ではマズいということです)
もし、メンバ変数にprivateのアクセス修飾子を入れていなかった場合、別のクラスからもこうやって直接アクセスして代入してしまうことができてしまう。なので、メソッドを呼び出すように設計図で決めていても、呼び出す側が.speedで代入できてしまうという状態になってしまっていることがよくないということになる。
これを防げるのが、privateである。
class DriveCar3{
public static void main(String[] args){
Car3 c1 = new Car3();
c1.run(30);
c1.display();
Car3 c2 = new Car3(2525);
c2.speed = 50;
// c2.run(50);
c2.display();
}
}
コンパイルした時点でエラーが出るので、他の開発者にメソッドを経由してねと言葉だけでなく強制させることができる。
もう一つは、修正範囲が狭くてメンテナンスがしやすいという利点がある。
カプセル化をしておくと、Scoreを、mathScoreにしたいとおもったら、
設計図の中だけを修正すればよい。
しかし、.speedみたいに、直接代入を実行用クラスに入れておくと、
実行用クラスも.mathScoreみたいに編集する必要が出てくる。
つまり、一つのクラスを編集すれば変更が可能。
しかし、直接代入を複数のクラスで行ってしまった場合、その全てを変えなくてはいけなくなる。そうすると、メンテナンスが最強に無駄になる。
class Car4{
private int no;
private int count = 0;
public Car4(){
no = 0;
count++;
System.out.println("ナンバーなしを作りました");
}
public Car4(int n){
no = n;
count++;
System.out.println("ナンバー" + no + "を作りました");
}
public void display(){
System.out.println(count + "台作成済です");
}
}
class DriveCar4{
public static void main(String[] args){
Car4 c1 = new Car4();
c1.display();
Car4 c2 = new Car4(2525);
c2.display();
Car4 c3 = new Car4(8888);
c3.display();
}
}
各インスタンスが、共通して使うために、static変数を使う。
データ型の前にstaticを入れる。
displayメソッドの前にもstaticを入れる。
また、
呼び出す側も変わる。
変数名.メソッド
→クラス名.変数名、メソッド名.変数名に変える必要がある。
よって、
///////////////////////////////////変更前
class Car4{
private int no;
private int count = 0;
public Car4(){
no = 0;
count++;
System.out.println("ナンバーなしを作りました");
}
public Car4(int n){
no = n;
count++;
System.out.println("ナンバー" + no + "を作りました");
}
public void display(){
System.out.println(count + "台作成済です");
}
}
///////////////////////////////////変更後
class Car4{
private int no;
private static int count = 0;
public Car4(){
no = 0;
count++;
System.out.println("ナンバーなしを作りました");
}
public Car4(int n){
no = n;
count++;
System.out.println("ナンバー" + no + "を作りました");
}
public static void display(){
System.out.println(count + "台作成済です");
}
}
実行用クラスは、
///////////////////////////////////変更前
class DriveCar4{
public static void main(String[] args){
Car4 c1 = new Car4();
c1.display();
Car4 c2 = new Car4(2525);
c2.display();
Car4 c3 = new Car4(8888);
c3.display();
}
}
///////////////////////////////////変更後
class DriveCar4{
public static void main(String[] args){
Car4 c1 = new Car4();
Car4.display();
Car4 c2 = new Car4(2525);
Car4.display();
Car4 c3 = new Car4(8888);
Car4.display();
}
}
これによって、
これによって、自動車を何台作ったのか(インスタンスどうし)を合計してカウントすることができるようになった!!
すげ〜〜!!
ここまで!!