Struct like objects in Java

Czy tworzenie struktur podobnych do obiektów w Javie jest całkowicie sprzeczne?

class SomeData1 {
    public int x;
    public int y;
}

Widzę klasę z accesorami i mutatorami bardziej podobnymi do Javy.

class SomeData2 {
    int getX();
    void setX(int x);

    int getY();
    void setY(int y);

    private int x;
    private int y;
}

Klasa z pierwszego przykładu nie jest wygodna.

// a function in a class
public int f(SomeData1 d) {
    return (3 * d.x) / d.y;
}
To nie jest takie wygodne.
// a function in a class
public int f(SomeData2 d) {
    return (3 * d.getX()) / d.getY();
}
Author: Cheekysoft, 2008-08-31

20 answers

Jest to często dyskutowany temat. Wadą tworzenia publicznych pól w obiektach jest brak kontroli nad ustawionymi wartościami. W projektach grupowych, gdzie jest wielu programistów używających tego samego kodu, ważne jest, aby unikać skutków ubocznych. Poza tym czasami lepiej zwrócić kopię obiektu Fielda lub jakoś go przekształcić itp. Możesz wyśmiewać takie metody w swoich testach. Jeśli utworzysz nową klasę, możesz nie zobaczyć wszystkich możliwych akcji. To jak obrona programowanie-pewnego dnia gettery i settery mogą być pomocne, a ich tworzenie/używanie nie kosztuje wiele. Więc czasami są przydatne.

W praktyce większość pól ma proste gettery i settery. Możliwe rozwiązanie wyglądałoby tak:

public property String foo;   
a->Foo = b->Foo;

Aktualizacja: jest bardzo mało prawdopodobne, że wsparcie właściwości zostaną dodane w Java 7 lub być może kiedykolwiek. Inne języki JVM, takie jak Groovy, Scala itp., obsługują teraz tę funkcję. - Alex Miller

 58
Author: Bartosz Bierkowski,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-07-10 16:58:39

Wydaje się, że wielu ludzi Javy nie zna wytycznych Sun Java Coding Guidelines które mówią, że jest całkiem właściwe użycie publicznej zmiennej instancji, gdy klasa jest zasadniczo "Struct", jeśli Java obsługuje "struct" (gdy nie ma żadnego zachowania).

Ludzie myślą, że gettery i settery to sposób Javy, jakby były sercem Jawy. Tak nie jest. Jeśli podążasz za słońcem Wytyczne dotyczące kodowania, z wykorzystaniem zmiennych instancji publicznych w odpowiednich sytuacjach, jesteś właściwie pisanie lepszego kodu niż zaśmiecanie go niepotrzebnymi geterami i seterami.

Konwencje kodu Javy z 1999 roku i nadal bez zmian.

10.1 zapewnienie dostępu do zmiennych instancji i klas

Nie upubliczniaj żadnej instancji ani zmiennej klasy bez ważnego powodu. Często zmienne instancji nie muszą być jawnie ustawiane ani uzyskiwane-często dzieje się to jako efekt uboczny wywołań metod.

Przykład odpowiednich zmiennych instancji publicznych jest to przypadek, w którym klasa jest zasadniczo strukturą danych, bez zachowania. innymi słowy, jeśli użyłbyś struktury zamiast klasy( jeśli Java wspierała strukturę), to właściwe jest utworzenie zmiennych instancji klasy publiczne.

Http://www.oracle.com/technetwork/java/javase/documentation/codeconventions-137265.html#177

Http://en.wikipedia.org/wiki/Plain_old_data_structure

Http://docs.oracle.com/javase/1.3/docs/guide/collections/designfaq.html#28

 265
Author: developer.g,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-05 06:20:42

Używaj zdrowego rozsądku. Jeśli masz coś takiego:

public class ScreenCoord2D{
    public int x;
    public int y;
}
Więc nie ma sensu owijać ich w getery i setery. Nigdy nie będziesz zapisywał współrzędnych x, y w całych pikselach w żaden inny sposób. Gettery i setery tylko cię spowolnią.

Z drugiej strony, z:

public class BankAccount{
    public int balance;
}

Możesz chcieć zmienić sposób obliczania salda w pewnym momencie w przyszłości. To naprawdę powinno używać getterów i seterów.

