niedziela, kwietnia 23, 2017

Airly + Python + Oczyszczacz Powietrza = lepsze oddychanie ;-)

W Krakowie powstaje genialny produkt zwany Airly, który pokazuje w real time poziom zanieczyszczenia powietrza.
Ostatnio szerzej otworzyli swoje API. Co mnie ucieszyło, bo chociaż mają genialną apkę na Androida to chciałem mieć możliwość napisania sobie skryptu, który w momencie osiągnięcia odpowiednio wysokiego poziomu zanieczyszczenia wysyłał by mi maila z sugestią włączenia oczyszczacza powietrza (najlepiej jakby go sam włączał, ale to jednak takie proste nie jest ;-)).

Chciałem, to mam ;-)

import urllib2
import json
import os
import string
import sendmail

ALERT_LEVEL = 40
MAIL_TO = "<MAIL>"
apikey = "<APIKEY from https://apiportal.airly.eu/>"
url = "https://airapi.airly.eu/v1/mapPoint/measurements?latitude=<yourLatitude>&longitude=<yourLongitude>"
prevCaqi = 0
if os.path.exists("prevCaqi.txt"):
prevCaqi = float("".join(open("prevCaqi.txt").readlines()))

req = urllib2.Request(url)
req.add_header('apikey', apikey)
resp = urllib2.urlopen(req)
content = resp.read()

data=json.loads(content)

caqi = float(data["currentMeasurements"]["airQualityIndex"])

open("prevCaqi.txt","w+").write(str(caqi))

if prevCaqi<ALERT_LEVEL and caqi>=ALERT_LEVEL:
content = string.Template("""Current CAQI: $airQualityIndex
pm25: $pm25
pm10: $pm10
pollution level: $pollutionLevel
pressure: $pressure
humidity: $humidity
temperature: $temperature""").safe_substitute(data["currentMeasurements"])
sendmail.sendEMail(MAIL_TO,"Turn on AirCleaner",content)


Żeby działał ten skrypt trzeba mieć swój klucz do API, który idzie pod apikey. Trzeba ustawić też maila w MAIL_TO i długość i szerokość geograficzną (które można sobie odczytać np. używając mojego toola do wyliczania czasu wschodu i zachodu słońca ;-)).
Jeszcze trzeba mieć moduł sendmail, który można znaleźć w moim wpisie o tym jak nie zapomnieć o kupnie biletu miesięcznego ;-)


Podobne postybeta
Raspberry Pi + no-ip.org ;-)
Jak nie zapomnieć kupić biletu miesięcznego - revised ;-)
Jak nie zapomnieć kupić biletu miesięcznego ;-)
Jak się dowiedziałem o tym, że w Polsce rusza Google Play Movies ;-)
Polowanie na Nexus 4 - wersja automagiczna ;-)

czwartek, kwietnia 20, 2017

Z Nexusów do Pixeli

Jakiś czas temu w tabletach przeszedłem z Nexusa 10 na Pixela C.
Wczoraj zaś zrobiłem to w telefonach. Z Nexusa 6 na Pixela XL.

Czuć różnicę.
Nexusy są fajne, ale tam celem było zrobienie dobrych urządzeń w rozsądnej cenie.
Pixele mają inny cel, to mają być pełnoprawne flagshipy w nierozsądnej cenie ;-)

I takie są ;-)

Jakość wykonania jest dużo wyższa niż w przypadku Nexusów.

Wszystko też jest straszliwie szybkie (chociaż to akurat wynik wieku urządzeń).

Jedyną wadą dla mnie Pixela XL w porównaniu do Nexus 6 jest to, że jednak telewizor w Pixelu XL to tylko 5.5 cala, a nie 5.96 z Nexusa 6.

Ale za to aparat i cała reszta są dużo lepsze.

posted from Bloggeroid




Podobne postybeta
Uspokajacz
Pixel C - dobry
Przemek w krainie Stefanów ;-)
I znów widziałem The Internship :-)
Jak oceniasz swoje bezpieczeństwo? - podsumowanie

środa, kwietnia 19, 2017

"Zestaw inspektora" się tworzy ;-)

Powoli, acz skutecznie, zaczynam wykorzystywać inspekcje w IntelliJ'u do pilnowania kodu przed różnymi dziwnymi błędami.
Dziś sobie dodałem taką inspekcję, która płacze gdy używamy gdzieś bezpośrednio liczb jako indeksów w tablicach, albo listach ;-)

