JavaRush /Blog Jawa /Random-JV /Perbandingan obyek: laku
articles
tingkat

Perbandingan obyek: laku

Diterbitake ing grup
Iki minangka artikel nomer loro sing ditrapake kanggo mbandhingake obyek. Pisanan padha rembugan basis teori saka comparison - carane iku rampung, apa lan ing ngendi iku digunakake. Ing artikel iki kita bakal ngomong langsung babagan mbandhingake nomer, obyek, kasus khusus, subtleties lan TCTerms non-jelas. Luwih tepate, iki sing bakal kita bahas:
Perbandingan obyek: praktik - 1
  • Perbandingan string: ' ==' lanequals
  • MetodeString.intern
  • Perbandingan primitif nyata
  • +0.0lan-0.0
  • ArtineNaN
  • Jawa 5.0. Cara ngasilake lan mbandhingake liwat ' =='
  • Jawa 5.0. Autoboxing/Unboxing: ' ==', ' >=' lan ' <=' kanggo pambungkus obyek.
  • Jawa 5.0. perbandingan unsur enum (jinis enum)
Dadi ayo miwiti!

Perbandingan string: ' ==' lanequals

Ah, garis-garis iki ... Salah sawijining jinis sing paling umum digunakake, sing nyebabake akeh masalah. Ing asas, ana artikel kapisah bab wong-wong mau . Lan ing kene aku bakal ndemek masalah perbandingan. Mesthi, strings bisa dibandhingake nggunakake equals. Kajaba iku, kudu dibandhingake liwat equals. Nanging, ana subtleties sing worth ngerti. Kaping pisanan, senar sing identik minangka obyek tunggal. Iki bisa gampang diverifikasi kanthi mbukak kode ing ngisor iki:
String str1 = "string";
String str2 = "string";
System.out.println(str1==str2 ? "the same" : "not the same");
Asil bakal "padha" . Tegese referensi senar padha. Iki rampung ing tingkat compiler, temenan kanggo nyimpen memori. Compiler nggawe ONE conto saka senar, lan menehi str1referensi str2kanggo conto iki. Nanging, iki mung ditrapake kanggo senar sing diumumake minangka literal ing kode. Yen sampeyan nggawe senar saka potongan-potongan, link kasebut bakal beda. Konfirmasi - conto iki:
String str1 = "string";
String str2 = "str";
String str3 = "ing";
System.out.println(str1==(str2+str3) ? "the same" : "not the same");
Asil bakal "ora padha" . Sampeyan uga bisa nggawe obyek anyar nggunakake konstruktor salinan:
String str1 = "string";
String str2 = new String("string");
System.out.println(str1==str2 ? "the same" : "not the same");
Asil uga bakal "ora padha" . Mangkono, kadhangkala strings bisa dibandhingake liwat referensi comparison. Nanging luwih becik ora ngandelake iki. Aku pengin ndemek siji cara sing menarik banget sing ngidini sampeyan entuk perwakilan kanonik sing diarani senar - String.intern. Ayo dadi pirembagan bab ing liyane rinci.

Metode String.intern

Ayo dadi miwiti karo kasunyatan sing kelas Stringndhukung blumbang senar. Kabeh string literals ditetepake ing kelas, lan ora mung wong-wong mau, ditambahake menyang blumbang iki. Dadi, cara kasebut internngidini sampeyan entuk senar saka blumbang iki sing padha karo sing wis ana (sing diarani metode kasebut intern) saka sudut pandang equals. Yen baris kasebut ora ana ing blumbang, banjur sing ana diselehake ana lan link menyang bali. Dadi, sanajan referensi kanggo rong senar sing padha beda-beda (kaya ing rong conto ing ndhuwur), banjur nelpon menyang senar kasebut internbakal ngasilake referensi menyang obyek sing padha:
String str1 = "string";
String str2 = new String("string");
System.out.println(str1.intern()==str2.intern() ? "the same" : "not the same");
Asil ngeksekusi potongan kode iki bakal dadi "padha" . Aku ora bisa ngomong persis apa iki rampung cara iki. Cara interniki asli, lan jujur, aku ora pengin njaluk menyang wilds kode C. Paling kamungkinan iki rampung kanggo ngoptimalake konsumsi memori lan kinerja. Ing kasus apa wae, sampeyan kudu ngerti babagan fitur implementasine iki. Ayo pindhah menyang bagean sabanjure.