Zawsze lepiej wiedzieć dlaczego stosujesz dobre praktyki, aby wiedzieć, kiedy można nagiąć Zasady.

 214
Author: izb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-08-21 08:03:42

Aby rozwiązać problem zmienności, możesz zadeklarować x i y jako ostateczne. Na przykład:

class Data {
  public final int x;
  public final int y;
  public Data( int x, int y){
    this.x = x;
    this.y = y;
  }
}

Kod wywołujący, który próbuje napisać do tych pól, otrzyma błąd czasu kompilacji "pole x jest zadeklarowane jako ostateczne; nie można go przypisać".

Kod klienta może mieć wygodę "krótkiej ręki" opisaną w poście

public class DataTest {
    public DataTest() {
        Data data1 = new Data(1, 5);
        Data data2 = new Data(2, 4);
        System.out.println(f(data1));
        System.out.println(f(data2));
    }

    public int f(Data d) {
        return (3 * d.x) / d.y;
    }

    public static void main(String[] args) {
        DataTest dataTest = new DataTest();
    }
}
 47
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-15 03:58:41

[0] re: aku, izb, John Topley..

Uważaj na problemy z zmiennością...

Może wydawać się rozsądne pominięcie getterów/setterów. W niektórych przypadkach może być ok. Prawdziwym problemem z przedstawionym tu wzorem jest zmienność.

Problem polega na tym, że po przekazaniu odniesienia do obiektu zawierającego niekończące się, publiczne pola. Wszystko inne z tym odniesieniem może dowolnie modyfikować te pola. Nie masz już żadnej kontroli nad stanem tego obiektu. (Pomyśl co by się stało gdyby struny były mutowalne.)

Robi się źle, gdy ten obiekt jest ważną częścią wewnętrznego stanu innego, właśnie ujawniasz wewnętrzną implementację. Aby temu zapobiec, należy zwrócić kopię obiektu. Działa to, ale może powodować ogromne ciśnienie GC od Ton kopii jednorazowego użytku stworzonych.

Jeśli masz pola publiczne, rozważ utworzenie klasy tylko do odczytu. Dodaj pola jako parametry do konstruktora i oznacz je jako ostateczne. W przeciwnym razie upewnij się, że nie jesteś Wyświetlanie stanu wewnętrznego i jeśli musisz zbudować nowe instancje dla zwracanej wartości, upewnij się, że nie zostanie ona wywołana nadmiernie.

Patrz: "Effective Java" Joshuy Bloch -- Item #13: Favor Immutability.

PS: należy również pamiętać, że wszystkie JVMs w dzisiejszych czasach zoptymalizują getmethod, jeśli to możliwe, co skutkuje tylko jedną instrukcją odczytu pola.

 9
Author: Mark Renouf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 16:27:29

Nie używaj pól public

Nie używaj pól public, gdy naprawdę chcesz zawinąć wewnętrzne zachowanie klasy. Take java.io.BufferedReader na przykład. Ma ono następujące pole:

private boolean skipLF = false; // If the next character is a line feed, skip it

skipLF jest odczytywany i zapisywany we wszystkich metodach odczytu. Co jeśli zewnętrzna Klasa działająca w oddzielnym wątku złośliwie zmodyfikowała stan skipLF w środku odczytu? BufferedReader na pewno będzie siano.

Do use public fields

Weź tę Point klasę dla przykład:

class Point {
    private double x;
    private double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }

    public double getX() {
        return this.x;
    }

    public double getY() {
        return this.y;
    }

    public void setX(double x) {
        this.x = x;
    }

    public void setY(double y) {
        this.y = y;
    }
}

To sprawiłoby, że Obliczanie odległości między dwoma punktami byłoby bardzo bolesne do napisania.

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.getX() - a.getX(), 2) + Math.pow(b.getY() - a.getY(), 2));

Klasa nie posiada żadnych zachowań innych niż zwykłe gettery i settery. Dopuszczalne jest używanie publicznych pól, gdy klasa reprezentuje tylko strukturę danych i nie ma, i nigdy nie będzie miała zachowania (cienkie gettery i settery są tutaj uważane za zachowanie , a nie). Można to lepiej napisać sposób:

class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

