Page 1 of 1

Εσωτερικές classes και final local variables σε Java

Posted: Thu Nov 15, 2007 7:38 pm
by Zifnab
Με ποιό σκεπτικό υποχρεούμαι να δηλώσω final οποιαδήποτε local μεταβλητή που θα χρησιμοποιήσω σε local inner class (και μάλιστα anonymous) ?
Υπάρχει κάποια λύση?
π.χ

Code: Select all

public void func(final Obj obj) {
    final String str = "bla bla";
    Timer timer = new Timer();
    TimerTask timertask = new TimerTask(){
       public void run(){
           obj.setX(4); //εδώ χτυπάει compiler
           System.out.println(str.length()+obj.toString());
       }
   };
   timer.schedule(timertask,1000);
}

Posted: Thu Nov 15, 2007 11:48 pm
by Sreak
Για check this
Two ways to pass initializing parameters to an inner class:

* Initialize a property that the inner class then uses -- properties have the cross-method-call persistence that local variables lack.
* Make the local variable "final" -- compiler will automatically transfer the value to a more persistent portion of the computer memory. Disadvantage: the value cannot be changed. (Γιαυτό χτυπάει ο compiler)
http://www.exciton.cs.rice.edu/JavaReso ... lasses.htm

Posted: Fri Nov 16, 2007 1:28 am
by tsilochr
προφανώς και χτυπά γιατι το obj είναι final και με την obj.setX το αλλάζεις, κάτι που απαγορεύεται.

όμως δεν καταλαβαίνω ποια είναι η απορία σου ακριβώς. δεν είναι υποχρεωτικό να χρησιμοποιείς final πεδία. ίσα ίσα συνήθως σε εσωτερικές τάξεις χρησιμοποιείς πεδία της εξωτερικής τάξης. κλασσικό pattern για multithreading αρκεί να συγχρονίσεις την πρόσβαση στις κοινές δομές (πεδία της εξωτερικής τάξης) - αυτό που στα λειτουργικά συστήματα λέγεται race conditions

Posted: Fri Nov 16, 2007 11:54 am
by Zifnab
Πρώτον δεν ξέρω να συγχρονίζω με multithreading ή ότιδήποτε άλλο σε σχέση με αυτό που λές tsilochr, ακόμα :-p
Δεύτερον, η απορία μου δεν ήταν γιατί δεν έκανε compile, αλλά γιατί να με υποχρεώνει σε μία από τις περιπτώσεις να ορίζω τις local μεταβλητές final (με βάση το link του Sreak). Ποιό το σκεπτικό ? Τι θα υπήρχε πρόβλημα στην υλοποίηση άμα δεν μας υποχρέωναν να τις κάνουμε final (ξεχνάμε τους συγχρονισμούς) για λίγο...Δηλαδή τι πρόβλημα θα υπήρχε αν η εσωτερική τάξη επιτρεπόταν να αλλαζει τα local πεδία της εξωτερικής μεθόδου?

Posted: Fri Nov 16, 2007 12:10 pm
by tsilochr
Since an object made from the inner class has a "life" independent of its outer class object, there is a problem with accessing local variables, especially method input paramenters.
Έχει να κάνει με την υλοποίηση από μεριάς compiler, προφανώς το χώρο στη μνήμη που φορτώνεται κλπ. Υπόψην μιλάμε αυστηρά για ανώνυμες κλάσεις και όχι απλά εσωτερικές. Δεν έχω ασχοληθεί εκτενώς πάντως.
Zifnab wrote:Πρώτον δεν ξέρω να συγχρονίζω με multithreading ή ότιδήποτε άλλο σε σχέση με αυτό που λές tsilochr, ακόμα
Ναι, αλλά λειτουργικά πρέπει να έχεις πάρει άρα τα race conditions και το producer-consumer schema δεν σου είναι άγνωστα ε?

ΥΓ Κατανεμημένα πήρες φέτος? ;)

Posted: Fri Nov 16, 2007 2:33 pm
by HdkiLLeR
Να μου ζήσετε παιδιά μου!!! Επιτέλους ένα ωραίο και τεχνικό θεματάκι μετά απο τόσο καιρό :) :) :)

Λοιπόν έχουμε και λέμε (θα είναι ψιλομεγάλο το post):

Στην συγκεκριμένη περίπτωση έχεις conflict δύο ξεχωριστών ιδιοτήτων/features.

0)Πάμε σε μερικά βασικά που πρέπει να γνωρίζεις για να το πιάσουμε. Έχεις διαφορετικά κομμάτια μνήμης για κάθε process: το heap, το stack, το code, το data (αυτά έχουν να κάνουν με τα segment registers του x86 αλλά μην το τραβήξουμε σε assembly γιατί δεν θα το διαβάσει κανένας το post :)). Όταν τρέχεις ένα .class, τότε γίνονται τα εξής*:

