java:static_keyword

Στατικές μεταβλητές και μέθοδοι της κλάσης

Μέχρι τώρα είδαμε ότι τα αντικείμενα αποτελούν υλοποιήσεις της κλάσης που είναι το “σχέδιο” των αντικειμένων που υλοποιούνται. Με την έννοια αυτή όλα τα πεδία και οι μέθοδοι της κλάσης ανήκουν τελικά στα επιμέρους αντικείμενα της κάθε κλάσης.

Εκτός από την παραπάνω θεώρηση είναι δυνατόν να έχουμε πεδία και μεθόδους που δεν ανήκουν σε συγκεκριμένα αντικείμενα της κλάσης, αλλά στην κλάση. Σε αυτή τη σελίδα αναλύουμε την χρήση του keyword static για την δημιουργία στατικών πεδίων και μεθόδων που ανήκουν στην κλάση και όχι σε συγκεκριμένα αντικείμενα της κλάσης.

Εάν τα πεδία ή οι μέθοδοι ανήκουν στη κλάση και όχι στα αντικείμενα της τότε οι μέθοδοι και τα πεδία είναι στατικά για τα αντικείμενα της κλάσης. Για παράδειγμα, αν προσπελάσουμε την τιμή ενός πεδίου που ανήκει στην κλάση από δύο διαφορετικά αντικείμενα της κλάσης τότε θα διαβάσουμε ακριβώς την ίδια τιμή.

Στατικές μεταβλητές της κλάσης

Ας θεωρήσουμε το παρακάτω παράδειγμα από τον κώδικα του παραλληλόγραμμου.

public class Rectangle {
 
  private int width;
  private int height;
  private Point origin;
 
  // the Rectangle class has one constructor
  public Rectangle(int width, int height, Point origin) {
    this.width = width;
    this.height = height;
    this.origin = origin;
  }
 
  // add an instance variable for the object ID
  private int id;
 
  // add a class variable for the
  // number of Rectangle objects instantiated
  private static int numberOfRectangles = 0;
 
  /* οι υπόλοιπες εντολές της κλάσης είναι όμοιες 
   * με προηγούμενα παραδείγματα και παραλείπονται
   * για λόγους οικονομίας χώρου.
   */
}

Με τον ορισμό

private static int numberOfRectangles = 0;

δημιουργούμε μία μεταβλητή που έχει ενιαία τιμή για όλες τα αντικείμενα της κλάσης μας. Η μεταβλητή αυτή δεν ανήκει σε κάποιο από τα αντικείμενα, αλλά ανήκει στην κλάση. Επομένως, για τα αντικείμενα της κλάσης αυτής, η συγκεκριμένη μεταβλητή μπορεί να θεωρηθεί στατική (για αυτό και η χρήση του keyword static).

Για να προσπελάσουμε την τιμή της συγκεκριμένης μεταβλητής μπορούμε να το κάνουμε με τους εξής δύο τρόπους:

  1. Με χρήση του ονόματος της κλάσης Rectangle.numberOfRectangles++;.
  2. Με χρήση ενός αντικειμένου ως εξής Rectangle myRectangle = new Rectangle(); myRectangle.numberOfRectangles++;.

Και οι δύο παραπάνω τρόποι προσπέλασης είναι ισοδύναμοι για τον compiler. Ο 2ος τρόπος προσπέλασης ΔΕΝ συνιστάται, καθώς δεν είναι σαφές αν πρόκειται για μεταβλητή που ανήκει στην κλάση ή στο αντικείμενο. Αντίθετα, ο 1ος τρόπος αφορά αποκλειστικά μεταβλητές που ανήκουν στην κλάση και για αυτό θεωρείται προγραμματιστικά ορθότερος. Δείτε τον κώδικα της κλάσης Rectangle όπως διαμορφώνεται με την χρήση των δύο επιπλέον πεδίων και την καταγραφή του αριθμού των αντικειμένων που δημιουργούνται.

Rectangle.java
public class Rectangle {
 
  // fields
  private int width;
  private int height;
  private Point origin;
  // add an instance variable for the object ID
  private int id;
 
  // add a class variable for the
  // number of Rectangle objects instantiated
  private static int numberOfRectangles = 0;
 
  // constructors
  public Rectangle(int initWidth, int initHeight, Point initOrigin) {
    width = initWidth;
    height = initHeight;
    origin = initOrigin;
    id = ++numberOfRectangles;
  }
 
  public int getID() {
    return id;
  }
 
  public static int getNumberOfRectangles() {
    return numberOfRectangles;
  }
 
  // methods
  public void setWidth(int newWidth ) {
    width = newWidth;
  }
 
  public int getWidth() {
    return width;
  }
 
  public void setHeight(int newHeight ) {
    height = newHeight;
  }
 
  public int getHeight() {
    return height;
  }
 
  public void setOrigin(Point newOrigin) {
    origin = newOrigin;
  }
 
  public Point getOrigin() {
    return origin;
  }
 
  public int getArea() {
       return width * height;
  }
 