Point a = new Point(5.0, 4.0);
Point b = new Point(4.0, 9.0);
double distance = Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
Czyste!

Ale pamiętaj: nie tylko twoja klasa musi być nieobecna w zachowaniu, ale także powinna mieć Nie powód, aby zachować się również w przyszłości.

 8
Author: Krumia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-06-08 06:21:49

Nawiasem mówiąc, struktura, którą podajesz jako przykład, istnieje już w bibliotece klas bazowych Java jako java.awt.Point. Ma x i y jako pola publiczne, Sprawdź to Sam .

Jeśli wiesz, co robisz, a inni w Twoim zespole wiedzą o tym, to dobrze jest mieć publiczne pola. Ale nie powinieneś na tym polegać, ponieważ mogą one powodować bóle głowy, jak w przypadku błędów związanych z deweloperami używającymi obiektów tak, jakby były strukturami przydzielonymi stosem (obiekty Javy są zawsze wysyłane do metod jako referencje, a nie kopie).

 7
Author: Spoike,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 14:24:06

Próbowałem tego w kilku projektach, na teorii, że gettery i settery zaśmiecają kod semantycznie bezsensownym cruft, i że inne języki wydają się dobrze radzić sobie z ukrywaniem danych w oparciu o konwencje lub dzieleniem obowiązków (np. python).

Jak inni zauważyli powyżej, są 2 problemy, które napotkasz, i nie są one naprawdę możliwe do naprawienia:

  • prawie każde zautomatyzowane narzędzie w świecie Javy opiera się na konwencji getter/setter. Ditto dla, jak zauważyli inni, tagi jsp, konfiguracja sprężyny, narzędzia eclipse, itp. itd... Walka z tym, czego oczekują Twoje narzędzia, to przepis na długie sesje trollingu przez google, próbując znaleźć niestandardowy sposób inicjowania fasolek wiosennych. Naprawdę nie warto się trudzić.
  • Gdy masz elegancko zakodowaną aplikację z setkami zmiennych publicznych, prawdopodobnie znajdziesz przynajmniej jedną sytuację, w której są one niewystarczające - w której absolutnie potrzebujesz niezmienności lub musisz Uruchom jakieś zdarzenie, gdy zmienna zostanie ustawiona, lub chcesz rzucić wyjątek na zmianę zmiennej, ponieważ ustawia stan obiektu na coś nieprzyjemnego. Następnie utkniesz z niewyobrażalnymi wyborami między zaśmiecaniem kodu jakąś specjalną metodą wszędzie tam, gdzie zmienna jest bezpośrednio odwoływana, mając specjalny formularz dostępu do 3 z 1000 zmiennych w aplikacji.

I to jest najlepszy scenariusz pracy w całości w samodzielnym prywatnym projekt. Po wyeksportowaniu całości do publicznie dostępnej biblioteki problemy te staną się jeszcze większe.

Java jest bardzo gadatliwa i jest to kusząca rzecz do zrobienia. Nie rób tego.

 7
Author: Steve B.,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-12-01 20:50:48

Jeśli sposobem Javy jest sposób OO, to tak, Tworzenie klasy z polami publicznymi łamie zasady dotyczące ukrywania informacji, które mówią, że obiekt powinien zarządzać własnym stanem wewnętrznym. (Więc nie mówię tylko żargonem na Ciebie, zaletą ukrywania informacji jest to, że wewnętrzne działanie klasy jest ukryte za interfejsem-powiedzmy, że chcesz zmienić mechanizm, za pomocą którego twoja klasa struct zapisała jedno z jej pól, prawdopodobnie będziesz musiał wrócić i zmienić wszelkie klasy, które nie będą w stanie tego zrobić . skorzystaj z klasy...)

Nie możesz również skorzystać ze wsparcia dla klas zgodnych z nazwami JavaBean, co zaszkodzi, jeśli zdecydujesz się, powiedzmy, użyć klasy na stronie JavaServer, która jest napisana w języku wyrażeń.

Artykuł JavaWorld Dlaczego metody Getter i Setter są złe Artykuł również może Cię zainteresować myśleniem o tym, kiedy nie implementować metod accessor i mutator.

Jeśli piszesz małe rozwiązanie i chcesz zminimalizować ilość kodu, sposób Javy może nie być właściwy - myślę, że zawsze zależy od Ciebie i problemu, który próbujesz rozwiązać.

 4