Od teraz mi IntelliJ tak płacze jak coś takiego zobaczy:


Chodzi mi po głowie by sobie zrobić "zestaw inspektora", coś co by mi podkreślało wszystkie code smells'y z mojej "listy" inspekcyjnej.
Chociaż dobrze by było by takie coś działało w toolu do inspekcji, a nie w IDE, bo w IDE tylko ja z tego skorzystam, a mimo wszystko zwykle jak robię inspekcję to nie robię clone'a czy checkout'u kodu.
Niby tak, są jakieś toole do analizy kodu, ale one są zwykle do poprawy jakości kodu, a nie do np. wskazywania podejrzanie trefnych miejsc w trakcie inspekcji ;-)
Idealnie byłoby mieć skrypt, który tworzyłby listę komentarzy do inspekcji i sam mógłbym skupić się na podejrzanych miejscach ;-)
Chociaż nie ma pewności, że to by było dobre, mogłoby ukrywać bardziej subtelne problemy.


Podobne postybeta
Walka z null'em - pozwólmy działać IntelliJ'owi ;-)
Distinct (albo unique) w JavaScript
MS Nieszczęście 8 - psujemy...
Nie lubię oszustów.
Ewolucja Buzz Troll Remover'a ;-) - czyli nad czym teraz pracuję

wtorek, kwietnia 18, 2017

Rule w Outlook = ZUO

Mój stosunek do oprogramowania Microsoftu jest negatywny.
Poza Windowsem i MS Paintem nie udało im się w mojej ocenie nigdy wypuścić kawałka dobrego softu.

Każdy kontakt z ich softem utwierdza mnie tylko w tym przekonaniu ;-)

W firmie używamy Outlooka 365 i MS Office'a. Poczta jest przez Outlooka.

Nie używam klienta desktopowego bo jest słaby, używam webowego. Który też jest słaby, ale chociaż nie robi mi "tadam" jak kalendarz ma na to ochotę.

Jak zacząłem pracę to zrobiłem sobie trochę reguł i zmniejszyła się liczba maili jakie musiałem czytać...
Niby fajnie, ale np. zniknęły zaproszenia na inspekcje kodu.
Nie widzę też maili, które zostały wysłane do kilku osób.

Nie wydaje się by maile te lądowały w jakimkolwiek katalogu, po prostu ich nie widać....

No to skasowałem wszystkie rule (pewnie okaże się, że jednak nie..) i zobaczymy czy zacznę odzyskiwać maile..

Outlook to ZUO!!!!


Podobne postybeta
Outlook zły
Metapost o tym co pisać jak nie mam pomysłów o czym pisać....
Deszczowy Niebieski Ząb ;-)
Jak Henryk VIII i Dynastia Tudorów uczy, że demokracja is the best! ;-)
CVS "złamany" :-)

niedziela, kwietnia 16, 2017

Walka z null'em - pozwólmy działać IntelliJ'owi ;-)

Jakiś czas temu pisałem o tym, że chciałbym stworzyć wtyczkę do IntelliJ, która pozwoliłaby mi unikać pisania kodu z null'ami.

Nie zacząłem jeszcze nawet, ale od paru dni stosuję coś co robi za MVP (Minimal Viable Product) takiej wtyczki ;-)

Stworzyłem sobie w IntelliJ inspekcję, która podkreśla mi na czerwono KAŻDE użycie null'a ;-)


Wydaje się, że spełnia swoje podstawowe zadanie, czyli zwraca moją uwagę na użycia null'a ;-)

Zaryzykuję stwierdzenie, że na razie działa to tak dobrze, że chyba porzucę plany pisania wtyczki.

Jak ktoś ma ochotę się pobawić to są dwa sposoby ;-)

Prostszy ;-) pobieramy ten plik, uruchamiamy IntelliJ Idea, w menu File wybieramy Import Settings (File -> Import Settings) i szukamy pliku stopNull.jar, który właśnie pobraliśmy.
Oczom naszym ukazuje się dialog:


 Klikamy OK, restartujemy IntelliJ i voilà od teraz IntelliJ nam będzie podkreślał na czerwono null'e ;-)

Trudniejsza droga, acz pozwalająca się więcej nauczyć wygląda zaś tak:
1) idź do ustawień IntelliJ (np. Shift-Shift i piszemy Settings)
2) idź do ustawień Inspekcji:

