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

Συζητήσεις για γλώσσες προγραμματισμού και θέματα σχετικά με προγραμματισμό.
Post Reply
User avatar
Zifnab
Venus Former Team Member
Posts: 7581
Joined: Tue Nov 15, 2005 2:42 am
Academic status: MSc
Gender:
Location: Connecticut
Contact:

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

Post by Zifnab » Thu Nov 15, 2007 7:38 pm

Με ποιό σκεπτικό υποχρεούμαι να δηλώσω 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);
}
User avatar
Sreak
Venus Project Founder
Venus Project Founder
Posts: 956
Joined: Fri Apr 02, 2004 9:56 am
Academic status: PhD
Location: eltrun.gr

Post by Sreak » Thu Nov 15, 2007 11:48 pm

Για 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
User avatar
tsilochr
Wow! Terabyte level
Wow! Terabyte level
Posts: 3246
Joined: Tue Mar 16, 2004 2:47 pm
Academic status: PhD
Gender:
Location: mm.aueb.gr
Contact:

Post by tsilochr » Fri Nov 16, 2007 1:28 am

προφανώς και χτυπά γιατι το obj είναι final και με την obj.setX το αλλάζεις, κάτι που απαγορεύεται.

όμως δεν καταλαβαίνω ποια είναι η απορία σου ακριβώς. δεν είναι υποχρεωτικό να χρησιμοποιείς final πεδία. ίσα ίσα συνήθως σε εσωτερικές τάξεις χρησιμοποιείς πεδία της εξωτερικής τάξης. κλασσικό pattern για multithreading αρκεί να συγχρονίσεις την πρόσβαση στις κοινές δομές (πεδία της εξωτερικής τάξης) - αυτό που στα λειτουργικά συστήματα λέγεται race conditions
User avatar
Zifnab
Venus Former Team Member
Posts: 7581
Joined: Tue Nov 15, 2005 2:42 am
Academic status: MSc
Gender:
Location: Connecticut
Contact:

Post by Zifnab » Fri Nov 16, 2007 11:54 am

Πρώτον δεν ξέρω να συγχρονίζω με multithreading ή ότιδήποτε άλλο σε σχέση με αυτό που λές tsilochr, ακόμα :-p
Δεύτερον, η απορία μου δεν ήταν γιατί δεν έκανε compile, αλλά γιατί να με υποχρεώνει σε μία από τις περιπτώσεις να ορίζω τις local μεταβλητές final (με βάση το link του Sreak). Ποιό το σκεπτικό ? Τι θα υπήρχε πρόβλημα στην υλοποίηση άμα δεν μας υποχρέωναν να τις κάνουμε final (ξεχνάμε τους συγχρονισμούς) για λίγο...Δηλαδή τι πρόβλημα θα υπήρχε αν η εσωτερική τάξη επιτρεπόταν να αλλαζει τα local πεδία της εξωτερικής μεθόδου?
User avatar
tsilochr
Wow! Terabyte level
Wow! Terabyte level
Posts: 3246
Joined: Tue Mar 16, 2004 2:47 pm
Academic status: PhD
Gender:
Location: mm.aueb.gr
Contact:

Post by tsilochr » Fri Nov 16, 2007 12:10 pm

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 δεν σου είναι άγνωστα ε?

ΥΓ Κατανεμημένα πήρες φέτος? ;)
User avatar
HdkiLLeR
Venus Project Founder
Venus Project Founder
Posts: 4356
Joined: Tue Jan 27, 2004 4:41 pm
Academic status: Alumnus/a
Gender:
Location: New York, NY
Contact:

Post by HdkiLLeR » Fri Nov 16, 2007 2:33 pm

Να μου ζήσετε παιδιά μου!!! Επιτέλους ένα ωραίο και τεχνικό θεματάκι μετά απο τόσο καιρό :) :) :)

