Hi all,

I've been doing some reading about calling a non static variable or method
from a static context, and almost but not quite have my head around what exactly is going on. I've read the text but can't seem to put that into context, so please bare with me.

I'm doing a program to simulate a student enrolment system (Unique huh!)
I have most of the functionality that I need, with exception to searching the array to
match based on an attribute but that I will work on later.

The project has a hard coded array of students which is then used to
search through for a matching year started at the place of study.
I'm having problem with my printEnrolment() method from my Enrolment class,
I used the addStudent() method in Enrolment to add the students to the array
using the Student constructor, and that works without drama.
I then put all of the information into a readable format using printDetails()
which returns a String which I then want to use in the printEnrolment() method under the Enrolment class, which is where I get the dreaded non static error.

Now from what I can tell, I somehow need to create an instance of the printDetails() method so that I can call it from the static printEnrolment() method, but i'm not quite sure as to how I should approach that.

Will my printEnrollment() method not work until I implement the search function?
Like, create a temp Student in the array to compare values against the array?
Is creating a temp student even the best way to achieve this?

Any advice to point me in the right direction would be very much appreciated!

Code below - Error line 23 of Enrolment

public class enrolment
{
	
	public static void addStudent()
	{
	        //Create objects of Student class
        Student[] unistudent = new Student[6];
		unistudent[0] = new Student("Al", "Capone", "Male", 12345671, "0419817271", 2006);
		unistudent[1] = new Student("Bob", "Builder", "Male", 12345672, "0419817271", 2007);
		unistudent[2] = new Student("Carol", "Candlelight", "Female", 12345673, "0419817271", 2007);
		unistudent[3] = new Student("Dirk", "Diggler", "Male", 12345674, "0419817271", 2007);
		unistudent[4] = new Student("Ebony", "Star", "Female", 12345675, "0419817271", 2008);
	}
	
	public void getStudent()
	{
		// Used for searchStudent() in main
	}
	
	public static void printEnrolment()
	{
		String details = Student.printDetails();  // <----- ERROR IS HERE
		System.out.println(details);
	}
	
}
class Student
{
    private String firstName, lastName, gender, phoneNumber, details;
    private int studentID,yearStarted;
    
   
    public Student(String firstName, String lastName, String gender, 
				   int studentID, String phoneNumber, int yearStarted)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.gender = gender;
        this.studentID = studentID;
        this.yearStarted = yearStarted;
        this.phoneNumber = phoneNumber;
    }
   
    private String getFirstName()
    {
        return this.firstName;
    }
   
    private String getLastName()
    {
        return this.lastName;
    }
    
    private String getGender()
    {
        return this.gender;
    }
    
    private String getPhoneNumber()
    {
		return this.phoneNumber;
	}
    
    private int getStudentID()
    {
        return this.studentID;
    }
    
    private int getYearStarted()
    {
        return this.yearStarted;
    }
   
    public String printDetails()
	{
             String details = ("First Name: " + getFirstName() + "\nLast Name: " +getLastName() +
							   "\nStudent ID: " + getStudentID() + "\nGender: " + getGender() +
							   "\nPhone No: " + getPhoneNumber() + "\nYear Started: " + getYearStarted() +"\n\n");
			return this.details;
    }
}
public class admin
{

    public static void main(String args[])
    {
		fillData();
    }
    
    public static void fillData()
    {
		enrolment.addStudent();
		enrolment.printEnrolment();
	}
	
	public void searchStudent()
	{
		// Not yet started
	}
}
Student.printDetails();

printDetails is an instance method that prints the details of a single Student. It only makes sense when you call it for a single Student. You are trying to call it using the class Student, so Java doesn't know which Student you want to print the details of.

I somehow need to create an instance of the printDetails() method s

No. you can't create an instance of a method, you can only create an instance of a class. In this case printDetails is an instance method so you MUST have an instance of a Student object on which to call it. Your Enrolment class currently has 6 Students - so which one did you want to print?

ps: The Enrolment class needs some more work anyway - it has no variables! The Student array you create in addStudent is just local to that method and will disappear when the method finishes. And why does a method called addStudent add six Students? How many Students does one Enrolment involve? You need to go back to the specifications, and re-think this class.

G'day James,

Thanks (again) for your quick response!
I think I know what you mean about creating an instance of a class
hence creating student from the constructor right?

In terms of enrolment having variables, I was hoping that the only
variable I would need would be the String details which it could (somehow)
get from Student?

The project has guidelines on roughly what each method should do
I'll copy the info , I must have misunderstood something?