a)ο εκτελέσιμος κώδικας για κάθε method (οι εντολές δηλαδή), μπαίνουν στο code segment.
b)static, final και διάφορα άλλα variables τέτοιων τύπων μπαίνουν στο data
c)μεταφέρεται ο έλεγχος στην main και ξεκινάει η εκτέλεση -- δηλαδή η main, σαν method και αυτή είναι στο code segment και απλά πάει ο έλεγχος εκεί και ξεκινάει η εκτέλεση.**

Κάθε φορά που γίνεται ένα new τότε πολύ απλά δεσμεύεται χώρος μόνο για τα global variables μιας class στο heap (τα methods βρίσκονται ήδη στο code segment δεν χρειάζεται να ξαναφορτωθούν).

Ενώ κάθε φορά που τρέχει μια method τα local variables αλλά και τα arguments περνάνε στο stack

1)Η Java σου δίνει την δυνατότητα να χρησιμοποιείς inner classes (συντακτικά). Αυτό τι σημαίνει όσον αφορά όμως το scope/life*** των variables; Οτι θα μπορείς να χρησιμοποιήσεις κατευθείαν μια μεταβλητή που έχει οριστεί σε μια function/method μέσα στην inner class. Ο κλασσικός ορισμός του scope, nothing more, nothing less.

2)Πάμε λίγο σε σοβαρά πράγματα τώρα, για να υλοποιήσεις το variable scope γίνεται χρήση της στοίβας για τις local variables και τα ορίσματα σε μεθόδους.

Συνεπώς εάν έχεις το εξής code segment:

Code: Select all

public class foo {
        private int fooBar;

        public foo() {
                fooBar = 0;
        }

        public void print() {
                int fooBar = 1;
                System.err.println(fooBar+" "+this.fooBar);
        }

        public static void main(String args[]) {
                new foo().print();
        }
}
Όταν κληθεί η print(), τότε έχεις στην στοίβα (μεταξύ άλλων - return addess, return value κλπ κπλ) και το fooBar--το local. Κάθε φορά που γίνεται αναφορά στο fooBar μέσα στην μέθοδο, αυτό αναφέρεται σε μια συγκεκριμένη θέση στο stack, ενώ το this.booBar είναι μια θέση της μνήμης στο heap.

Το πρόβλημα είναι ότι η ζωή του local fooBar είναι όσο διαρκεί η κλήση της method print(). Λίγο πρίν ξεκινήσει η εκτέλεση της τρέχει σε assm (το παράγει ο compiler αυτό - εσύ δεν το βλέπεις) ένα κομμάτι που κάνει stack advancement, περνάει παραμέτρους, return address κλπ κλπ. Μόλις τελειώσει πετάει και ότι βρίσκεται μέσα στο κομμάτι αυτό της στοίβας που χρησιμοποίησε (αφαιρεί απο το top δηλαδή).

3)Εσύ τώρα τι έχεις; Μια class μέσα σε μια function. Η class υπάρχει στο heap (απο την αρχή), ενώ η function έχει τις local variables στο stack. Οπότε δύο προβλήματα:

a)πως μια method (η run()) μιας class(της inner - TimerTask) θα προσπελάσει κάτι που βρίσκεται μέσα σε στο stack μιας μεθόδου (func()) μιας άλλης class (αυτής στην οποία ανήκει η func());

b)κανονικά το timertask είναι thread, αυτό σημαίνει ότι ενώ θα εκτελείται η run() του timertask ο κώδικας της func θα συνεχίσει να εκτελείται -- ψευδοπαράλληλα.

Όσον αφορά το a, το πρόβλημα σου είναι ότι θα πάρεις segmentation fault. Γιατί μια class θα πάει να πειράξει variables - code άλλης. Το ίδιο το OS δεν το επιτρέπει αυτό, συενπώς εσύ μπορείς να γράφεις έτσι στην Java αλλά ο compiler ποιός ξέρει τι σηκώνει απο πίσω και τι overhead έχει για να το επιτύχει αυτό -- στην ουσία υλοποιεί ένα light IPC - interprocess communication με shared memory μεταξύ δύο process για να το πετύχει (το εικάζω αυτό δεν το έχω ψάξει).

Το b είναι στην ουσία αυτό που σου δημιουργεί το πρόβλημα σου. Καθώς θα τρέχει η run(), η func() θα τελειώσει και θα πρέπει να διαγράψει και απο την stack την local variable. Η run() όμως μπορεί να αναφερθεί σε αυτήν πιο μετά :). Συνεπώς γι' αυτό σου λέει κάντην final για να ξενοιάσει απο τέτοια θέματα, θα φύγει απο το stack και θα ζεί ώστε να μην έχεις τέτοια probs. Επίσης αποφεύγεις και race conditions, σε περίπτωση που δεν κάνεις σωστό multiple access (εάν και η func και η run πειράζουν την variable str).

