Εισαγωγή στην Java - κεφ. 3

...ασύγχρονα μαθήματα γλώσσας Java

Εισαγωγή στην Java - κεφ. 3

Δημοσίευσηαπό alkismavridis » 28 Απρ 2012, 13:28

Προηγούμενο: Το πρώτο μας πρόγραμμα
Επόμενο: Τελεστές

Βασικοί τύποι δεδομένων


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

Αν δούμε γραμμένο σε ένα χαρτί το κείμενο 20:10, μπορούμε να το δούμε σαν διαίρεση και να πούμε «είκοσι διά δέκα», δηλαδή δύο. Θα μπορούσαμε όμως να το δούμε σαν ώρα της ημέρας και να πούμε «οκτώ και δέκα το απόγευμα».
Το δίδαγμα είναι ότι η ίδια πληροφορία, όταν διαβαστεί με διαφορετικούς τρόπους δίνει διαφορετικό μήνυμα!

Κάπως έτσι μπορούμε να δούμε την έννοια των «τύπων δεδομένων».
Δεδομένα (ή μεταβλητές) ονομάζουμε μία σειρά από 0 και 1 που αποθηκεύονται στη μνήμη του υπολογιστή μας. Είναι η πληροφορία των προγραμμάτων μας.
Ο τύπος δεδομένων καθορίζει πως αυτά θα διαβαστούν ή θα γραφούν!

Κάθε μεταβλητή έχει τον τύπο της. Ο τύπος δηλώνεται τη στιγμή δημιουργίας της μεταβλητής (ή και πιο πριν σε ορισμένες περιπτώσεις!) και δέν αλλάζει κατά τη διάρκεια του προγράμματος.

Υπάρχουν δύο κατηγορίες μεταβλητών: Οι βασικοί τύποι (primitive data types) και τα αντικείμενα (objects).
Θα πρέπει να διαχωρίσουμε σαφώς αυτές τις δύο κατηγορίες, γιατί η Java τις μεταχειρίζεται αρκετά διαφορετικά!

Ας ασχοληθούμε λοιπόν αρχικά με τους βασικούς τύπους. Όλα τα υπόλοιπα βασίζονται σε αυτούς. Περιλαμβάνουν αριθμούς, χαρακτήρες και λογικές τιμές.

Διακρίνουμε 8 είδη βασικών τύπων:
4 για ακέραιους αριθμούς: byte short int και long
2 για δεκαδικούς αριθμούς: float και double
Χαρακτήρες κειμένου: char
Λογικές τιμές: boolean

Ας δούμε όμως τι είναι το καθένα!

Στην κατηγορία των ακεραίων αριθμών αυτό που αλλάζει είναι πόσο μεγάλη είναι η πληροφορία, άρα πόσο μεγάλο αριθμό μπορούμε να αναπαραστήσουμε.
Ο byte έχει μέγεθος ...(μαντέψτε!)... 1 byte (=8bit) και μπορεί να αναπαραστήσει τιμές από -128 εώς και 127
short: μέγεθος 2 byte, αναπαριστά από -32,768 εώς και 32,767
int: μέγεθος 4 byte, αναπαριστά από -2,147,483,648 εώς και 2,147,483,647
long: μέγεθος 8 byte, αναπαριστά από -9,223,372,036,854,775,808 εώς και 9,223,372,036,854,775,807 (πολύ πράμα)

Στους δεκαδικούς αριθμούς επίσης, αλλάζει το μέγεθος και άρα η ακρίβεια
Ο float έχει μέγεθος 4 byte
Ο double 8 byte

Οι χαρακτήρες κειμένου έχουν μέγεθος 2 byte και περιλαμβάνουν τους ASCII χαρακτήρες: εκτυπώσιμους όπως τα a,b,1,2,%,^ και μη εκτυπώσιμους, όπως ο χαρακτήρας αλλαγής παραγράφου κ.α.

Τέλος, οι λογικές τιμές αναπαριστούν δύο είδη δεδομένων: true και false Και είναι πολύ χρήσιμες για λογικούς ελέγχους, και διάκριση περιπτώσεων!

Ωραία! Είδαμε ποιοι είναι οι τύποι δεδομένων. Τι μπορούμε να κάνουμε όμως με αυτούς; Πως τους χρησιμοποιούμε;