Perbandingan primitif nyata

Kanggo miwiti, aku arep takon. Prasaja banget. Apa jumlah ing ngisor iki - 0.3f + 0.4f? Kenging punapa? 0,7f? Ayo priksa:
float f1 = 0.7f;
float f2 = 0.3f + 0.4f;
System.out.println("f1==f2: "+(f1==f2));
Akibaté? Kaya? Aku uga. Kanggo sing ora ngrampungake fragmen iki, aku bakal ujar manawa asile bakal ...
f1==f2: false
Yagene iki kedadeyan?.. Ayo padha nindakake tes liyane:
float f1 = 0.3f;
float f2 = 0.4f;
float f3 = f1 + f2;
float f4 = 0.7f;
System.out.println("f1="+(double)f1);
System.out.println("f2="+(double)f2);
System.out.println("f3="+(double)f3);
System.out.println("f4="+(double)f4);
Wigati konversi menyang double. Iki ditindakake supaya bisa ngasilake papan desimal luwih akeh. asil:
f1=0.30000001192092896
f2=0.4000000059604645
f3=0.7000000476837158
f4=0.699999988079071
Tegese, asile bisa ditebak. Perwakilan saka bagean pecahan digawa metu nggunakake seri winates 2-n, lan mulane ana ora perlu kanggo pirembagan bab perwakilan pas saka nomer milih arbitrarily. Kaya sing bisa dideleng saka conto, akurasi perwakilan floatyaiku 7 desimal. Strictly ngandika, perwakilan float allocates 24 bit kanggo mantissa. Mangkono, jumlah absolut minimal sing bisa diwakili nggunakake float (tanpa njupuk gelar, amarga kita ngomong babagan akurasi) yaiku 2-24≈6 * 10-8. Kanthi langkah iki, nilai-nilai ing perwakilan kasebut bener-bener lunga float. Lan amarga ana kuantisasi, ana uga kesalahan. Dadi kesimpulan: angka ing perwakilan floatmung bisa dibandhingake karo akurasi tartamtu. Aku nyaranake dibunderaké menyang panggonan desimal kaping 6 (10-6), utawa, luwih becik, mriksa prabédan mutlak ing antarane:
float f1 = 0.3f;
float f2 = 0.4f;
float f3 = f1 + f2;
float f4 = 0.7f;
System.out.println("|f3-f4|<1e-6: "+( Math.abs(f3-f4) < 1e-6 ));
Ing kasus iki, asil nyemangati:
|f3-f4|<1e-6: true
Mesthi, gambar persis padha karo jinis double. Bentenipun mung 53 bit diparengake kanggo mantissa, mulane, akurasi perwakilan 2-53≈10-16. Ya, nilai kuantisasi luwih cilik, nanging ana. Lan bisa muter guyon kejem. Miturut cara, ing perpustakaan test JUnit , ing cara kanggo mbandhingake nomer nyata, presisi kasebut kanthi tegas. Sing. cara comparison ngandhut telung paramèter - nomer, apa kudu padha, lan akurasi comparison. Miturut cara, aku pengin nyebutake subtleties sing ana gandhengane karo nulis nomer ing format ilmiah, nuduhake gelar kasebut. Pitakonan. Kepiye carane nulis 10-6? Praktek nuduhake yen luwih saka 80% jawaban - 10e-6. Dene wangsulan kang bener yaiku 1e-6! Lan 10e-6 yaiku 10-5! Kita mlaku ing rake iki ing salah sawijining proyek, kanthi ora sengaja. Dheweke nggoleki kesalahan kasebut nganti suwe, ndeleng konstanta kaping 20. Lan ora ana sing ragu-ragu babagan benere, nganti sawijining dina, umume kanthi ora sengaja, konstanta 10e-3 dicithak lan ketemu loro. digit sawise titik desimal tinimbang samesthine telung. Mulane, ati-ati! Ayo nerusake.