  // Move rectangle origin by dx,dy
  public void move(int dx, int dy) {
    origin.setX( origin.getX() + dx );
    origin.setY( origin.getY() + dy );
  }
}

Μπορείτε να κατεβάσετε τον πλήρη κώδικα της κλάσης εδώ rectangle_example_with_static.zip.

Στατικές μέθοδοι της κλάσης

Σε αναλογία με τις μεταβλητές της κλάσης μπορούμε να έχουμε και μεθόδους αποκλειστικά σε επίπεδο κλάσης. Oι μέθοδοι της κλάσης χρησιμοποιούνται για να προσπελάσουν στατικά πεδία της κλάσης. Επίσης, μέσα σε μία στατική μέθοδο μπορούν να δημιουργηθούν αντικείμενα οποιασδήποτε κλάσης. Σε αναλογία με τις μεταβλητές οι μέθοδοι σε επίπεδο κλάσης ορίζονται και πάλι με χρήση του keyword static, ως εξής.

public static int getNumberOfRectangles() {
    return numberOfRectangles;
}

Για να καλέσουμε στατικές μεθόδους σε αναλογία με τα πεδία έχουμε τις εξής επιλογές:

  1. Με χρήση του ονόματος της κλάσης Rectangle.getNumberOfRectangles();
  2. Με χρήση ενός αντικειμένου ως εξής Rectangle myRectangle = new Rectangle(); myRectangle.getNumberOfRectangles();

Οι στατικές μέθοδοι μπορούν να χρησιμοποιηθούν για να εκτελεστούν εργασίες που δεν συνδέονται με τα δεδομένα της κλάσης. Για παράδειγμα, η παρακάτω στατική μέθοδος υλοποιεί τον αλγόριθμο Bubble Sort μέσα σε μία κλάση με το όνομα Sort. Ο πίνακας προς ταξινόμηση λαμβάνεται ως όρισμα στη μέθοδο

Sort.java
public class Sort {
  public void bubbleSort(String a[], int left, int right) {
    String temp;
    for(int i=left; i<right; i++) {
      for(int j=right; j>i; j--) {
        if( a[j].compareTo(a[j-1])<0 ) {
          temp = a[j-1];
          a[j-1] = a[j];
          a[j] = temp;
        }
      }
    }
  }
}

Επίσης, μέσα σε μία στατική μέθοδο μπορούμε να δημιουργήσουμε αντικείμενα οποιασδήποτε κλάσης. Παράδειγμα στατικής μεθόδου είναι η μέθοδος main() από την οποία ξεκινάει κάθε πρόγραμμα. Δείτε την παρακάτω μέθοδο η οποία παράγει αρχικοποιημένα με τυχαίες τιμές αντικείμενα της κλάσης Rectangle.

/* η παράμετρος seed αρχικοποιεί την γεννήτρια τυχαίων 
 * αριθμών.
 */
public static Rectangle randomRectangle(int seed) {
  java.util.Random rand = new java.util.Random(seed);
  // εύρος τιμής randWidth (0 - 100)
  int randWidth = rand.nextInt(100);
  // εύρος τιμής randHeight (0 - 100)
  int randHeight = rand.nextInt(100);
  Rectangle rect = new Rectangle(randWidth,randHeight);
  return rect;
}

Συνδυασμοί πρόσβασης στατικών/μη στατικών πεδίων από στατικές/μη στατικές μεθόδους

Συνολικά οι επιτρεπόμενοι συνδυασμοί μεταξύ στατικών και μη στατικών μεθόδων και μεταβλητών είναι οι εξής:

  • Μη στατικές μέθοδοι ΜΠΟΡΟΥΝ να προσπελάσουν μη στατικά πεδία.
  • Μη στατικές μέθοδοι ΜΠΟΡΟΥΝ να προσπελάσουν στατικά πεδία.
  • Στατικές μέθοδοι ΜΠΟΡΟΥΝ να προσπελάσουν στατικά πεδία.
  • Στατικές μέθοδοι ΔΕΝ ΜΠΟΡΟΥΝ να προσπελάσουν μη στατικά πεδία.
    • το παραπάνω είναι λογικό αν αναλογιστείτε ότι μία στατική μέθοδος (που ανήκει συνολικά στην κλάση) δεν μπορεί να γνωρίζει το αντικείμενο στο οποίο ανήκει ένα μη στατικό πεδίο.

Χρήση σταθερών - Constants

H δημιουργία σταθερών επιτυγχάνεται με χρήση του συνδυασμού των keywords static final. Για παράδειγμα, εάν θέλουμε να γράψουμε την σταθερά π=3.141592653589793 θα μπορούσαμε να το κάνουμε ως εξής.

static final double PI = 3.141592653589793;

Η σταθερά θα πρέπει να ανήκει σε μία κλάση σε αναλογία με τις στατικές μεταβλητές της κλάσης που ορίσαμε παραπάνω και δεν μπορεί να οριστεί αυτόνομα.

java/static_keyword.txt · Last modified: 2017/03/03 16:36 by gthanos