1. Δήλωση μεταβλητών
Πριν κάνουμε οτιδήποτε με μία μεταβλητή πρέπει να την δηλώσουμε. Δηλαδή να πούμε στον compiler ότι «η συγκεκριμένη μεταβλητή υπάρχει και έχει τον τάδε τύπο».
Η εντολή που δηλώνει μεταβλητές είναι πολύ απλή! Απλώς γράφουμε τον τύπο που θέλουμε, ύστερα τα ονόματα των μεταβλητών χωρισμένα με κόμμα, και τέλος το ; που δηλώνει το τέλος της εντολής.

Παραδείγματα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int a;
int b;
double e, pi;
byte mybyte, my_other_byte;
boolean secret;
char mychar;



2. Ανάθεση τιμής
Μπορούμε να δίνουμες διάφορες τιμές στις μεταβλητές μας χρησιμοποιώντας τον τελεστή ανάθεσης που είναι το =

Σημαντικό: Μην μπερδεύετε τον τελεστή ανάθεσης με το μαθηματικό ίσον!

Η χρήση της εντολής έχει ως εξής:
Αριστερά του = γράφουμε το όνομα της μεταβλητής (χωρίς τον τύπο της) και δεξιά την τιμή που θέλουμε να δώσουμε.
Το πρόγραμμα θα θυμάται αυτές τις τιμές. Οποιαδήποτε χρήση της μεταβλητής από εδώ και πέρα θα «παραπέμπει» στην τιμή της!

Παραδείγματα
Μορφοποιημένος Κώδικας: Επιλογή όλων
a = 500; //Μπορούμε να βάζουμε κενά πριν και μετά το = αν θέλουμε
b = a; //Αυτή η εντολή είναι σωστή! Δίνει και στο b την τιμή 500
e=2.718; //Χρησιμοποιούμε '.' και όχι ',' για τους δεκαδικούς αριθμούς!
pi=3.14159;
secret=true; //Μία boolean μπορεί να είναι ΜΟΝΟ true ή false. Σε άλλες γλώσσες όπως η C/C++ οι αριθμοί 0 και 1 μπορούν να παριστάνουν boolean,
//στην Java αυτό δε συμβαίνει...
mychar='r'; //Τους χαρακτήρες τους εσωκλείουμε σε μονές αποστρόφους!


Μία ιδιαίτερη περίπτωση ανάθεσης είναι όταν δεξιά του = εμφανίζεται πάλι η μεταβλητή που αναθέτουμε. Πχ:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int a=10;
a = a+5; //χρησιμοποιούμε τον τελεστή + για να κάνουμε πρόσθεση. Η εντολή αυτή κάνει το a 15...


Η εντολή αυτή λέει: Κάνε το a ό,τι ήταν πριν +5.
Υπενθυμίζω: ο τελεστής = δεν πρέπει να συγχέεται με την μαθηματική ισότητα, γιατί τότε η έκφραση a=a+5 δε θα είχε κανένα νόημα!
Οι ποσότητες στο δεξί μέλος συμβολίζουν τις τιμές πριν την ανάθεση, ενώ το αριστερό μέλος την τιμή της μεταβλητής μετά την ανάθεση!
Με την ίδια λογική θα μπορούσαμε να γράψουμε:

Μορφοποιημένος Κώδικας: Επιλογή όλων
a=6-a;
a = a*a + 2*a; //Εδώ βλέπουμε έναν άλλο τελεστή: τον * που κάνει πολλαπλασιασμό.
a = (a-1)*(a+8);

ή ότι άλλο χωράει ο νούς σας!


:!:Η ανάθεση τιμής μπορεί να γίνει και ταυτόχρονα με τη δήλωση ως εξής:
Μορφοποιημένος Κώδικας: Επιλογή όλων
int a=7, b=10;
char c='&', d='u', f;// Εδώ στους δύο δίνουμε αρχική τιμή ενώ στον τρίτο όχι!
double mydouble = 64.9;


Αν δε γράψουμε εμείς κάποια τιμή κατά τη δήλωση ο Compiler δίνει μία προεπιλεγμένη τιμή. Παρ όλα αυτά καλό είναι πάντα να γράφουμε την τιμή που θέλουμε για να είναι πιο ευανάγνωστος ο κώδικάς μας!



Η προεπιλεγμένη τιμή είναι μηδέν για όλους τους αριθμούς, false για την boolean και ο '\u0000' για την char.


Κατά τη διάρκεια του προγράμματος οι τιμές που δώσαμε στις μεταβλητές μας μπορεί να αλλάξουν! Γράψτε, κάντε compile και τρέξτε το παρακάτω πρόγραμμα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
//Αρχείο Primitive.java
public class Primitive {
public static void main(String[] args) {
int i=4;
System.out.print(i);
System.out.print("\n"); //άλλαξε σειρά!
i=i+3; //δηλαδή i=7
System.out.print(i);
System.out.print("\n");
i=150000;
System.out.print(i);
}//MAIN
}//CLASS