+0,0 lan -0,0

Ing perwakilan saka nomer nyata, dicokot paling pinunjul mlebu. Apa sing kedadeyan yen kabeh bit liyane 0? Boten kados integers, ngendi ing kahanan kuwi asil nomer negatif dumunung ing wates ngisor saka sawetara perwakilan, nomer nyata karo mung dicokot paling pinunjul disetel kanggo 1 uga tegese 0, mung karo tandha minus. Mangkono, kita duwe loro nul - +0,0 lan -0,0. Pitakonan logis muncul: apa nomer kasebut kudu dianggep padha? Mesin virtual mikir kanthi cara iki. Nanging, iki rong nomer sing beda-beda , amarga minangka asil saka operasi karo wong-wong mau, nilai beda dijupuk:
float f1 = 0.0f/1.0f;
float f2 = 0.0f/-1.0f;
System.out.println("f1="+f1);
System.out.println("f2="+f2);
System.out.println("f1==f2: "+(f1==f2));
float f3 = 1.0f / f1;
float f4 = 1.0f / f2;
System.out.println("f3="+f3);
System.out.println("f4="+f4);
... lan asil:
f1=0.0
f2=-0.0
f1==f2: true
f3=Infinity
f4=-Infinity
Dadi ing sawetara kasus iku ndadekake pangertèn kanggo nambani +0,0 lan -0,0 minangka rong nomer beda. Lan yen kita duwe rong obyek, ing salah sawijining lapangan yaiku +0,0, lan ing liyane -0,0, obyek kasebut uga bisa dianggep ora padha. Pitakonan mengkene - carane sampeyan bisa ngerti sing nomer unequal yen comparison langsung karo mesin virtual menehi true? Jawaban iki. Sanajan mesin virtual nganggep angka kasebut padha, perwakilan kasebut isih beda. Mula, sing bisa ditindakake yaiku mbandhingake tampilan. Lan kanggo njaluk iku, ana cara int Float.floatToIntBits(float)lan long Double.doubleToLongBits(double), kang bali perwakilan dicokot ing wangun intlan longmungguh (lanjutan saka conto sadurunge):
int i1 = Float.floatToIntBits(f1);
int i2 = Float.floatToIntBits(f2);
System.out.println("i1 (+0.0):"+ Integer.toBinaryString(i1));
System.out.println("i2 (-0.0):"+ Integer.toBinaryString(i2));
System.out.println("i1==i2: "+(i1 == i2));
Asil bakal
i1 (+0.0):0
i2 (-0.0):10000000000000000000000000000000
i1==i2: false
Dadi, yen sampeyan duwe +0.0 lan -0.0 minangka nomer sing beda, mula sampeyan kudu mbandhingake variabel nyata liwat perwakilan bit. Kita koyone wis diurutake +0,0 lan -0,0. -0,0, Nanging, ora mung surprise. Ana uga sing kaya ...

Nilai NaN

NaNstands for Not-a-Number. Nilai iki katon minangka asil saka operasi matématika sing ora bener, umpamane, pamisah 0,0 karo 0,0, tanpa wates karo tanpa wates, etc. Keanehan nilai kasebut yaiku ora padha karo awake dhewe. Sing.:
float x = 0.0f/0.0f;
System.out.println("x="+x);
System.out.println("x==x: "+(x==x));
...asil ...
x=NaN
x==x: false
Kepiye carane bisa kedadeyan nalika mbandhingake obyek? Yen lapangan obyek padha karo NaN, banjur comparison bakal menehi false, i.e. obyek dijamin dianggep ora padha. Senajan, logis, kita bisa uga pengin mung ngelawan. Sampeyan bisa entuk asil sing dikarepake kanthi nggunakake metode kasebut Float.isNaN(float). Iki bali trueyen argumen kasebut NaN. Ing kasus iki, aku ora bakal gumantung ing mbandhingaké perwakilan dicokot, amarga iku ora standar. Mbok menawa cukup babagan primitif. Ayo saiki pindhah menyang subtleties sing wis katon ing Jawa wiwit versi 5.0. Lan titik pisanan sing dakkarepake yaiku