3) Wybierze General -> Structural Search Inspection:

4) w Options dodaj nową (zielony +, albo po prostu Alt-Insert (przynajmniej na Ubuntu), u Ciebie na razie nie będzie Used null ;-))

5) Add Search Template:

6) Wpisz template (u nas po prostu null jak na obrazku ;-)):

7) nazwij swój template:
8) OK
9) voilà masz nową inspekcję ;-)

Dobrze jeszcze zaznaczyć jej severity na Error by podkreślała się jako błąd.

W taki sposób można dodawać różne nowe inspekcje, które pozwolą poprawić jakość naszego kodu :-)

Testowane na IntelliJ Idea 2017.1 i IntelliJ 15.


Podobne postybeta
"Zestaw inspektora" się tworzy ;-)
SleepAdvisor - komórka pomaga w wyspaniu się ;-)
Walka z null'em ;-)
Selfhacking ;-)
Naprawdę nienawidzę...

wtorek, kwietnia 11, 2017

Sztuczki tropiciela błędów - breakpoint na sterydach ;-)

Breakpoint to dobry przyjaciel tropiciela błędów.

Zatrzymuje wykonanie kodu (zwykle danego wątku) gdy napotka zaznaczony kawałek kodu, albo gdy poleci Exception, albo gdy zostanie zawołana jakaś metoda (strasznie wolne!).

Ale czasem chcielibyśmy mieć jakąś kontrolę nad tym zatrzymywaniem, bo np. nie chcemy by nam się kod zatrzymywał przy każdym wejściu do metody, ale tylko w pewnych warunkach.

Do tego mamy w InteliJ Idea i w Eclipse (a i w innych też) warunki aka conditiony dla breakpointów.
Zwykle są w stylu:

param==1
"specialCase".equals(text)

i podobne.
Czasem chcielibyśmy jednak czegoś lepszego ;-)

Ja ostatnio zapragnąłem by mi się zatrzymywał kod tylko gdy na stosie wywołań nie ma pewnej metody.
Chodziło o to, że już wiedziałem co przychodzi z tego miejsca, chciałem zobaczyć inne przypadki bez trzymania F9.

Najpierw spróbowałem użyć strumieni i lambd:

java.util.Arrays.stream(new Throwable().fillInStackTrace().stackTrace)
     .noneMatch(x -> "getWorker".equals(x.getMethodName()))

Czyli chciałem by warunek wystąpił gdy na StackTrace'ie nie będzie żadnej metody o nazwie getWorker.

Niestety IntelliJ poinformował mnie, że sorry Winnetou, ale lambd się nie da używać w warunkach breakpointa...

To stworzyłem sobie taką klasę ;-)

import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;

public class Terminator {

  public static boolean terminateIfNotCalledFrom(String... methodsNames) {
    Throwable t = new Throwable();
    t.fillInStackTrace();
    Set<String> methods = Arrays.stream(methodsNames).collect(Collectors.toSet());
    return Arrays.stream(t.getStackTrace()).noneMatch(x -> methods.contains(x.getMethodName()));
  }

  public static boolean terminateIfCalledFrom(String... methodsNames) {
    Throwable t = new Throwable();
    t.fillInStackTrace();
Set<String> methods = Arrays.stream(methodsNames).collect(Collectors.toSet()); return Arrays.stream(t.getStackTrace()).anyMatch(x -> methods.contains(x.getMethodName())); } }

Która to klasa dostarcza 2 metody statyczne, których możemy użyć w warunku:


I teraz kod zatrzymuje mi się tylko gdy osiągnęliśmy dany breakpoint nie przechodząc przez metody o nazwach, które przekazujemy w parametrze ;-)

Tropienie błędów staje się w takim przypadku dużo ciekawsze ;-)


Podobne postybeta
Sztuczki tropiciela błędów ;-)
Sztuczki tropiciela błędów, part 2 ;-)
Niecne wykorzystanie refleksji... czyli jak poszukać tekstu w drzewie obiektów? ;-)
Sztuczek Java'owy
Deklaratywnie czy imperatywnie... oto jest pytanie ;-)

sobota, kwietnia 08, 2017

Journaling

W końcu przeczytałem Search Inside Yourself.
Zajęło mi to tylko 4.5 roku ;-) z tym, że 4.5 roku temu doczytałem do 1/3, a ostatnio od początku do końca.

I opisano tam journaling. Chytrą technikę do odczytywania własnych stanów, myśli i marzeń.
Dopiero po takim journalingu do mnie dotarło, że mój ulubiony dowcip "Co znaczy wegetarianin po indiańsku? Za głupi by polować" nie jest aż taki zabawny (tzn. nadal mnie bawi, ale bezpiecznie może powiedzieć ten dowcip tylko ktoś kto nie uważa wegetarian za szaleńców, a raczej ktoś kto ich prawie podziwia i to w sytuacji gdy odbiorcy znają poglądy tego mówiącego... ogólnie powinni mówić ten dowcip tylko wegetarianie :-)).

A już wersja journalingu w którym piszemy z pozycji "za 5 lat" jest w ogóle potężna... i trudna.

Chodzi o to, że mamy przez jakiś czas (u mnie 5 minut) pisać tak jakbyśmy byli 5 lat od teraz i mamy opisać nasze życie, czym się zajmujemy, gdzie mieszkamy, jak wygląda nasza rodzina i tak dalej.

To mi uświadomiło, że właściwie nie wiem co chcę robić ;-)

Robię to co robię, ale głównie radochę mam w momentach gdy tak trochę obok swojej pracy robię jakieś dziwne narzędzia czy usprawnienia.
Radość sprawia mi nie tyle kodowanie, a nietypowe rozwiązywanie problemów ;-)

Stąd jak masz 5 minut, to wylosuj sobie liczbę od 1 do 11, otwórz notatnik i zależnie która liczba wypadła napisz:
1) czuję teraz...
2) jestem świadom(a)...
3) tym co mnie motywuje jest...
4) dziś pragnę/dążę do....
5) boli mnie...
6) chciałbym/chciałabym...
7) inni są...
8) wbrew temu co chciałem/chciałam, szczęśliwie stało się że...
9) moje wartości to...
10) popieram...
11) przy założeniu, że wszystko się udaje za 5 lat będę... (pisać jakby się pisało za te 5 lat, czyli w czasie teraźniejszym)

Teraz przez 5 minut pisz kontynuację tych pierwszych słów :-)

Jak nic nie przychodzi do głowy to pisz o tym, że nic do głowy nie przychodzi, a jak się coś pojawi, to niezależnie czy ma związek z pytaniem pisz. Czasem trzeba przetestować pomysły, a ich napisanie to dobry test.

Wychodzi na to, że konieczność napisania przepuszcza myśli przez te części umysłu, które muszą to ubrać w słowa i nazwać uczucia, pragnienia czy pomysły.
A jak coś umiemy nazwać to mamy metody do wpływania na to.

Przynajmniej u mnie to działa :-)


Podobne postybeta
Wegetarianizm kaizen - czyli ja bywać wegetarianinem bez zbytniego wysiłku ;-)
Samochód jako zmniejszacz temperatury.... GC i jak to możliwe, że Young Generation może być zbyt duże, strzeż się finalize() i muzyczka :-) Czyli potok świadomości....
Śmierdząca ryba wolności ;-)
Google Talk i herbata... eksperyment ;-)
Dalsze śledzenie geolokalizacji Google'a :-)

czwartek, kwietnia 06, 2017

Z jednej strony ludzie żyją dłużej i lepiej, z drugiej "upadek moralny"... to co w tym "upadku" złego?

Politycy PiS oderwali się już od rzeczywistości.
Posłanka PiS Anna Sobecka wygłosiła w Sejmie słowa o upadku moralnym Europy przez "porzucanie chrześcijaństwa".

OK...
Oczekiwana długość życia mieszkańców Europy rosła przez cały XX wieku i wszystkie lata XXI wieku.
Nawet I i II Wojna Światowa w których zginęło kilkadziesiąt milionów ludzi były tylko chwilowymi spadkami na krzywej.
W całym XX wieku średnia oczekiwana długość życia wzrosła o jakieś 30 lat.
Umieralność noworodków spada.
Szanse na śmierć lub rany w wyniku przemocy ze strony innych ludzi spadają.
Szanse na śmierć lub rany w wyniku działań wojennych spadają.

Dziś mieszkaniec Europy ma kilkadziesiąt większe szanse umrzeć z powodu otyłości niż przez to, że go ktoś zabije.

To jeśli mamy upadek moralny Europy i pewnie świata jak twierdzi Pani poseł Anna Sobecka, który jest spowodowany odwrotem od wartości chrześcijańskich... to mam pytanie...
Co w tym do k... nędzy złego? Skoro ludzkość jako taka zyskuje?


Podobne postybeta
Historia +1
Full Screen w Chrome :-)
"Cywlizacja białego człowieka" - WTF?
HP7 bez manifestu ;-)
POpulizm

środa, marca 29, 2017

Pensje programistów

Wczoraj Wyborcza pisała o zarobkach programistów i o tym, że zarabiają oni więcej od lekarzy (przynajmniej młodych).

Jestem programistą i też mnie to bulwersuje, zyskuję na tym, ale nadal mnie to jednak bulwersuje.

Wydaje mi się jednak, że rozumiem mechanizm, który za tym stoi.

To, że lekarz czy policjant w Polsce zarabiają mniej niż programista wynika z tego, że pensja lekarza czy policjanta jest w jakimś związku z pensjami reszty mieszkańców kraju.
To dotyczy też większości innych zawodów. Bo klientami są ludzie mieszkający w tym samym kraju.

W przypadku programistów tak nie jest.

Klienci żyją często nie tylko w innym kraju, ale i na innym kontynencie, albo żyją na całym świecie.

Liczba ludzi, którzy są w stanie skończyć medycynę jest ograniczona, co powinno podnosić pensję, ale swoje usługi lekarze wykonują lokalnie i z góry cena za ich pracę jest ograniczona tym co będą w stanie zapłacić klienci na miejscu.

Liczba ludzi, którzy są w stanie pracować jako programiści też jest ograniczona, jest pewnie kilkukrotnie większa od liczby potencjalnych lekarzy, ale nadal jest ograniczona.
Ich praca czy efekty ich pracy nie są dostępne jednak tylko lokalnie, ale i globalnie. Stąd lokalne warunki tak bardzo nie ograniczają pensji.

Niby tutaj powinna działać zasada, że drogich programistów powinni zastępować tańsi z tańszych krajów... ale ogólnie programistów brakuje na całym świecie.

To co tworzą programiści, czyli oprogramowanie w ogólności służy do "zabierania ludziom pracy albo czasu".
Może 100 USD miesięcznie za aplikację do księgowania to dużo, ale z drugiej strony jeśli dzięki temu nie trzeba zatrudniać kogoś do fakturowania to i tak oszczędza się całkiem sporo kasy.

Czyli firmy/klienci bardzo chcą oprogramowania, bo to pozwala im na oszczędzanie pieniędzy, są więc w stanie płacić duże pieniądze za to oprogramowanie.
A ktoś je musi tworzyć.  Stąd jest duże ssanie na programistów i ceny ich pracy rosną.
Jak firma nie jest w stanie znaleźć programistów to zaczyna szukać po świecie i w końcu otwiera biuro gdzieś zagranicą, gdzie na dodatek może płacić mniej niż u siebie (co nie jest AŻ tak istotne).
Żeby ściągnąć szybko ludzi daje wyższe stawki niż okolica... ale w okolicy też potrzeba programistów bo przecież ta firma nie jest jedyną, która wpadła na pomysł otworzenia biura zagranicą.... czyli wkrótce wszyscy w koło podnoszą pensje programistów bo wszystkim to się opłaca.

Górną granicą jest tak naprawdę albo to ile płaci się programiście "w domu", albo zysk jaki z softu się czerpie.

Stąd wnoszę, że pensje w IT będą jeszcze rosły.... a że jak na razie nie widać końca zapotrzebowania na oprogramowanie to pewnie potrwa to jeszcze długo.
No chyba, że ktoś osiągnie sukces budując oprogramowanie, które zastąpi programistów.
Do tego jednak jeszcze sporo brakuje.


Podobne postybeta
MS Nieszczęście 8 - psujemy...
Złudne poczucie bezpieczeństwa...
Dobór naturalny, albo my
Płatnik czy beneficjent?
Java, JavaScript, Python, C++, C#? co ma przyszłość? 7 lat później ;-)

wtorek, marca 28, 2017

Referencje w Java'ie

Wychodzi na to, że wiele osób daje się zwieść temu, że w Java'ie część rzeczy jest przekazywana przez referencję, a część przez wartość.