*:Τα γράφω λίγο απλοϊκά, εάν θέλετε το χοντρένουμε μετά, δεν είναι εντελώς έτσι εδώ.
**: Εντάξει γίνεται και κάτι ακόμη εδώ, το environment preparation, δηλαδή αντιγράφονται environment variables στο stack της method αυτής για να μπορείς να επεξεργαστείς τα arguments κλπ κλπ.
***: Το scope και το life μιας μεταβλητής είναι το ίδιο πράγμα ουσιαστικά, ανάλογα με το scope, ορίζεται και πόσο θα ζήσει η κάθε μεταβλητή.

Posted: Sat Nov 17, 2007 1:36 am
by The Punisher
great post! σε πάω :-D

Posted: Sat Nov 17, 2007 2:18 am
by Zifnab
φοβερός Hd!!!! :-D Κανένα καλό βιβλίο να αγγίξουμε και εμείς αυτή τη γνώση έχεις να προτείνεις? Έψαξα αλλά δεν βρήκα κάτι στους τομέις
Compilers,System organization,JVM κτλ... :-( Thnx για τον χρόνο που διάθεσες once again ;)

Posted: Sat Nov 17, 2007 10:48 am
by tsilochr
zifnab, για τα βασικά: τη διαδικασία με την στοίβα και πως υλοποιείται μια κλήση υπορουτίνας σε assembly (αντιγραφή παραμέτρων, διεύθυνση επιστροφής κλπ) την κάνεις στο εργαστήριο Οργάνωσης. Το πως οργανώνεται ο κώδικας (code segment, data, stack) το κάνεις στα λειτουργικά (σημάντικό κομμάτι του επιστημονικού πεδίου των λειτουργικών είναι να ασφαλίσει την περιοχή μνήμης της εκάστοτε διεργασίας).

Από κει και έπειτα όμως είναι προσωπική ενασχόληση. Σκόρπιες πληροφορίες που μαζεύεις με το καιρό, τις συνθέτεις στο μυαλό σου και πλέον όλα είναι μια εικόνα. Δεν είναι ένα βιβλίο που θα στα πει. Αν θες μια πηγή που να σου λύνει τέτοιες απορίες με τη μία, εδώ είναι ο hd!!!!

Φυσικά ο hd εκτονώνεται στο venus γράφοντας tech reports αντί να χαβαλεδιάσει στο off topic και κάνει όλους εμάς να θέλουμε να σκίσουμε τα πτυχία μας από ντροπή. Φτου σου :-p

Posted: Sat Nov 17, 2007 1:03 pm
by HdkiLLeR
Zifnab wrote:Κανένα καλό βιβλίο να αγγίξουμε και εμείς αυτή τη γνώση έχεις να προτείνεις? Έψαξα αλλά δεν βρήκα κάτι στους τομέις
Compilers,System organization,JVM κτλ... :-( Thnx για τον χρόνο που διάθεσες once again ;)
Τπτ, χαρά μου να μιλάμε για τέτοια πράγματα. Μακάρι να έχεις πάντα τέτοιους (και χειρότερους :)) προβληματισμούς για να τους συζητάμε και να ξεσκουριάζουμε. Τώρα σχετικά με books και sources δεν έχω να προτείνω κάτι, δεν νομίζω ότι έχω διάβασει και την τρομερή βιλβιογραφία. Ο Χρήστος σου είπε τα βασικά κομμάτια και θα είσαι μια χαρά.

ΥΓ: Δική μου συμβουλή είναι να μην μένεις στο διάβασμα, μικρά πραγματάκια θα σου μείνουν περισσότερο εάν τα υλοποιείς, γιατί πέρα απο το πρόβλημα που θα λύσεις, κατά την υλοποίηση, θα αναλογιστείς και άλλα 10 και έτσι θα έχεις καλύτερη άποψη.

Posted: Sun Nov 18, 2007 1:11 pm
by Zifnab
Ευχαριστώ πολύ παιδιά! :-D Βασικά δεν είναι και πολύ επλιδοφόρο που μου αναφέρετε τα δύο μαθήματα Κάβουρα...Έπρεπε να υπάρχει ένα βιβλίο για το έναυσμα! :???: Φυσικά και δεν μένω στη θεωρία αλλά προχωράω στην υλοποίηση (εξάλλου μισώ την θεωρία σκέτη και ανυλοποίητη)

Ηd έχω πολλές σκοτεινές απορίες αλλά δεν μαζεύονται - είναι ένα χάος - γι αυτό δεν πέρασα επίτηδες οριακά τα Λειτουργικά γιατί απλά δεν το άξιζα ;) - ούτε έδωσα Οργάνωση .....

Θα κοιτάξω αυτά που είπε ο Τσίλο και βλέπουμε ;)