Jawa 5.0. Cara ngasilake lan mbandhingake liwat ' =='

Ana pola ing desain sing diarani metode produksi. Kadhangkala panggunaane luwih nguntungake tinimbang nggunakake konstruktor. Ayo kula menehi conto. Aku rumangsa ngerti cangkang obyek kasebut Boolean. Kelas iki ora bisa diganti lan mung bisa ngemot rong nilai. Tegese, kanggo kabutuhan apa wae, mung rong salinan sing cukup. Lan yen sampeyan nggawe sadurunge lan mung bali, bakal luwih cepet tinimbang nggunakake konstruktor. Ana cara kasebut Boolean: valueOf(boolean). Katon ing versi 1.4. Cara produksi sing padha dikenalake ing versi 5.0 ing kelas Byte, Character, Short, Integerlan Long. Nalika kelas kasebut dimuat, array saka kedadeyan kasebut digawe sing cocog karo kisaran nilai primitif tartamtu. Kisaran kasebut kaya ing ngisor iki:
Perbandingan obyek: praktik - 2
Iki tegese nalika nggunakake metode kasebut, valueOf(...)yen argumen kasebut ana ing kisaran sing ditemtokake, obyek sing padha bakal dibalekake. Mbok iki menehi sawetara Tambah ing kacepetan. Nanging ing wektu sing padha, masalah muncul saka alam sing bisa dadi cukup angel kanggo njaluk menyang ngisor. Waca liyane babagan. Ing teori, metode produksi valueOfwis ditambahake ing kelas Floatlan Double. Katrangan kasebut nyatakake yen sampeyan ora butuh salinan anyar, mula luwih becik nggunakake metode iki, amarga bisa nambah kacepetan, etc. lan liya-liyane. Nanging, ing implementasine saiki (Jawa 5.0), conto anyar digawe ing metode iki, yaiku. Panggunaan kasebut ora dijamin bakal nambah kacepetan. Menapa malih, angel kula mbayangno carane cara iki bisa dipercepat, amarga amarga kesinambungan nilai, cache ora bisa diatur ing kono. Kajaba kanggo integer. Maksudku, tanpa bagean pecahan.

Jawa 5.0. Autoboxing/Unboxing: ' ==', ' >=' lan ' <=' kanggo pambungkus obyek.

Aku curiga yen metode produksi lan cache conto ditambahake menyang bungkus kanggo primitif integer kanggo ngoptimalake operasi autoboxing/unboxing. Ayo kula ngelingake sampeyan apa iku. Yen obyek kudu melu operasi, nanging primitif melu, banjur primitif iki kanthi otomatis kebungkus ing pambungkus obyek. Iki autoboxing. Lan kosok balene - yen primitif kudu melu ing operasi, sampeyan bisa ngganti Nihan obyek ana, lan Nilai bakal ditambahi kanthi otomatis saka iku. Iki unboxing. Alamiah, sampeyan kudu mbayar kanggo penak kuwi. Operasi konversi otomatis alon-alon aplikasi kasebut. Nanging, iki ora cocog karo topik saiki, mula ayo ninggalake pitakonan iki. Kabeh iku nggoleki anggere kita dealing with operasi sing cetha related kanggo primitif utawa cangkang. Apa sing bakal kelakon ing ==operasi ''? Ayo kita duwe rong obyek Integerkanthi nilai sing padha ing njero. Kepiye carane mbandhingake?
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println("i1==i2: "+(i1==i2));
asil:
i1==i2: false