Zacznijmy od tego co jest przez co przekazywane, później powiemy co to znaczy, że jest przekazywane i w końcu jak to sobie można wyobrazić.

W Java'ie wszystkie obiekty są przekazywane przez referencję, a wszystkie wartości proste aka prymitywy przez wartość*.

Co to znaczy?

Gdy mamy kod:
1. void doSth(MyType obj) {
2.   obj.field=7;
3.   obj = new MyType();
4. }
/.../
5. MyType obj = new MyType();
6. doSth(obj);
7. MyType obj2 = obj;
8. print(obj2.field);

w linii 5 zostaje stworzony nowy obiekt, a referencja do niego zostaje zapisana do zmiennej obj.
W linii 6 referencja ta zostaje przekazana do metody doSth().

Obiekt w linii 5 jest tworzony gdzieś** w pamięci.
Operator new zwraca referencję do obiektu.
Referencja jest liczbą, która mówi o który obiekt chodzi.
W najprostszym przypadku jest to adres obiektu w pamięci, chociaż w Java'ie lepiej myśleć o tym jako o indeksie w tablicy w której trzymamy fizyczne adresy obiektów (tak to kiedyś było zaimplementowane i robiło GC prostszym).

Najprościej wyobrazić to sobie można następująco (to nie działa w taki sposób bo JVM jest maszyną stosową, a nie rejestrową, ale model mentalny można taki mieć ;-)).

Gdy tworzony jest nowy obiekt to JVM decyduje gdzie się on znajdzie i adres tego nowo utworzonego obiektu zwraca i zapisuje w zmiennej obj.
Zapisanie w zmiennej oznacza w JVM albo zapisane tego "adresu" gdzieś w "rejestrze" albo na stosie.
Gdy w linii 6 przekazujemy obj do metody doSth() to przekazujemy "adres" do obiektu, nie sam obiekt. Nie robimy kopi obiektu, obiekt jest nadal w tym samym miejscu pamięci gdzie był po wykonaniu linii 5.
Metoda doSth() coś sobie robi na tym obiekcie w linii 2. Zapisuje w obiekcie wskazanym przez adres z "obj" bity które są identyfikowane jako liczba 7***.
W linii 3 robi się coś dziwnego, tworzony jest nowy obiekt, który zostaje stworzony w jakimś nowym miejscu niż nasz pierwszy obiekt. Do zmiennej lokalnej obj zostaje zapisany ten nowy adres.
Tu warto się zatrzymać i wrócić ;-) Do tej linii w obj był "adres" obiektu stworzonego w linii 5. Jednak w linii 3 przypisujemy do tej zmiennej adres nowego obiektu. Java robi tu trick, w linii 2 obj.field mówi "pole o nazwie field obiektu, który znajduje się pod adresem zapisanym w obj", w linii 3 samo obj to po prostu zmienna lokalna (rejestr, miejsce w pamięci) w której zapisujemy adres nowego obiektu.
Kończymy metodę doSth(). Zmienna obj w metodzie doSth() przestaje istnieć. Nie ma więc nikogo kto trzyma "adres" obiektu z linii 3. Obiekt ten może zostać poddany działaniu GC.
Jesteśmy w linii 7. Do nowej zmiennej lokalnej zapisujemy "adres" obiektu z linii 5.
W linii 8 chcemy wypisać wartość pola o nazwie field spod adresu przechowywanego w obj2.
Jest to pole o nazwie field obiektu stworzonego w linii 5, a jego wartość to 7 co jest wynikiem linii 2.

Tu dygresja do assemblera i fizycznego komputera ;-)

Pamięć komputera to w uproszczeniu 1 linia komórek pamięci.
Pierwsza komórka ma numer 0, druga 1 i tak dalej.

Adres to numer komórki. Adres pod którym znajdują się jakieś dane to numer komórki w pamięci od której te dane się zaczynają.

Referencja to właśnie taki adres pierwszej komórki pamięci gdzie znajduje się obiekt......

OK, tak to sobie można wyobrazić i tak to wygląda w wielu JVM, ale w naszym modelu mogłoby powstać pytanie, że jeśli to tak działa to jak działa GC, który może przenosić obiekty. Przecież wtedy adresy też się powinny zmieniać.
Stąd u nas referencja to tak naprawdę indeks w tablicy z adresami.