Details of the methods:
Method
1
Method Name Description
printDetails() This method summarizes and returns (but does not print) the
student data members in a reader friendly manner. It should return
the summarized information as a string.

2
addStudent()
Adds new students to the enrolment array; you can hardcode these
students, in other words you don’t have to ask for a user input.

3
getStudent()
Retrieves a student from the enrolment given its index (index of
array)

4
printEnrolment()
It calls the printDetails() method to return and print the details on
the command prompt.

5
fillData()
This method must be present inside the driver class and should be
called by the main method. This method:
1. Creates an enrolment list using the addStudent() method
2. Prints the details of the student using the printEnrolment()
method

6
searchStudent()
This method must ask the user for input on the command line. The
user enters a commencing year and the method searches for the
students in the Enrolment array. If there are no matching students,
a message is displayed stating that no matching students have
been found and the user is asked again to enter a commencing
year. Any matching students, if found, are listed with ALL their
details. You may want to make use of the printDetails() method to
prepare for printing these details.

Sorry I should have added

Admin - fillData() , searchStudent()

Enrolment - addStudent(), getStudent(), printEnrolment()

Student - Constuctor, printDetails()

OK, that's not quite how I would do an enrolment system, but hey-ho.
I think point 4 should really say
4
printEnrolment()
It calls the printDetails() method for each Studentto return and print the details on the command prompt.

Anyway, I think you have enough to keep going with for a while now...

I get you now James, thanks for taking the time to explain it to me,
I'm thinking along the lines of whilst doing a search, sending the array student into the student constructor to populate the variables in the student class, then use printDetails() for each student that is sent (based on whatever condition that is met).
so that the variables are already populated from the constructor and it will have information to send over to printEnrolment() under Enrolment.

Does this sound like i'm on the right line of thinking?

Thanks in advance :)

sending an array of 'students' into the 'student' constructor? no, not really.

your student class should be built to deal with a certain student. besides, how can you have an array of 'students', before you actually have 'student's'?

use the student constructor to create a new student, by giving it the information of oneparticular student, and store the new students in an array of Student objects (not in the Student class) in either an array or a list.

^ like Stultuske says.
As I understand your assignment (ie not very well!) the array of Student objects belongs in the Enrollment.

Programming languages are very precise things; you can't mis-use terminology or expect the compiler to "understand what I really meant". The same applies when you talk about programming in these posts, which is why S. rightly picked you up on your sending an array of students to the student constructor. Be very careful that what you write is exactly what you mean.

Thank you both for your replies, that makes perfect sense,
I didn't think about it properly before I typed sorry about that.

I have done quite some work to the assignment with help from the guidance received here and I think I am much closer to having it licked.
But, alas I still haven't quite grasped calling the printDetails() under Student.

I have updated my code below, all I need to do now is when there is a match in my for loop (under enrolment), to have it print the details of the match instead of a system.out "match"

To do this the assignment wants me to call printEnrolment() under Enrolment which in turn calls printDetails() in the Student class.

However because I still haven't quite got the concept for calling the non-static method in my head (I thought I had it :/ ) I can't get it to do that?

Could either of you please take a look, any push in the right direction would
sincerely be appreciated!

Admin (Driver Class)

import java.util.*;
public class admin
{
	public static Student[] unistudent = new Student[5];
	public static Scanner input = new Scanner(System.in);
	public static int yearToSearch;
	
    public static void main(String args[])
    {
		fillData();			
		searchStudent();
		enrolment.getStudent();
    }
    
    public static void fillData()
    {
		enrolment.addStudent();	
	}
	
	public static int searchStudent()
	{
		System.out.print("Please enter year to search  >> ");
		yearToSearch = input.nextInt();
		return yearToSearch;
	}
}

Student

class Student
{
    private String firstName, lastName, gender, phoneNumber, details;
    private int studentID,yearStarted;
    
   
    public Student(String firstName, String lastName, String gender, 
				   int studentID, String phoneNumber, int yearStarted)
    {
        this.firstName = firstName;
        this.lastName = lastName;
        this.gender = gender;
        this.studentID = studentID;
        this.yearStarted = yearStarted;
        this.phoneNumber = phoneNumber;
    }
   
    private String getFirstName()
    {
        return this.firstName;
    }
   
    private String getLastName()
    {
        return this.lastName;
    }
    
    private String getGender()
    {
        return this.gender;
    }
    
    private String getPhoneNumber()
    {
		return this.phoneNumber;
	}
    
    private int getStudentID()
    {
        return this.studentID;
    }
    
    public int getYearStarted()
    {
        return this.yearStarted;
    }
   
    public String printDetails()
	{
             String details = ("First Name: " + getFirstName() + "\nLast Name: " +getLastName() +
							   "\nStudent ID: " + getStudentID() + "\nGender: " + getGender() +
							   "\nPhone No: " + getPhoneNumber() + "\nYear Started: " + getYearStarted() +"\n\n");
			return this.details;
    }
}

Enrolment

import java.util.*;

public class enrolment
{
	public static Scanner input = new Scanner(System.in);	
	
	public static void addStudent()
	{
	    //Create objects of Student class
        
		admin.unistudent[0] = new Student("Al", "Capone", "Male", 12345671, "0419817271", 2006);
		admin.unistudent[1] = new Student("Bob", "Builder", "Male", 12345672, "0419817271", 2007);
		admin.unistudent[2] = new Student("Carol", "Candlelight", "Female", 12345673, "0419817271", 2007);
		admin.unistudent[3] = new Student("Dirk", "Diggler", "Male", 12345674, "0419817271", 2007);
		admin.unistudent[4] = new Student("Ebony", "Star", "Female", 12345675, "0419817271", 2008);
	}
	
	public static void getStudent()
	{
		int match = 0;
		System.out.println("");
		
		for (int i = 0; i < admin.unistudent.length; i++)
		{
			if (admin.yearToSearch == admin.unistudent[i].getYearStarted())
			{
				match++;
				System.out.println("Found a match");
			}
			else
			{
				System.out.println("No Match");
			}
		}
			
		if (match == 0)
		{
			System.out.print("\nSorry, no Match Found: Would you like to search again?\n1: Yes\n2: No/Quit\nEnter Choice  >>  ");
			int searchAgain = input.nextInt();
			if (searchAgain == 1)
			{
				admin.searchStudent();
				getStudent();
			}
			else if (searchAgain == 2)
			{
				System.exit(0);
			}
		}
	}
	
	public void printEnrolment()
	{
		
	}
	
}

I also wanted to ask is it a bad idea to create the array in Enrolment but store it in the Admin class?

Many thanks :)

Edit: No compile errors, but only because I removed the lines to call the printEnrolment() and printDetails()

I also wanted to ask is it a bad idea to create the array in Enrolment but store it in the Admin class?

It depends. If there is only one instance of Admin, and only one instance of Enrolment then it probably makes no difference. If you have (eg) one Admin but multiple Enrolments the each Enrolment would have its own array of Students. At a guess I would say put the array in Enrolment and give it a public accessor method so Admin can access it.

calling printDetails for one or more Students:
This is a lot simpler than you realise. All you need is a variable that refers to one student, then use that for the call, as in:

Student s = ... something
s.printDetails();

that variable can, of course, be an element from an array of Students, as in:

Student[] sa = new Student[99];
sa[0] = new Student(...
...
sa[0].printDetails();

or, if it's inside a loop

for (int i ...
   sa[i].printDetails();

Just use these concepts in your own code.

That is perfect, I've written all of those down, it seems so simple
given that i already have a printDetails() method ! Thankyou

printDetails() is non-static as it is to do with each instance of Student,
that I have read and understood about static/non static.

printEnrollment() therefore should also be non static method, is that correct?
As it should only print when each instance of student is called and matched by the year they enrolled? If this is the case, I'm not sure how to then get printDetails() to talk to printEnrolment() and then lastly, how to call printEnrolment() as it would be called from a static variable within Enrolment (within the loop) ?

I must have flawed logic here somewhere, any ideas?
Again I do really appreciate the help, I am learning as we go!

Re static in Enrolment and Admin:
You decide whether to use static or not by asking "how many of these are there?". eg the name field in Student has one value for each Student, so it must be an instance variable, not static. eg In the Admin class you have a Scanner; there will only ever be one Scanner which everything will share, so that's static.

It seems you have exactly one Admin and one Enrolment. If so there are two ways to code them. (1) make everything in those classes static and refer to them via the class name or (2) create one instance of Admin and one instance of Enrolment, have everything non-static, and refer to them via the instances.
"Best practice" is option (2), and this is how an experienced developer would normally do it. (The main reason is that sooner or later someone will want more than one instance.) However, it does introduce a bit more complexity, and you do already have that stuff defined as static, so I suggest you leave them as they are and refer to the static methods and variables via the class name.

Selective print by year: you have an instance method in Student that returns the year that student enrolled, so you can call that for each student to compare the year, something like this:

for (int i ....
   if (sa[i].getYearStarted() == searchYear) sa[i].printDetails();

Oh that makes it a lot more clear, I think you should write a book James,
textbooks don't explain it as easy as that!
I've managed to get the printDetails() method to be called through the if loop

The assignment basically said that printDetails() (Student) shouldn't print the info to the console, just format it, so it could send it to printEnrolment() (Enrolment) but that would mean I would have to make all of my methods non static, and create instance(s) of enrolment for the variable to be passed.

Which means I either need to make everything non static for that to occur,
or I'll HAVE to print details to Console from the Student Instance

Is that correct?

You may be getting confused by the use of the words "send it to". That should be "return it to" - ie the formatted string is returned from the printDetails method when it is called from within printEnrolment. printDetails doesn't have to call or refer to anything other than its own Student instance variables.
printEnrolment just has to go something like this:

for (int i...
   String studentDetails = sa[i].printDetails(); // get the details for this student
   System.out.println(studentDetails); // ... and print them on the console

Yes you are right, I have now completed I think all of the code , the methods all talk to each other as they should (For loop sends variable i into printEnrolment(int i) ) so to use with your idea, creating a string from the array.printDetails() was the step that I was missing, thank you for all your great help so far James.

I only have one (hopefully) small problem now.

Whenever it finds a match based on the year, it prints out null, and I'm not quite sure why :/
There must be a logic error with my methods somewhere, could you please do me one last huge favour and check over my code changes to see what could be causing the breakdown in the methods?

Thankyou so much in advance!

(Student and admin haven't changed)


ENROLMENT

import java.util.*;

public class enrolment
{
	public static Student[] unistudent = new Student[5];
	public static Scanner input = new Scanner(System.in);	
	public static void addStudent()
	{
	    //Create objects of Student class
        
		unistudent[0] = new Student("Al", "Capone", "Male", 12345671, "0419817271", 2006);
		unistudent[1] = new Student("Bob", "Builder", "Male", 12345672, "0419817271", 2007);
		unistudent[2] = new Student("Carol", "Candlelight", "Female", 12345673, "0419817271", 2007);
		unistudent[3] = new Student("Dirk", "Diggler", "Male", 12345674, "0419817271", 2007);
		unistudent[4] = new Student("Ebony", "Star", "Female", 12345675, "0419817271", 2008);
	}
	
	public static void getStudent()
	{
		int match = 0;
		System.out.println("");
		
		for (int i = 0; i < unistudent.length; i++)
		{
			if (admin.yearToSearch == unistudent[i].getYearStarted())
			{
				match++;
				printEnrolment(i);
			}
			else
			{
				System.out.println("No Match");
			}
		}
			
		if (match == 0)
		{
			System.out.print("\nSorry, no Match Found: Would you like to search again?\n1: Yes\n2: No/Quit\nEnter Choice  >>  ");
			int searchAgain = input.nextInt();
			if (searchAgain == 1)
			{
				admin.searchStudent();
				getStudent();
			}
			else if (searchAgain == 2)
			{
				System.exit(0);
			}
		}
	}
	
	public static void printEnrolment(int i)
	{
		String studentDetails = unistudent[i].printDetails();
		System.out.println(studentDetails);
	}
	
}

edit: double post

Faced with a bug like this you should put lots of print statements into your code to check (a) if it is executing the code you expected for the expected number of times and (b) to check that the variables have the values you expected.
99 times out of 100 this process will let to home in on exactly where the problem is.

In this case it's printing when it should be printing, but its not printing what it should be printing -so the overall flow of the logic is OK, but there's something wrong with the values being assigned to the variables - in this case the value being returned from unistudent.printDetails() is null when it should be a long String. So that's where the problem is.
Have a closer look at printDetails; try printing the values inside that method to see where they go wrong. I'm not going to tell you the answer until you've had a really good go at solving it yourself!

Touche, good point James, I shall work on it again and do my best, and hopefully let you know it's completed, and then mark it solved.

Fingers crossed!

Thank you so much again :)

I'm happy to report that I have solved the issue!
I removed returning the this.details from printDetails() as each time it is called it is a new instance and doesn't require a this.details to be returned.

Secondly, I used printEnrolment to send int i into printDetails() so that it knew WHICH student to print! It all makes so much more sense now that it's done...

With both of those steps taken I now have a fully functioning system as intended.

I really appreciate the expert guidance :)

Marked as solved, thankyou!

- Nate


edit: to clarify, I simply removed the this. , the printDetails() still returns the "details" String.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.