ΕΙΣΑΓΩΓΗ
Στο σημερινό δωρεάν μάθημα Java, θα αναλύσουμε τους τρόπους με τους
οποίους η Java
χρησιμοποιεί την λέξη κλειδί static. Θα ξεκινήσουμε πρώτα με την ανάλυση της θεωρίας
και μετά θα δούμε παραδείγματα στα οποία χρησιμοποιούνται static fields, static methods και static initializers.
Όπως ήδη έχουμε αναφέρει
σε προηγούμενα δωρεάν μαθήματα Java, όταν δημιουργούμε μεταβλητές ή
μεθόδους σε μια κλάση, αυτά τα στοιχεία δεν ανήκουν στην κλάση αλλά στο
αντικείμενο και σε κάθε αντικείμενο που πρόκειται να δημιουργηθεί από αυτή την
κλάση. Για αυτό άλλωστε και δεν έχει νόημα να θέτουμε αρχικές τιμές σε αυτές
τις μεταβλητές, γιατί όλα τα αντικείμενα που θα δημιουργηθούν θα έχουν λάβει
την ίδια τιμή για την συγκεκριμένη μεταβλητή ή μεταβλητές. Μερικές φορές όμως μας
είναι επιθυμητό μια μεταβλητή ή μια μέθοδο να μην ανήκει στο αντικείμενο αλλά
να ανήκει στην ίδια την κλάση. Δηλαδή να έχει έναν global ρόλο
μεταβλητής ή μεθόδου. Αυτό σημαίνει ότι δεν θα χρειάζεται να δημιουργήσουμε
αντικείμενο (αφού ανήκουν στην κλάση) αλλά θα μπορούμε άμεσα να τα καλέσουμε
και να τα χρησιμοποιήσουμε. Εδώ βασικά φαίνεται τώρα και ο διαχωρισμός που
γίνεται όταν αναφερόμαστε σε static και non-static. Όταν
έχουμε non-static μεταβλητές
ή μεθόδους, επίσημα αυτά στην γενική τους μορφή ονομάζονται instance members. Ενώ οι
μεταβλητές και οι μέθοδοι που είναι static (δηλαδή
ανήκουν στην κλάση) ονομάζονται class members.
Τώρα αν απορείτε γιατί
μαθαίνουμε μια τέτοια θεωρία ενώ υπάρχουν άλλα πιο σημαντικά θέματα να μάθουμε,
η απάντηση είναι απλή – γιατί την χρησιμοποιεί η ίδια η java ακόμα και
στις πιο απλές βιβλιοθήκες. Μάλιστα την λογική αυτή την έχετε χρησιμοποιήσει
πολλαπλές φορές μέχρι τώρα χωρίς να το έχετε καταλάβετε.
Ας πάρουμε για
παράδειγμα την κλάση EmployeeDemo που είχαμε δημιουργήσει σε
προηγούμενο δωρεάν μάθημα Java.
EmployeeDemo.java
package com.example;
public class EmployeeDemo{
public static void main(String[]args){
Employee michail= new Employee("Michail",20000,"Development");
System.out.println("Thank you for registering the employee "+michail.getName());
}
}
Στο παραπάνω πρόγραμμα,
συναντάμε την λογική του static στον ορισμό της main( ) μεθόδου. Ο συγκεκριμένος ορισμός
δίνει τη δυνατότητα στο JVM περιβάλλον να καλέσει την μέθοδο main( ) και να
ξεκινήσει η εκτέλεση του προγράμματος χωρίς να είναι απαραίτητο να δημιουργηθεί
πρώτα ένα αντικείμενο από την κλάση EmployeeDemo.
Στο ίδιο πρόγραμμα,
χρησιμοποιούμε την λογική static, χωρίς να είναι άμεσα ορατή όταν
καλούμε την println( ) μέθοδο αφού την καλούμε χωρίς
πρώτα να έχουμε δημιουργήσει κάποιο αντικείμενο. Καλούμε απλά μια static κλάση που
ονομάζεται System η οποία εσωτερικά δημιουργεί ένα
αντικείμενο out είδος PrintStream στο οποίο ανήκει η μέθοδος println( ).
Θα ξεκινήσουμε την
θεωρία μας πρώτα από τα static fields. Θα
χρησιμοποιήσουμε το παράδειγμα του Employee, που έχουμε ήδη αναλύσει πολλαπλές
φορές σε προηγούμενα δωρεάν μαθήματα Java. Ο καινούργιος κώδικας, στον οποίο
έχει προστεθεί η static μεταβλητή, είναι ο εξής:
Employee.java
package com.example;
class Employee {
private String name;
private int AFM;
private double salary;
private String department;
private int remainingDays;
private int employeeId;
public static int counter;
public Employee(String name, double salary, String department) {
System.out.println("Constructing an Employee");
this.name = name;
this.salary = salary;
this.department = department;
this.employeeId = ++counter;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAFM() {
return AFM;
}
public void setAFM(int AFM) {
this.AFM = AFM;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getRemainingDays() {
return remainingDays;
}
public void setRemainingDays(int remainingDays) {
this.remainingDays = remainingDays;
}
public void mailCheck() {
System.out.println("Mailing a check to " + this.name);
}
public double payment() {
return this.salary / 52.0;
}
public void vacationCalc(int daysTotal, int daysRequested) {
this.remainingDays = daysTotal - daysRequested;
System.out.println("You have requested " + daysRequested + " days of vacation");
}
}
Στην κλάση Employee έχουμε προσθέσει μια static μεταβλητή (static field) που ονομάζεται counter.
Κάθε φορά που
δημιουργούμε ένα αντικείμενο είδος Employee ,μέσα από τον constructor που έχουμε
εμείς δημιουργήσει, αυξάνεται η τιμή του counter κατά ένα
και αναθέτουμε την τιμή στην employeeId του αντικειμένου που δημιουργήσαμε.
Κάθε αντικείμενο που δημιουργείται θα καλεί την ίδια static μεταβλητή
και για όσο τρέχει το πρόγραμμα μας, η μεταβλητή αυτή θα διατηρεί την τιμή της.
Το υπόλοιπο πρόγραμμα αποτελείται από getter και setter μεθόδους οι
οποίες μας είναι απαραίτητες για να έχουμε πρόσβαση στις private instance μεταβλητές.
Υπάρχει επίσης η vacationCalc( ) μέθοδος την οποία χρησιμοποιούμε
για να μάθουμε πόσες μέρες διακοπών μας έχουν απομείνει.
Το ενδιαφέρον σημείο του
κώδικα είναι στην EmployeeDemo μέσα από την οποία δημιουργούμε τα
αντικείμενα είδος Employee. Ας δούμε τον κώδικα, και θα
αναλύσουμε την θεωρία αμέσως μετά.
EmployeeDemo.java
package com.example;
public class EmployeeDemo {
public static void main(String[] args) {
Employee.counter = 100;
Employee michail = new Employee("Michail", 20000, "Development");
System.out.println(michail.getName() + ", your new employee id is: " + Employee.counter);
Employee john = new Employee("John", 30000, "HR");
System.out.println(john.getName() + ", your new employee id is: " + Employee.counter);
}
}
Output
Constructing an Employee
Michail, your new employee id is:
101
Constructing an Employee
John, your new employee id is:
102
Όπως ήδη έχουμε
αναφέρει, μια static μεταβλητή δεν ανήκει σε κάποιο
αντικείμενο αλλά στην ίδια την κλάση. Για να αποκτήσουμε πρόσβαση στην
μεταβλητή λοιπόν και να τις αναθέσουμε μια αρχική τιμή δεν έχουμε παρά να
καλέσουμε το όνομα της κλάσης, τελεία, και το όνομα της μεταβλητής.
Employee.counter = 100;
Η μεταβλητή αυτή, λόγω
της static ιδιότητας
της, θεωρείστε την σαν ένα είδος global μεταβλητής. Κάθε φορά που
δημιουργούμε ένα καινούργιο αντικείμενο, επηρεάζουμε, δια μέσω του constructor, και την
τιμή του counter. Αρχικοποιήσαμε λοιπόν την
μεταβλητή counter στην τιμή 100, και αφού
δημιουργήσαμε δύο αντικείμενα, η τιμή του counter αυξήθηκε
κατά δύο.
Έχουμε επίσης την
δυνατότητα να ορίσουμε και μια static μέθοδο (static method). Η λογική
κάτω από την οποία λειτουργεί είναι ακριβώς η ίδια όπως με την μεταβλητή. Όμως
υπάρχει ένας πολύ αυστηρός περιορισμός – μια static μέθοδο
μπορεί να καλέσει μόνο static μεταβλητές. Αν προσπαθήσετε να
καλέσετε μια instance μεταβλητή μέσα από μια static μέθοδο o compiler της java θα σας
επιστρέψει λάθος. Ας προσθέσουμε λοιπόν μια static μέθοδο στην
Employee κλάση, η
οποία μέθοδο θα επιστρέφει την τιμή του static counter.
Employee.Java
package com.example;
class Employee {
private String name;
private int AFM;
private double salary;
private String department;
private int remainingDays;
private int employeeId;
public static int counter;
public Employee(String name, double salary, String department) {
System.out.println("Constructing an Employee");
this.name = name;
this.salary = salary;
this.department = department;
this.employeeId = ++counter;
}
public static int getCounter() {
System.out.println("Inside getCounter");
return counter;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAFM() {
return AFM;
}
public void setAFM(int AFM) {
this.AFM = AFM;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getRemainingDays() {
return remainingDays;
}
public void setRemainingDays(int remainingDays) {
this.remainingDays = remainingDays;
}
public void mailCheck() {
System.out.println("Mailing a check to " + this.name);
}
public double payment() {
return this.salary / 52.0;
}
public void vacationCalc(int daysTotal, int daysRequested) {
this.remainingDays = daysTotal - daysRequested;
System.out.println("You have requested " + daysRequested + " days of vacation");
}
}
Τώρα στην EmployeeDemo κλάση
μπορούμε να δούμε την τιμή της counter καλώντας την static μέθοδο getCounter( ).
EmployeeDemo.java
package com.example;
public class EmployeeDemo {
public static void main(String[] args) {
Employee.counter = 100;
Employee michail = new Employee("Michail", 20000, "Development");
System.out.println(michail.getName() + ", your new employee id is: " + Employee.getCounter());
Employee john = new Employee("John", 30000, "HR");
System.out.println(john.getName() + ", your new employee id is: " + Employee.getCounter());
}
}
Output
Constructing an Employee
Inside getCounter
Michail, your new employee id is:
101
Constructing an Employee
Inside getCounter
John, your new employee id is:
102
Η χρήση της λέξης static δεν
σταματάει όμως εδώ. Μπορούμε να χρησιμοποιήσουμε την λέξη static σε
συνδυασμό με τα αντικείμενα έτσι ώστε να τρέξουμε κάποια tasks πριν
δημιουργηθεί το αντικείμενο. Αυτό το είδος χρήσης του static ονομάζεται static initializer και ο τρόπος
που το γράφουμε είναι να γράψουμε την λέξη static και μέσα σε
άγκιστρα ( { } ) να γράψουμε τον κώδικα που θέλουμε να εκτελεστεί πριν
δημιουργηθεί το αντικείμενο. Ας προσθέσουμε στην κλάση Employee και έναν static initializer. Ο κώδικας του είναι πολύ απλός
απλά για να δείξουμε ότι εκτελείται πριν την δημιουργία του αντικειμένου.
Employee.java
package com.example;
class Employee {
private String name;
private int AFM;
private double salary;
private String department;
private int remainingDays;
private int employeeId;
public static int counter;
public Employee(String name, double salary, String department) {
System.out.println("Constructing an Employee");
this.name = name;
this.salary = salary;
this.department = department;
this.employeeId = ++counter;
}
static {
System.out.println("Static initializer running before object creation");
}
public static int getCounter() {
System.out.println("Inside getCounter");
return counter;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAFM() {
return AFM;
}
public void setAFM(int AFM) {
this.AFM = AFM;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getRemainingDays() {
return remainingDays;
}
public void setRemainingDays(int remainingDays) {
this.remainingDays = remainingDays;
}
public void mailCheck() {
System.out.println("Mailing a check to " + this.name);
}
public double payment() {
return this.salary / 52.0;
}
public void vacationCalc(int daysTotal, int daysRequested) {
this.remainingDays = daysTotal - daysRequested;
System.out.println("You have requested " + daysRequested + " days of vacation");
}
}
EmployeeDemo.java
package com.example;
public class EmployeeDemo {
public static void main(String[] args) {
Employee.counter = 100;
Employee michail = new Employee("Michail", 20000, "Development");
System.out.println(michail.getName() + ", your new employee id is: " + Employee.getCounter());
Employee john = new Employee("John", 30000, "HR");
System.out.println(john.getName() + ", your new employee id is: " + Employee.getCounter());
}
}
Output
Static initializer running before
object creation
Constructing an Employee
Inside getCounter
Michail, your new employee id is:
101
Constructing an Employee
Inside getCounter
John, your new employee id is:
102
Όπως παρατηρείτε στο output, πριν
δημιουργηθεί το πρώτο αντικείμενο, έτρεξε πρώτα ο static initializer. Όμως
έτρεξε μια φορά, για το πρώτο αντικείμενο. Αν και είναι πολύ χρήσιμη μια τέτοια
ιδιότητα, θα ήταν ακόμα πιο χρησιμότερη αν έτρεχε για κάθε αντικείμενο που
δημιουργούσαμε. Αυτό είναι πολύ εύκολο να γίνει – αφαιρούμε απλά την λέξη static και
αφήνουμε μόνο τα άγκιστρα. Ας δούμε τώρα πως αλλάζει ο κώδικας στο πρόγραμμα
μας και το τελικό αποτέλεσμα.
Employee.java
package com.example;
class Employee {
private String name;
private int AFM;
private double salary;
private String department;
private int remainingDays;
private int employeeId;
public static int counter;
public Employee(String name, double salary, String department) {
System.out.println("Constructing an Employee");
this.name = name;
this.salary = salary;
this.department = department;
this.employeeId = ++counter;
}
{
System.out.println("Static initializer running before object creation");
}
public static int getCounter() {
System.out.println("Inside getCounter");
return counter;
}
public int getEmployeeId() {
return employeeId;
}
public void setEmployeeId(int employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAFM() {
return AFM;
}
public void setAFM(int AFM) {
this.AFM = AFM;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public String getDepartment() {
return department;
}
public void setDepartment(String department) {
this.department = department;
}
public int getRemainingDays() {
return remainingDays;
}
public void setRemainingDays(int remainingDays) {
this.remainingDays = remainingDays;
}
public void mailCheck() {
System.out.println("Mailing a check to " + this.name);
}
public double payment() {
return this.salary / 52.0;
}
public void vacationCalc(int daysTotal, int daysRequested) {
this.remainingDays = daysTotal - daysRequested;
System.out.println("You have requested " + daysRequested + " days of vacation");
}
}
EmployeeDemo.java
package com.example;
public class EmployeeDemo {
public static void main(String[] args) {
Employee.counter = 100;
Employee michail = new Employee("Michail", 20000, "Development");
System.out.println(michail.getName() + ", your new employee id is: " + Employee.getCounter());
Employee john = new Employee("John", 30000, "HR");
System.out.println(john.getName() + ", your new employee id is: " + Employee.getCounter());
}
}
Output
Static initializer running before
object creation
Constructing an Employee
Inside getCounter
Michail, your new employee id is:
101
Static initializer running before
object creation
Constructing an Employee
Inside getCounter
John, your new employee id is:
102
Μην ξεχάσετε να κάνετε ένα μικρό donation έτσι ώστε αυτό το blog να μεγαλώσει
ακόμα πιο πολύ και να έχει περισσότερες δυνατότητες στην online παράδοση δωρεάν
μαθημάτων.
full-width
0 Comments
Η γνώμη σας είναι σημαντική.