Author: brabster,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 09:39:58

Nie ma nic złego w tego typu kodzie, pod warunkiem, że autor Wie są to struktury (lub transfery danych) zamiast obiektów. Wielu programistów Javy nie potrafi odróżnić dobrze uformowanego obiektu (nie tylko podklasy Javy).lang.Obiekt, ale true obiekt w określonej domenie) i ananas. Ergo, kończą pisząc struktury, gdy potrzebują obiektów i viceversy.

 3
Author: luis.espinal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-15 02:59:08

Problem z używaniem public field access jest taki sam jak z używaniem nowej zamiast fabrycznej metody - jeśli później zmienisz zdanie, wszystkie istniejące wywołania zostaną uszkodzone. Tak więc, z punktu widzenia ewolucji API, zwykle dobrym pomysłem jest ugryźć kulę i użyć getterów / setterów.

Jednym z miejsc, gdzie idę w drugą stronę, jest sytuacja, gdy mocno kontrolujesz dostęp do klasy, na przykład w wewnętrznej statycznej klasie używanej jako wewnętrzna struktura danych. W tym przypadku może to być znacznie jaśniejsze aby skorzystać z dostępu do pola.

Przy okazji, przy twierdzeniu e-Bartka, jest bardzo mało prawdopodobne IMO, aby obsługa właściwości została dodana w Javie 7.

 2
Author: Alex Miller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-15 16:21:20

Często używam tego wzorca podczas budowania prywatnych klas wewnętrznych, aby uprościć mój kod, ale nie polecam wystawiania takich obiektów w publicznym API. Ogólnie rzecz biorąc, im częściej można uczynić obiekty w publicznym API niezmiennymi, tym lepiej i nie jest możliwe zbudowanie obiektu' przypominającego strukturę ' w sposób niezmienny.

Na marginesie, nawet gdybym pisał ten obiekt jako prywatną klasę wewnętrzną, nadal dostarczałbym konstruktor, który uprościłby kod i zainicjalizowałby obiekt. Posiadanie 3 linijek kodu, aby uzyskać użyteczny Obiekt, gdy ktoś to zrobi, jest po prostu niechlujne.

 2
Author: Kris Nuttycombe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-15 04:28:04

Bardzo-bardzo stare pytanie, ale pozwolę sobie na jeszcze jeden krótki wkład. Java 8 wprowadziła wyrażenia lambda i odniesienia do metod. Wyrażenia Lambda mogą być prostymi odniesieniami do metod i nie deklarować" prawdziwego " ciała. Nie można jednak "przekonwertować" pola na odniesienie do metody. Tak więc

stream.mapToInt(SomeData1::x)

Nie jest legalne, ale

stream.mapToInt(SomeData2::getX)

Jest.

 2
Author: Lyubomyr Shaydariv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-10 15:03:55

Nie widzę szkody, jeśli wiesz, że zawsze będzie to prosta struktura i że nigdy nie będziesz chciał się do niej przywiązać.

 1
Author: John Topley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 09:20:18

Jest to pytanie dotyczące projektowania obiektowego, a nie języka Java. Ogólnie dobrą praktyką jest ukrywanie typów danych w ramach klasy i ujawnianie tylko metod, które są częścią API klasy. Jeśli ujawnisz wewnętrzne typy danych, nigdy nie będziesz mógł ich zmienić w przyszłości. Jeśli je ukrywasz, Twoim jedynym obowiązkiem wobec użytkownika jest typ zwracania i argumentowania metody.

 1
Author: Jonathan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-08-31 10:13:01

Tutaj tworzę program do wprowadzania nazwy i wieku 5 różnych osób i wykonywania sortowania selekcji (wiek mądry). Użyłem klasy, która działa jako struktura (jak język programowania C) i klasy głównej, aby wykonać pełną operację. Poniżej przedstawiam kod...

import java.io.*;

class NameList {
    String name;
    int age;
}