Кто бы сомневался... Сравниваются они How an objectы. А если так:Integer i1 = 1;
Integer i2 = 1;
System.out.println("i1==i2: "+(i1==i2));
asil:
i1==i2: true
Saiki iki luwih menarik! Yen autoboxing-e obyek sing padha bali! Iki ngendi jebakan dumunung. Sawise kita nemokake manawa obyek sing padha bali, kita bakal miwiti eksperimen kanggo ndeleng apa iki mesthi kedadeyan. Lan pira nilai sing bakal kita priksa? siji? sepuluh? satus? Paling kamungkinan kita bakal matesi dhéwé kanggo satus ing saben arah watara nul. Lan kita entuk kesetaraan ing endi wae. Iku bakal katon sing kabeh iku nggoleki. Nanging, katon bali sethitik, kene . Wis sampeyan guessed apa nyekel iku? .. Ya, kedadean saka cangkang obyek sak autoboxing digawe nggunakake cara prodhuksi. Iki uga digambarake kanthi tes ing ngisor iki:
public class AutoboxingTest {

    private static final int numbers[] = new int[]{-129,-128,127,128};

    public static void main(String[] args) {
        for (int number : numbers) {
            Integer i1 = number;
            Integer i2 = number;
            System.out.println("number=" + number + ": " + (i1 == i2));
        }
    }
}
Asil bakal kaya iki:
number=-129: false
number=-128: true
number=127: true
number=128: false
Kanggo nilai sing ana ing jangkoan caching , obyek sing padha bakal bali, kanggo sing ana ing njaba, obyek sing beda bakal bali. Lan mulane, yen ing endi wae ing cangkang aplikasi dibandhingake tinimbang primitif, ana kemungkinan entuk kesalahan sing paling elek: sing ngambang. Amarga kode kasebut kemungkinan uga bakal dites ing sawetara nilai sing winates sing kesalahan iki ora bakal katon. Nanging ing karya nyata, bakal katon utawa ilang, gumantung saka asil sawetara petungan. Luwih gampang edan tinimbang golek kesalahan. Mula, aku bakal menehi saran supaya ora autoboxing yen bisa. Lan ora iku. Eling-eling matematika, ora luwih saka kelas 5 SD. Ayo inequalities A>=Blan А<=B. Apa bisa ngandika bab sesambetan Alan B? Mung ana siji - padha padha. Apa sampeyan setuju? Aku mikir ya. Ayo nglakoni tes:
Integer i1 = new Integer(1);
Integer i2 = new Integer(1);
System.out.println("i1>=i2: "+(i1>=i2));
System.out.println("i1<=i2: "+(i1<=i2));
System.out.println("i1==i2: "+(i1==i2));
asil:
i1>=i2: true
i1<=i2: true
i1==i2: false
Lan iki sing paling aneh kanggo aku. Aku ora ngerti apa sebabe fitur iki dikenalake ing basa kasebut yen ngenalake kontradiksi kasebut. Umumé, aku bakal mbaleni maneh - yen bisa ditindakake tanpa autoboxing/unboxing, mula kudu nggunakake kesempatan iki kanthi lengkap. Topik pungkasan sing dakkarepake yaiku ... Java 5.0. mbandhingake unsur enumerasi (jinis enum) Kaya sing sampeyan ngerteni, wiwit versi 5.0 Jawa wis ngenalake jinis kasebut minangka enum - enumerasi. Instance kanthi standar ngemot jeneng lan nomer urutan ing deklarasi conto ing kelas. Mulane, nalika urutan pengumuman diganti, nomer kasebut ganti. Nanging, kaya sing dakkandhakake ing artikel 'Serialization as it' , iki ora nyebabake masalah. Kabeh unsur enumerasi ana ing salinan siji, iki dikontrol ing tingkat mesin virtual. Mulane, padha bisa dibandhingake langsung, nggunakake pranala. * * * Mbok sing kabeh kanggo dina iki bab sisih praktis ngleksanakake comparison obyek. Mbok menawa aku kelangan soko. Kaya biasane, aku ngenteni komentar sampeyan! Kanggo saiki, aku njaluk ninggalake. Matur nuwun kabeh kanggo manungsa waé! Link kanggo sumber: Mbandhingaké obyek: laku
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION