とりあえず、前提そのものがおかしいです。
他の方も仰っているように、学習順序が違うです。
そもそもプログラミングっていうのは「こう書けばいい」というものではありません。
入門書に載っている内容は基礎の基礎です。
知っていて当たり前のものです。
つまり、基礎をないがしろにして、応用だけやろうとしている状態です。
たとえば、料理をするとして、包丁の使い方すら知らない人が、「この料理をしたいから、やり方を教えろ」と言って来たらどうしますか?
で、よく聞くと、かつら剥きどころか包丁すら使えない。
「包丁の使い方から学んで来い」と言うと、「はぁ??? わかんねーなら答えんなク○が!!!」と逆ギレされるのです。
確かに包丁の使い方ぐらいなら教える事もできます。
でもその「包丁の使い方」に相当する部分が、この道ウン十年でないと出来ないとかだとどうでしょうか?
そういう、基礎をないがしろにする人って、すぐに諦めます。
「んな面倒なことやってられっか!!!」と。
それなのに、「御託はいいからとっとと答えだけ寄こせ!!」って何様のつもりでしょうか。
と思いませんか?
そういう、明らかに他人を見下したやりかたをしているのと同義なんですよ。
仮に教えても、そもそもの基礎知識が欠けているから無駄になる。
なので、まともな回答が付きづらくなるのです。
まずは「Java 入門」とかでググって、調べてください。
ここからは本題です。
これのprotected Student[] students;とpublic StudentList(){}がわかりません。
問題のコードを見ると、
public class StudentList{
protected Student[] students; // <- ここ(*1) と
private int last = 0;
public StudentList(){} // <- ここ(*2)
public StudentList(int studentCount){
this.students = new Student[studentCount];
}
public void add(Student student){
students[last] = student;
last++;
}
public Student getStudentAt(int index){
return students[index];
}
public int getLastNum(){
return last;
}
}
ですね。(*1, *2)
(*1)は「フィールド」と言います。
(*2)は「コンストラクタ」と言います。
そもそも、オブジェクト指向というのは、「クラスを組んだからオブジェクト指向」…ではありません。
オブジェクト指向(以下OOP)は、「データ(= フィールド) と処理(= メソッド) をひとまとめにしたオブジェクト」なるものを中心に見る発想法です。
C言語とかのような、OOP以前の言語だと、データと処理(C言語だと関数と呼ばれるが)は別物でした。
それをデータと処理、つまりJavaでいえばフィールドとメソッドをひとまとめにすることで管理をしやすくするのです。
たとえば、Stringクラス。
この オブジェクト s は、データである "Hello" を持っています。
で、このsが "Hello"というデータを保持し、管理をします。
フィールドとメソッドをひとまとめにすることで、「オブジェクトだけが対象データと処理方法を知っている」状態にできます。
これにより、呼び出し側(mainメソッドとか)は、「sさん、一番目のデータを下さいな」と依頼するだけで、処理されます。
Stringという型によって、sは自分が管理するデータや処理方法(メソッド)を知っているため、
System.out.printlnメソッドみたいに、呼び出し側は「どういう実装なのか」を意識することなく、
処理の概要と引数、戻り値だけを集中していればいいのです。
そして、デザインパターンのStrategyパターンのようにオブジェクトを切り替えるだけでいい……みたいな感じでできます。
そして、クラスはそのオブジェクトの担当区域を定義しているだけです。
コンパイラとかに「こういうデータ構造があるので、よろしくね~」と教えてあげるだけです。
そのため、単に定義しただけでは動きません。動かせません。
なのでインスタンス化と呼ばれる処理をします。オブジェクトを生成するのです。
で、コンストラクタはそのオブジェクトを生成するときに動くものです。
Test1 test1 = new Test1( 100 );
みたいにすると、int型(おそらく)の引数を受けるコンストラクタ Test1( int n ) が動きます。
コンストラクタの役割は『フィールドの初期化や前処理』です。
ただ、今回のような処理自体が空の場合もありますね。
今回のコードで、もし空のコンストラクタを定義しない場合、
StudentList sl = new StudentList();
みたいな、引数無しのインスタンス化ができません。それをできるようにするために、引数無しのコンストラクタを用意する事があります。
ただ、今回のコードだと、引数無しの方を呼ぶとフィールドである student がインスタンス化されていないので、いわゆるヌルポが発生するはずです。
それならのprotected Student[] =new Student;となるのではないでしょうか?
一応、Javaではフィールドをコンストラクタ等以外でそのまま初期化する事はできるようですが、
今回の場合、int型引数を一つ受け取る方のコンストラクタ内で要素数を指定して初期化しています。
もし
protected Student[] student = new Student[10];
とかみたいにやると、配列なので要素数を変動させることができません。要素数10としたら、10個しかはいりません。
10 -> 12 とかにする場合、つまり追加や削除をする場合、別の配列を用意してそこにコピーして挿げ替えないといけません。
ヒント: 配列のサイズ変更について
なので、直接やるのではなく、コンストラクタで要素数を決めています。
完全固定なら質問者さんが思うようにやってもいいです。(書き方は間違っているが)
またpublic StudentList(){}というこの空のメソッドは何なのでしょうか?
上で述べた通り、引数無しのコンストラクタです。
つまり、「基礎からやりましょう」です。
基礎をやるのは面倒ですね。でもそれをないがしろにしても、必要になるのでどうしてもやらないといけません。
そうなると通常の工程までストップしてしまいます。
まずは基礎からやりましょう。