Jeśli mamy 5 obiektów to ta tablica wygląda jakoś tak:
{0x0000,0x00FA,0x1100,0x11FE,0xEE07}
Gdzie te liczby to adresy pamięci gdzie jest obiekt.
Wtedy referencja do obiektu pod adresem 0x00FA będzie miała wartość 1 i będzie wskazywała na element z indeksem 1****...

To referencje z grubsza mamy.
Widzimy, że "przekazywane obiektu przez referencję" to po prostu przekazane "adresu" do obiektu.

W przypadku typów prostych mamy przekazywanie przez wartość.

Znaczy to tylko tyle, że JVM trzyma w pamięci bajty, które dla danego typu oznaczają jakąś tam wartość. Gdy przekazujemy taki typ to JVM po prostu kopiuje bajty.

Gdy kod wygląda tak:
1. void doSth(int i) {
2.   print(i);
3.   i++;
4.  print(i);
5. }
/.../
6. int number = 7;
7. doSth(number);
8. print(number);

To w linii 7 JVM wkłada do zmiennej bajty, które są równe liczbie 7. To wkładanie do zmiennej to zapisanie tej liczby 7 do "rejestru" albo na stosie.
W linii 7 JVM kopiuje te bajty i przekazuje je do metody doSth. Tutaj zwykle przez zapisanie na stosie, a metoda doSth sobie je ze stosu pobierze.
W linii 2 JVM kopiuje te bajty i przekazuje do metody print, która je sobie wypisuje. (znów przez stos).
W linii 3 JVM zmienia "i" na zmienianą wartość... Wartość w rejestrze jest zwiększana o 1, albo ta ze stosu zdejmowana, zwiększana o jeden i znów zapisywana.
W linii 4 JVM znów zapisuje wartość ze zmiennej (rejestru) na stos i przekazuje tak do metody print...
Jesteśmy znów w linii 8.
Nasza wartość 7 z linii 6 jest przechowywana w "rejestrze" i nie została zmieniona w doSth (tam pracowaliśmy na kopi). Ta wartość jest zapisywana na stosie i przekazywana tak do print, które wypisze 7....

Jeśli to nie jest jeszcze jasne to popatrzmy na to jak to działa w normalnym komputerze.
Mamy procesor, który to procesor ma rejestry, w rejestrach może trzymać liczby.
Liczba ta może być wartością i wtedy np. chcąc dodać 1 do 2, ładujemy do jednego rejestru 1, do drugiego 2 i później w pierwszym umieszczamy wynik dodawania wartości rejestrów.
Możemy jednak też trzymać w rejestrze adres miejsca w pamięci gdzie jest wartość 1, a w drugim rejestrze adres miejsca pamięci gdzie jest liczba 2.
Teraz dodając dwie liczby zrobimy inaczej, najpierw do jeszcze jednego rejestru procesor wciągnie to co jest w pamięci pod adresem zapisanym w pierwszym rejestrze, do kolejnego rejestru wciągnie to na co wskazuje 2 rejestr, zrobi dodawanie i w końcu zapisze wynik pod adres zapisany w pierwszym rejestrze.... tak z grubsza ;-)

W przypadku referencji od strony bebechów JVM kod wygląda tak:

       0: new           #2                  // class MyType
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: aload_1
      10: invokevirtual #4                  // Method doSth:(LMyType;)V
      13: return

W linii 0 JVM tworzy nowy obiekt, czyli rezerwuje gdzieś pamięć, tworzy tam struktury takie jak pola i im podobne. Po stworzeniu obiektu umieszcza jego "adres" na stosie.
W linii 3 wartość "adresu" ze stosu jest kopiowana i zapisywana ponownie na stosie (mamy tam więc 2 razy tą samą wartość "jedna nad drugą").
Teraz w linii 4 wywoływana jest metoda <init> z naszego nowego obiektu. Invokespecial odczytuje wartość "adresu" obiektu ze stosu, sprawdza jaki to jest obiekt, wpisuje tą wartość do "this", zapisuje na stosie adres następnego rozkazu i skacze pod adres gdzie znajduje się metoda <init>.
Metoda <init> korzystając z adresu w referencji (czyli w this) wypełnia przygotowane w linii 0 pola wartościami. Gdy skończy pobiera wartość ze stosu z adresem następnego rozkazu (został tam odłożony w momencie wołania invokespecial), i wraca do linii 7.
W linii 7 składuje wartość referencji (która jest na stosie nadal, dzięki linii 3) w zmiennej lokalnej 1. To jest odpowiednik przypisania do zmiennej obj.
W linii 8 wartość zmiennej 1 (takiego "rejestru") jest zapisywana na stosie (który to już raz...).
W linii 8 robimy to samo.
W 10 wykonujemy invokevirtual, które to invokevirtual zdejmuje wartość ze stosu, zagląda do obiektu, ustala jego typ, teraz w tabeli metod wirtualnych szuka najbardziej szczegółowej metody doSth, zapisuje na stosie miejsce do którego ma wrócić, skacze do kodu metody wirtualnej, jeszcze przed tym w this zapisuje adres obiektu stworzonego w 0......
Po zakończeniu metody doSth ze stosu odczytywany jest adres miejsca gdzie trzeba wrócić, i skaczemy do linii 13.....