Λοιπόν έχουμε και λέμε (θα είναι ψιλομεγάλο το 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, ορίζεται και πόσο θα ζήσει η κάθε μεταβλητή.
Last edited by HdkiLLeR on Sat Nov 17, 2007 2:37 am, edited 1 time in total.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d-->--- s+:+ a- C++(+++) BILS++++$ P--- L++++>+++++ E--- W+++ N+ o+ K w--
O M+ V-- PS++>+++ PE- Y++ PGP++ t+ 5+ X+ R* tv b++ DI- D+ G+++ e+++>++++ h r++ y++
------END GEEK CODE BLOCK------

"UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity." -- Dennis Ritchie
The Punisher
Venus Former Team Member
Posts: 7561
Joined: Thu Oct 27, 2005 1:43 pm
Academic status: Alumnus/a
Gender:
Location: Boston, MA

Post by The Punisher » Sat Nov 17, 2007 1:36 am

great post! σε πάω :-D
User avatar
Zifnab
Venus Former Team Member
Posts: 7581
Joined: Tue Nov 15, 2005 2:42 am
Academic status: MSc
Gender:
Location: Connecticut
Contact:

Post by Zifnab » Sat Nov 17, 2007 2:18 am

φοβερός Hd!!!! :-D Κανένα καλό βιβλίο να αγγίξουμε και εμείς αυτή τη γνώση έχεις να προτείνεις? Έψαξα αλλά δεν βρήκα κάτι στους τομέις
Compilers,System organization,JVM κτλ... :-( Thnx για τον χρόνο που διάθεσες once again ;)
User avatar
tsilochr
Wow! Terabyte level
Wow! Terabyte level
Posts: 3246
Joined: Tue Mar 16, 2004 2:47 pm
Academic status: PhD
Gender:
Location: mm.aueb.gr
Contact:

Post by tsilochr » Sat Nov 17, 2007 10:48 am

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

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

Φυσικά ο hd εκτονώνεται στο venus γράφοντας tech reports αντί να χαβαλεδιάσει στο off topic και κάνει όλους εμάς να θέλουμε να σκίσουμε τα πτυχία μας από ντροπή. Φτου σου :-p
User avatar
HdkiLLeR
Venus Project Founder
Venus Project Founder
Posts: 4356
Joined: Tue Jan 27, 2004 4:41 pm
Academic status: Alumnus/a
Gender:
Location: New York, NY
Contact:

Post by HdkiLLeR » Sat Nov 17, 2007 1:03 pm

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

ΥΓ: Δική μου συμβουλή είναι να μην μένεις στο διάβασμα, μικρά πραγματάκια θα σου μείνουν περισσότερο εάν τα υλοποιείς, γιατί πέρα απο το πρόβλημα που θα λύσεις, κατά την υλοποίηση, θα αναλογιστείς και άλλα 10 και έτσι θα έχεις καλύτερη άποψη.
Last edited by HdkiLLeR on Sun Nov 18, 2007 1:45 pm, edited 1 time in total.
-----BEGIN GEEK CODE BLOCK-----
Version: 3.12
GCS d-->--- s+:+ a- C++(+++) BILS++++$ P--- L++++>+++++ E--- W+++ N+ o+ K w--
O M+ V-- PS++>+++ PE- Y++ PGP++ t+ 5+ X+ R* tv b++ DI- D+ G+++ e+++>++++ h r++ y++
------END GEEK CODE BLOCK------

"UNIX is basically a simple operating system, but you have to be a genius to understand the simplicity." -- Dennis Ritchie
User avatar
Zifnab
Venus Former Team Member
Posts: 7581
Joined: Tue Nov 15, 2005 2:42 am
Academic status: MSc
Gender:
Location: Connecticut
Contact:

Post by Zifnab » Sun Nov 18, 2007 1:11 pm

Ευχαριστώ πολύ παιδιά! :-D Βασικά δεν είναι και πολύ επλιδοφόρο που μου αναφέρετε τα δύο μαθήματα Κάβουρα...Έπρεπε να υπάρχει ένα βιβλίο για το έναυσμα! :???: Φυσικά και δεν μένω στη θεωρία αλλά προχωράω στην υλοποίηση (εξάλλου μισώ την θεωρία σκέτη και ανυλοποίητη)

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

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

Return to “Προγραμματισμός”