class StructNameAge {
    public static void main(String [] args) throws IOException {

        NameList nl[]=new NameList[5]; // Create new radix of the structure NameList into 'nl' object
        NameList temp=new NameList(); // Create a temporary object of the structure

        BufferedReader br=new BufferedReader(new InputStreamReader(System.in));

        /* Enter data into each radix of 'nl' object */

        for(int i=0; i<5; i++) {
            nl[i]=new NameList(); // Assign the structure into each radix

            System.out.print("Name: ");
            nl[i].name=br.readLine();

            System.out.print("Age: ");
            nl[i].age=Integer.parseInt(br.readLine());

            System.out.println();
        }

        /* Perform the sort (Selection Sort Method) */

        for(int i=0; i<4; i++) {
            for(int j=i+1; j<5; j++) {
                if(nl[i].age>nl[j].age) {
                    temp=nl[i];
                    nl[i]=nl[j];
                    nl[j]=temp;
                }
            }
        }

        /* Print each radix stored in 'nl' object */

        for(int i=0; i<5; i++)
            System.out.println(nl[i].name+" ("+nl[i].age+")");
    }
}

Powyższy kod jest wolny od błędów i przetestowany... Wystarczy skopiować i wkleić do swojego IDE i ... Wiesz i co??? :)

 1
Author: Avik Kumar Goswami,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-02-19 09:36:07

Można utworzyć prostą klasę z publicznymi polami i bez metod w Javie, ale nadal jest klasą i jest nadal obsługiwana składniowo i pod względem alokacji pamięci tak jak Klasa. Nie ma możliwości autentycznego odtworzenia struktur w Javie.

 0
Author: cblades,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-10-15 04:35:09

Czasami używam takiej klasy, kiedy muszę zwrócić wiele wartości z metody. Oczywiście taki obiekt jest krótkotrwały i ma bardzo ograniczoną widoczność, więc powinno być OK.

 0
Author: PhiLho,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-23 18:43:14

Jak w większości rzeczy, jest ogólna zasada, a potem są konkretne okoliczności. Jeśli robisz zamkniętą, przechwyconą aplikację, aby wiedzieć, w jaki sposób dany obiekt ma być używany, możesz skorzystać z większej swobody, aby faworyzować widoczność i / lub wydajność. Jeśli tworzysz klasę, która będzie używana publicznie przez innych poza Twoją kontrolą, pochyl się w kierunku modelu getter / setter. Jak w przypadku wszystkich rzeczy, po prostu użyj zdrowego rozsądku. Często można zrobić pierwszą rundę z publikować, a następnie zmienić je na getter/setters później.

 0
Author: Evvo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-04-25 04:13:52

Programowanie zorientowane na aspekt pozwala przechwytywać zadania lub pobierać i dołączać do nich logikę przechwytywania, co proponuję jest właściwym sposobem rozwiązania problemu. (Kwestia, czy powinny być publiczne, chronione lub chronione pakietami, jest ortogonalna.)

W ten sposób zaczynasz od niezakceptowanych pól z odpowiednim kwalifikatorem dostępu. Wraz ze wzrostem wymagań programu dołączasz logikę, aby być może zweryfikować, wykonać kopię zwracanego obiektu itp.

The getter / setter filozofia nakłada koszty na dużą liczbę prostych przypadków, w których nie są one potrzebne.

Czy styl aspektowy jest czystszy, czy nie, jest nieco jakościowy. Łatwo byłoby zobaczyć tylko zmienne w klasie i zobaczyć logikę oddzielnie. W rzeczywistości, raison d ' etre dla programowania zorientowanego na Apect jest to, że wiele problemów jest przekrojowych i dzielenie ich w ciele klasy nie jest idealne (logging jest przykładem -- if you want to log all gets Java wants you to write a cała masa getterów i utrzymanie ich w synchronizacji, ale AspectJ pozwala na jednoliniowy).

Problem z IDE to red-herring. To nie tyle typowanie, co czytanie i wizualne zanieczyszczenie, które powstaje z get / sets.

Adnotacje na pierwszy rzut oka wydają się podobne do programowania zorientowanego na aspekt, jednak wymagają wyczerpującego wyliczenia punktów poprzez dołączenie adnotacji, w przeciwieństwie do zwięzłej specyfikacji pointcut w AspectJ.

I hope świadomość AspectJ uniemożliwia ludziom przedwczesne osiedlenie się na dynamicznych językach.

 0
Author: necromancer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-19 19:02:53