Reasumując (jak ktoś aż tutaj dotarł ;-)).
W Java'ie można sobie wyobrazić, że zmienna trzyma bajty. Powiedzmy dla uproszczenia, że jest to zawsze 8 bajtów.
Jeżeli w kodzie używamy typu prostego to bajty te to wartość tego typu prostego.
Jeżeli w kodzie używamy obiektu, to bajty "trzymane w zmiennej" to wartość referencji, czyli "adres" obiektu w pamięci.
Jeżeli przekazujemy taką zmienną do innej metody to te bajty są kopiowane i metoda dostaje swoją własną kopię tych bajtów. A kod metody wie czy opisują one wartość typu prostego, czy "adres" obiektu.
Gdy przypisujemy coś do zmiennej to kopiujemy bajty z prawej strony na lewą, jeśli to jest typ prosty to kopiujemy w tych bajtach wartość, jeśli to obiekt to kopiujemy wartość "adresu".

Przez to przekazywanie obiektów przez referencję (czyli kopiowanie dla metody bajtów z "adresem") może w JVM dochodzić do wycieków pamięci. Bo JVM liczy ile jest referencji do danego obiektu i póki ta liczba jest większa niż 0 to obiekt będzie trzymany w pamięci. Przez to wystarczy gdzieś zakitrać sobie referencję do obiektu i może ona nam siedzieć w pamięci po wsze czasy, chociaż jest nam nie potrzebna.
Możemy np. wrzucić taką referencję do HashMap'y z jakimś cache'm, wszystkie inne referencja poza tą z mapy mogą już dawno nie żyć, obiekt może nie być potrzebny, ale nadal będzie w pamięci siedział bo HashMap'a trzyma doń referencję (czyli bajty z "adresem").

I to by było na tyle ;-)

[Disclaimer: to wszystko wyżej są pewne uproszczenia by można sobie to było wyobrazić, wiele z tych rzeczy zależy od implementacji JVMa]

* - tak naprawdę naprawdę ;-) ZAWSZE kopiowane są bajty, z tym że w przypadku typów prostych, jak int, long, byte, short, etc JVM interpretuje te bajty jako wartość. Np. bajty 0x0007 (czyli 2 bajty, pierwszy o wartości 0, a drugi 7) dla typu char zostaną zinterpretowane przez JVM jako znak 7.
Jeżeli jest to referencja to JVM kopiuje bajty z "adresem" obiektu. Jeśli te bajty to 0x0007 (naprawdę mamy tutaj zwykle 4 albo 8 bajtów, nie dwa) to tym razem zostanie to zinterpretowane przez JVM jako adres 0x0007, co może oznaczać komórki pamięci od adresy 7, albo 7 indeks w tablicy, albo jeszcze 7*8 bajtów, to już zależy od JVMa, ale to coś pozwala znaleźć miejsce w pamięci gdzie jest nasz obiekt.
** - najpewniej w Edenie, ale to nie jest tak istotne, ważne że prawie zawsze gdzieś na stercie
*** - i niepostrzeżenie zrobiliśmy tutaj kopiowanie wartości, bo to typ prosty jest.
**** - może to być też wartość 5, jako numer bajtu od którego zaczyna się adres. To są już szczegóły implementacji danej JVM.


Podobne postybeta
Refleksje i serializacja w Java'ie - podstawy i obalanie mitów ;-)
clone() i Cloneable się mszczą ;-)
Java 8 nadchodzi....
Klasa statyczna - ki diabeł?;-)
Sztuczki tropiciela błędów, part 2 ;-)