Παρατηρούμε ότι με μία μεταβλητή, την i εκφράσαμε (σε διαφορετικά στάδια του προγράμματος) 3 τιμές!

:!: Υπάρχει παρόλα αυτά και η δυνατότητα να δίνουμε σε μία μεταβλητή κάποια τιμή, που δε θα επιτρέψουμε να αλλάξει καθ όλη την πορεία του προγράμματος. Αυτό μπορεί να γίνει μόνο κατά τη δήλωση της, βάζοντας τη λέξη-κλειδί final πριν από τον τύπο, και ορίζοντας αμέσως την τιμή ώς εξής:

Μορφοποιημένος Κώδικας: Επιλογή όλων
final short days = 7;


Η λέξη final (τελικός -η -ο) δηλώνει ότι αυτή η τιμή είναι η τελική, δε θα αλλάξει ποτέ.
Αν εμείς παρόλα αυτά προσπαθήσουμε να αλλάξουμε την τιμή του days, ο compiler θα παραπονεθεί ότι αυτό δεν επιτρέπεται, και το πρόγραμμά μας δε θα γίνει compile. Δοκιμάστε το για πείραμα!

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

Κάντε χρήση του final όπου μπορείτε!



Τέλος να πούμε ότι μπορούμε να αναθέσουμε σε μία μεταβλητή κάποιου τύπου, την τιμή μίας άλλης άλλου τύπου!
Προϋπόθεση όμως είναι ο τύπος της μεταβλητής δεξιά του = να είναι ίσος ή κατώτερος με αυτόν στα αριστερά.
πχ
Μορφοποιημένος Κώδικας: Επιλογή όλων
int i=2;
long l=3;
byte b=4;

i = b; //Σωστό! Ο compiler παίρνει την τιμή του b, την μετατρέπει σε int (4 byte) και δίνει αυτή την τιμή στο i

i = l;//Λάθος! Ο compiler δε μπορεί να μετατρέψει τον l σε int για να τον αποθηκεύσει στο i!
//Η πληροφορία 8 byte δε μπορεί να χωρέσει σε 4!
//Αν δοκιμάσετε να γράψετε κάτι τέτοιο, κατά το compile θα σας βγει σφάλμα...


Αντί να γράφουμε εμείς τις τιμές των μεταβλητών, μπορούμε να αφήνουμε το χρήστη να τις αποφασίζει! Έτσι ο προγραμματισμός αποκτά περισσότερο νοημα..
Στην Java υπάρχουν πολλοί τρόποι να παίρνουμε τιμές απ' το χρήστη. Παραθέτω αυτόν που θεωρώ πιο απλό (αν και δεν μου αρέσει σαν παιδαγωγική μέθοδος, θα σας ζητήσω να αντιγράψετε τις παρακάτω εντολές ακόμα και αν δεν καταλαβαίνετε τι ακριβώς σημαίνουν):

i. Στην αρχή του προγράμματος, πρίν τη δήλωση της κλάσης γράφουμε την εντολή import java.util.Scanner;
ii. Μέσα στην main γράφουμε: Scanner sc = new Scanner(System.in);
Το sc είναι απλώς το όνομα κάποιας μεραβλητής. Μπορείτε αν θέλετε να δώσετε κάποιο άλλο όνομα.
iii. Διαβάζουμε μεταβλητές με τις μεθόδους nextInt() nextDouble() nextBoolean() κτλ ως εξής:

Μορφοποιημένος Κώδικας: Επιλογή όλων
//αρχείο UserValue.java
import java.util.Scanner;

public class UserValue {
public static void main(String[] args) {

Scanner sc = new Scanner(System.in);
int i;
double d;
System.out.print("δώσε έναν ακέραιο\n");
i = sc.nextInt(); //έτσι λειτουργεί
System.out.print("\nκαι ένα πραγματικό\n");
d = sc.nextDouble(); // η ίδια λογική

System.out.print("\nΈδωσες "+i+" "+j+"\n");
}//main
}// class



3. Typecasting
Παρόλα αυτά μπορούμε, γράφοντας σε παρένθεση ένα τύπο πριν από μία μεταβλητή να πούμε στον compiler να προσπαθήσει να μετατρέψει αυτή τη μεταβλητή στον συγκεκριμένο τύπο, ακόμα και αν αυτό... είναι κατά τα παραπάνω αδύνατο!

Παράδειγμα:
Μορφοποιημένος Κώδικας: Επιλογή όλων
byte b=6;
int i=9;

b = (byte)i; //Μετατρέπει τον int σε byte. Αν όμως ο int έχει μία τιμή που «ξεφεύγει» από τα όρια του byte, πχ την 1000
//τότε το αποτέλεσμα θα είναι ολίγον... παράξενο! Μπορείτε να δοκιμάσετε να δείτε τι θα γίνει :)



4. Εργαζόμαστε με τις μεταβλητές μας χρησιμοποιώντας τελεστές
Την ενότητα των τελεστών θα την καλύψουμε στο επόμενο κεφάλαιο!


Προηγούμενο: Το πρώτο μας πρόγραμμα
Επόμενο: Τελεστές

Creative Commons License
Η εργασία υπάγεται στην άδεια Creative Commons Αναφορά-Παρόμοια διανομή 3.0 Ελλάδα
Γνώσεις ⇛ Linux: Μέτριο┃ Προγραμματισμός: Java, Assembly, Fortran, μαθαίνω C/X11┃ Αγγλικά: Μέτρια
Λειτουργικό σε Η/Υ ϰ μοντέλο: Ubuntu 14.04 64-bit ┃ Τρόπος εγκατάστασης: Live USB
Προδιαγραφές ⇛ Desktop: Intel i5 2320 3.00GHz.┃ MotherBoard: Asus p8h61 -m pro
Προδιαγραφές ⇛ RAM: 4GB ┃ Τροφοδοτικό Corsair CX430

GPU: Intel 2nd Generation Core Processor Family Integrated Graphics Controller [8086:0102] {i915}
5 eth0: Realtek RTL8111/8168B PCI Express Gigabit Ethernet controller [10ec:8168] (rev 06) ⋮ wlan0: 0b05:1723 ASUS WL-167G v2 802.11g Adapter [Ralink RT2571W]
Οθόνη Schaub Lorenz (Tv)
alkismavridis
punkTUX
punkTUX
 
Δημοσιεύσεις: 273
Εγγραφή: 18 Μαρ 2009, 18:46
Εκτύπωση

Re: Εισαγωγή στην Java - κεφ. 3

Δημοσίευσηαπό Vegeta » 30 Δεκ 2014, 02:40

μία διόρθωση και μία πολύ σημαντική (θεωρώ) παρατήρηση:

η διόρθωση:
στο "2. Ανάθεση τιμής", στο τελευταίο κομμάτι κώδικα...
αντί για: System.out.print("\nΈδωσες "+i+" "+j+"\n");
νομίζω ότι θέλεις να γράψεις: System.out.print("\nΈδωσες "+i+" "+d+"\n");

η παρατήρηση:
στο ίδιο κομμάτι κώδικα...
κάνοντας compile με open-jdk έχουμε (νομίζω) το αποτέλεσμα που θέλουμε.
κάνοντας compile με gcj έχουμε άλλο αποτέλεσμα...
πρώτα περιμένει να διαβάσει τον int,
μετά εμφανίζει το "δώσε έναν ακέραιο",
μετά περιμένει να διαβάσει τον double,
μετά εμφανίζει το "και ένα πραγματικό",
μετά περιμένει να διαβάσει έναν δεύτερο double,
τελικά εκτυπώνει τον Int και τον πρώτο double...

είναι δυνατόν, ο ίδιος ακριβώς κώδικας, όταν γίνεται compile με δύο διαφορετικούς compliers, να δίνει τόσο διαφορετικά αποτελέσματα?
κάτι στραβό δεν συμβαίνει?
Linux: Καλά | Προγραμματισμός: Καλά | Αγγικά: Καλά
Asus TUF Gaming A15 FA506IV-HN216T (Ryzen 9-4900H/16GB/512GB/GeForce RTX 2060/FHD/W10)
Ubuntu 20.04.1 LTS
Άβαταρ μέλους
Vegeta
babeTUX
babeTUX
 
Δημοσιεύσεις: 83
Εγγραφή: 25 Μαρ 2010, 13:49
Εκτύπωση


  • ΣΧΕΤΙΚΑ ΘΕΜΑΤΑ
    ΑΠΑΝΤΗΣΕΙΣ
    ΠΡΟΒΟΛΕΣ
    ΣΥΓΓΡΑΦΕΑΣ

Επιστροφή στο Μαθήματα Java