JavaRush /Java Blog /Random-ID /Tipe primitif di Java: Mereka tidak terlalu primitif
Viacheslav
Level 3

Tipe primitif di Java: Mereka tidak terlalu primitif

Dipublikasikan di grup Random-ID

Perkenalan

Pengembangan aplikasi dapat dianggap bekerja dengan beberapa data, atau lebih tepatnya, menyimpan dan memprosesnya. Hari ini saya ingin menyentuh aspek kunci pertama. Bagaimana data disimpan di Java? Di sini kita memiliki dua kemungkinan format: tipe data referensi dan primitif . Mari kita bicara tentang tipe tipe primitif dan kemungkinan bekerja dengannya (apa pun yang dikatakan, ini adalah dasar dari pengetahuan kita tentang bahasa pemrograman). Tipe data primitif Java adalah fondasi di mana segala sesuatunya bertumpu. Tidak, saya tidak melebih-lebihkan sama sekali. Oracle memiliki Tutorial terpisah yang didedikasikan untuk primitif: Tipe Data Primitif Tipe primitif di Java: Mereka tidak terlalu primitif - 1 Sedikit sejarah. Pada awalnya, angkanya nol. Tapi nol itu membosankan. Dan kemudian muncul sedikit . Mengapa dia disebut demikian? Dinamakan demikian dari singkatan “ bi nary digi t ” (bilangan biner). Artinya, hanya mempunyai dua arti. Dan karena dulunya nol, masuk akal jika sekarang menjadi 0 atau 1. Dan hidup menjadi lebih menyenangkan. Potongan-potongan itu mulai berkumpul dalam kawanan. Dan kawanan ini mulai disebut byte (byte). Di dunia modern, byte = 2 pangkat tiga, yaitu. 8. Namun ternyata tidak selalu demikian. Ada banyak tebakan, legenda dan rumor tentang dari mana asal nama byte. Beberapa orang berpikir bahwa ini semua tentang pengkodean pada waktu itu, sementara yang lain berpikir bahwa membaca informasi dengan cara ini lebih menguntungkan. Satu byte adalah bagian terkecil dari memori yang dapat dialamatkan. Ini adalah byte yang memiliki alamat unik di memori. Ada legenda bahwa ByTe adalah singkatan dari Binary Term - kata mesin. Kata mesin - sederhananya, ini adalah jumlah data yang dapat diproses oleh prosesor dalam satu operasi. Sebelumnya, ukuran kata mesin sama dengan memori terkecil yang dapat dialamatkan. Di Java, variabel hanya dapat menyimpan nilai byte. Seperti yang saya katakan di atas, ada dua jenis variabel di Java:
  • tipe primitif java secara langsung menyimpan nilai byte data (kita akan melihat tipe primitif ini lebih detail di bawah);
  • tipe referensi, menyimpan byte alamat objek di Heap, yaitu melalui variabel-variabel ini kita mendapatkan akses langsung ke objek itu sendiri (semacam remote control untuk objek tersebut)

byte Jawa

Jadi, sejarah memberi kita satu byte - jumlah minimum memori yang dapat kita gunakan. Dan itu terdiri dari 8 bit. Tipe data integer terkecil di java adalah byte. Ini adalah tipe 8-bit yang ditandatangani. Apa artinya? Mari berhitung. 2^8 adalah 256. Namun bagaimana jika kita menginginkan bilangan negatif? Dan pengembang Java memutuskan bahwa kode biner "10000000" akan mewakili -128, yaitu bit paling signifikan (bit paling kiri) akan menunjukkan apakah angka tersebut negatif. Biner “0111 1111” sama dengan 127. Artinya, 128 tidak dapat ditetapkan dengan cara apapun, karena itu akan menjadi -128. Perhitungan lengkapnya diberikan dalam jawaban ini: Mengapa kisaran byte -128 hingga 127 di Java? Untuk memahami cara memperoleh angka, sebaiknya perhatikan gambar:
Tipe primitif di Java: Mereka tidak terlalu primitif - 2
Oleh karena itu, untuk menghitung ukuran 2^(8-1) = 128. Artinya batas minimum (dan ada minusnya) adalah -128. Dan maksimumnya adalah 128 – 1 (dikurangi nol). Artinya, maksimumnya adalah 127. Faktanya, kita tidak terlalu sering bekerja dengan tipe byte pada "level tinggi". Pada dasarnya ini adalah pemrosesan data “mentah”. Misalnya, ketika bekerja dengan transmisi data melalui jaringan, ketika data berupa kumpulan 0 dan 1 yang ditransmisikan melalui beberapa saluran komunikasi. Atau saat membaca data dari file. Mereka juga dapat digunakan saat bekerja dengan string dan pengkodean. Contoh kode:
public static void main(String []args){
        byte value = 2;
        byte shortByteValue = 0b10; // 2
        System.out.println(shortByteValue);
        // Начиная с JDK7 мы можем разделять литералы подчёркиваниями
        byte minByteValue = (byte) 0B1000_0000; // -128
        byte maxByteValue = (byte) 0b0111_1111; // 127
        byte minusByteValue = (byte) 0b1111_1111; // -128 + 127
        System.out.println(minusByteValue);
        System.out.println(minByteValue + " to " + maxByteValue);
}
Ngomong-ngomong, jangan berpikir bahwa menggunakan tipe byte akan mengurangi konsumsi memori. Byte terutama digunakan untuk mengurangi konsumsi memori saat menyimpan data dalam array (misalnya, menyimpan data yang diterima melalui jaringan dalam beberapa buffer, yang akan diimplementasikan sebagai array byte). Namun saat melakukan operasi pada data, penggunaan byte tidak akan memenuhi harapan Anda. Hal ini disebabkan penerapan Java Virtual Machine (JVM). Karena sebagian besar sistem adalah 32 atau 64 bit, byte dan short selama perhitungan akan diubah menjadi int 32-bit, yang akan kita bicarakan nanti. Hal ini membuat perhitungan menjadi lebih mudah. Untuk lebih jelasnya, lihat Apakah penambahan konversi byte ke int karena aturan bahasa Java atau karena jvm? . Jawabannya juga berisi link ke JLS (Spesifikasi Bahasa Java). Selain itu, menggunakan byte di tempat yang salah dapat menyebabkan momen yang canggung:
public static void main(String []args){
        for (byte i = 1; i <= 200; i++) {
            System.out.println(i);
        }
}
Akan ada lingkaran di sini. Karena nilai counter mencapai maksimum (127), maka akan terjadi overflow dan nilainya menjadi -128. Dan kita tidak akan pernah keluar dari siklus tersebut.

pendek

Batasan nilai byte cukup kecil. Oleh karena itu, untuk tipe data berikutnya kami memutuskan untuk menggandakan jumlah bitnya. Artinya, sekarang bukan 8 bit, tapi 16. Artinya, 2 byte. Nilainya dapat dihitung dengan cara yang sama. 2^(16-1) = 2^15 = 32768. Artinya kisarannya adalah dari -32768 hingga 32767. Sangat jarang digunakan untuk kasus khusus apa pun. Seperti yang diberitahukan dalam dokumentasi bahasa Java: " Anda dapat menggunakan short untuk menghemat memori dalam array besar ."

ke dalam

Jadi kita sampai pada tipe yang paling sering digunakan. Dibutuhkan 32 bit, atau 4 byte. Secara umum, kami terus menggandakannya. Kisaran nilainya adalah dari -2^31 hingga 2^31 – 1.

Nilai int maksimum

Nilai maksimum int 2147483648 adalah 1, yang tidak kecil sama sekali. Sebagaimana dinyatakan di atas, untuk mengoptimalkan perhitungan, karena Lebih mudah bagi komputer modern, dengan mempertimbangkan kapasitas bitnya, untuk menghitung; data dapat secara implisit dikonversi ke int. Berikut ini contoh sederhananya:
byte a = 1;
byte b = 2;
byte result = a + b;
Kode yang tidak berbahaya, tetapi kami mendapatkan kesalahan: "kesalahan: tipe tidak kompatibel: kemungkinan konversi lossy dari int ke byte." Anda harus memperbaikinya menjadi byte result = (byte)(a + b); Dan satu lagi contoh yang tidak berbahaya. Apa yang terjadi jika kita menjalankan kode berikut?
int value = 4;
System.out.println(8/value);
System.out.println(9/value);
System.out.println(10/value);
System.out.println(11/value);
Dan kita akan mendapatkan kesimpulannya
2
2
2
2
*suara panik*
Faktanya adalah ketika bekerja dengan nilai int, sisanya dibuang, hanya menyisakan seluruh bagian (dalam kasus seperti itu lebih baik menggunakan double).

panjang

Kami terus menggandakannya. Kami mengalikan 32 dengan 2 dan mendapatkan 64 bit. Secara tradisi, ini adalah 4 * 2, yaitu 8 byte. Kisaran nilainya dari -2^63 hingga 2^63 – 1. Lebih dari cukup. Tipe ini memungkinkan Anda menghitung jumlah yang sangat besar. Sering digunakan saat bekerja dengan waktu. Atau jarak jauh, misalnya. Untuk menunjukkan bahwa suatu bilangan panjang, tempatkan huruf L – Panjang setelah bilangan tersebut. Contoh:
long longValue = 4;
longValue = 1l; // Не ошибка, но плохо читается
longValue = 2L; // Идеально
Saya ingin mendahului diri saya sendiri. Selanjutnya, kita akan mempertimbangkan fakta bahwa terdapat wrapper yang sesuai untuk primitif, yang memungkinkan untuk bekerja dengan primitif sebagai objek. Namun ada fitur menarik. Berikut ini contohnya: Dengan menggunakan kompiler online Tutorialspoint yang sama, Anda dapat memeriksa kode berikut:
public class HelloWorld {

     public static void main(String []args) {
        printLong(4);
     }

    public static void printLong(long longValue) {
        System.out.println(longValue);
    }
}
Kode ini berfungsi tanpa kesalahan, semuanya baik-baik saja. Tapi begitu tipe dalam metode printLong diganti dari long ke Long (yaitu tipenya tidak menjadi primitif, tapi objek), di Java menjadi tidak jelas parameter apa yang kita lewati. Itu mulai berasumsi bahwa int sedang dikirim dan akan ada kesalahan. Oleh karena itu, dalam hal suatu metode, 4L perlu ditunjukkan secara eksplisit. Seringkali long digunakan sebagai ID saat bekerja dengan database.

Java mengapung dan Java ganda

Tipe ini disebut tipe floating point. Artinya, ini bukan tipe integer. Tipe floatnya 32 bit (seperti int), dan double disebut tipe presisi ganda, jadi 64 bit (kalikan dengan 2, sesuai keinginan kita). Contoh:
public static void main(String []args){
        // float floatValue = 2.3; lossy conversion from double to float
        float floatValue = 2.3F;
        floatValue = 2.3f;
        double doubleValue = 2.3;
        System.out.println(floatValue);
        double cinema = 7D;
}
Dan berikut adalah contoh perbedaan nilai (karena presisi tipe):
public static void main(String []args){
        float piValue = (float)Math.PI;
        double piValueExt = Math.PI;
        System.out.println("Float value: " + piValue );
        System.out.println("Double value: " + piValueExt );
 }
Tipe primitif ini digunakan dalam matematika, misalnya. Ini buktinya, konstanta untuk menghitung bilangan PI . Secara umum, Anda bisa melihat API kelas Matematika. Inilah hal lain yang penting dan menarik: bahkan dokumentasinya mengatakan: “ Tipe data ini tidak boleh digunakan untuk nilai yang tepat, seperti mata uang. Untuk itu, Anda perlu menggunakan kelas java.math.BigDecimal. Angka dan String mencakup BigDecimal dan kelas berguna lainnya yang disediakan oleh platform Java. " Artinya, uang dalam bentuk float dan double tidak perlu dihitung. Contoh soal akurasi menggunakan contoh kerja di NASA: Java BigDecimal, Menangani perhitungan presisi tinggi Nah, untuk merasakannya sendiri:
public static void main(String []args){
        float amount = 1.0000005F;
        float avalue = 0.0000004F;
        float result = amount - avalue;
        System.out.println(result);
}
Ikuti contoh ini, lalu tambahkan 0 sebelum angka 5 dan 4. Dan Anda akan melihat semua kengeriannya) Ada laporan menarik dalam bahasa Rusia tentang float dan double pada topik: https://youtu.be/1RCn5ruN1fk Contoh cara kerja dengan BigDecimal dapat dilihat di sini: Menghasilkan sen dengan BigDecimal Omong-omong, float dan double dapat menghasilkan lebih dari sekedar angka. Misalnya, contoh di bawah ini akan mengembalikan Infinity:
public static void main(String []args){
        double positive_infinity = 12.0 / 0;
        System.out.println(positive_infinity);
}
Dan yang ini akan mengembalikan NAN:
public static void main(String []args){
        double positive_infinity = 12.0 / 0;
        double negative_infinity = -15.0 / 0;
        System.out.println(positive_infinity + negative_infinity);
}
Sudah jelas tentang ketidakterbatasan. Apa itu NaN? Ini Bukan Angka , artinya hasilnya tidak bisa dihitung dan bukan berupa angka. Berikut ini contohnya: Kita ingin menghitung akar kuadrat dari -4. Akar kuadrat dari 4 adalah 2. Artinya, 2 harus dikuadratkan lalu kita mendapatkan 4. Berapakah yang harus dikuadratkan untuk mendapatkan -4? Itu tidak akan berhasil, karena... jika ada bilangan positif maka akan tetap ada. Dan jika negatif, maka minus demi minus akan memberi nilai plus. Artinya, ini tidak dapat dihitung.
public static void main(String []args){
        double sqrt = Math.sqrt(-4);
        System.out.println(sqrt + 1);
        if (Double.isNaN(sqrt)) {
           System.out.println("So sad");
        }
        System.out.println(Double.NaN == sqrt);
}
Berikut ini ikhtisar bagus lainnya mengenai topik bilangan floating point: Dimana maksud Anda?
Apa lagi yang harus dibaca:

Boolean Jawa

Tipe selanjutnya adalah Boolean (tipe logis). Itu hanya dapat menerima nilai benar atau salah, yang merupakan kata kunci. Digunakan dalam operasi logika seperti perulangan while, dan dalam percabangan menggunakan if, switch. Hal menarik apa saja yang bisa kamu temukan di sini? Misalnya, secara teoritis kita hanya membutuhkan 1 bit informasi, 0 atau 1, yaitu benar atau salah. Namun kenyataannya, Boolean akan memakan lebih banyak memori dan ini akan bergantung pada implementasi JVM spesifik. Biasanya biayanya sama dengan int. Pilihan lainnya adalah menggunakan BitSet. Berikut penjelasan singkat dari buku Java Fundamentals: BitSet

karakter Jawa

Sekarang kita telah mencapai tipe primitif terakhir. Jadi, data dalam char memakan waktu 16 bit dan mendeskripsikan karakter. Java menggunakan pengkodean Unicode untuk char. Simbolnya dapat diatur berdasarkan dua tabel (Anda dapat melihatnya di sini ):
  • Tabel karakter unicode
  • Tabel karakter ASCII
Tipe primitif di Java: Mereka tidak terlalu primitif - 3
Contoh di studio:
public static void main(String[] args) {
    char symbol = '\u0066'; // Unicode
    symbol = 102; // ASCII
    System.out.println(symbol);
}
Omong-omong, char, pada dasarnya adalah bilangan, mendukung operasi matematika seperti penjumlahan. Dan terkadang hal ini dapat menimbulkan konsekuensi yang lucu:
public class HelloWorld{

    public static void main(String []args){
        String costForPrint = "5$";
        System.out.println("Цена только для вас " +
        + costForPrint.charAt(0) + getCurrencyName(costForPrint.charAt(1)));
    }

    public static String getCurrencyName(char symbol) {
        if (symbol == '$') {
            return " долларов";
        } else {
            throw new UnsupportedOperationException("Not implemented yet");
        }
    }

}
Saya sangat merekomendasikan memeriksa IDE online dari tutorialspoint . Ketika saya melihat teka-teki ini di salah satu konferensi, hal itu membangkitkan semangat saya. Saya harap Anda juga menyukai contohnya) DIPERBARUI: Ini terjadi di Joker 2017, laporkan: " Java Puzzlers NG S03 - Dari mana asal kalian semua? "

harfiah

Literal adalah nilai yang ditentukan secara eksplisit. Dengan menggunakan literal, Anda dapat menentukan nilai dalam sistem bilangan yang berbeda:
  • Sistem desimal: 10
  • Heksadesimal: 0x1F4, dimulai dengan 0x
  • Sistem oktal: 010, dimulai dari nol.
  • Sistem biner (sejak Java7): 0b101, dimulai dari 0b
Saya akan membahas lebih jauh tentang sistem oktal, karena ini lucu:
int costInDollars = 08;
Baris kode ini tidak dapat dikompilasi:
error: integer number too large: 08
Sepertinya tidak masuk akal. Sekarang mari kita ingat tentang sistem biner dan oktal. Tidak ada angka dua dalam sistem biner, karena ada dua nilai (mulai dari 0). Dan sistem oktal memiliki 8 nilai yang dimulai dari nol. Artinya, nilai 8 itu sendiri tidak ada. Oleh karena itu, ini adalah kesalahan yang sekilas tampak tidak masuk akal. Dan yang perlu diingat, inilah aturan “tindak lanjut” untuk menerjemahkan nilai:
Tipe primitif di Java: Mereka tidak terlalu primitif - 4

Kelas pembungkus

Primitif di Java memiliki kelas pembungkusnya sendiri sehingga Anda bisa menggunakannya sebagai objek. Artinya, untuk setiap tipe primitif ada tipe referensi yang sesuai. Tipe primitif di Java: Mereka tidak terlalu primitif - 5Kelas wrapper tidak dapat diubah: ini berarti bahwa setelah suatu objek dibuat, statusnya—nilai bidang nilai—tidak dapat diubah. Kelas wrapper dideklarasikan sebagai final: objek, bisa dikatakan, hanya-baca. Saya juga ingin menyebutkan bahwa tidak mungkin mewarisi dari kelas-kelas ini. Java secara otomatis membuat konversi antara tipe primitif dan pembungkusnya:
Integer x = 9;          // autoboxing
int n = new Integer(3); // unboxing
Proses mengubah tipe primitif menjadi tipe referensi (int->Integer) disebut autoboxing , dan sebaliknya disebut unboxing . Kelas-kelas ini memungkinkan untuk menyimpan primitif di dalam suatu objek, dan objek itu sendiri akan berperilaku seperti sebuah Objek (yah, seperti objek lainnya). Dengan semua ini, kita mendapatkan sejumlah besar metode statis yang bervariasi dan berguna, seperti membandingkan angka, mengubah simbol menjadi huruf besar-kecil, menentukan apakah suatu simbol adalah huruf atau angka, mencari angka minimum, dll. Kumpulan fungsionalitas yang disediakan hanya bergantung pada pembungkus itu sendiri. Contoh penerapan wrapper untuk int:
public class CustomerInt {

   private final int value;

   public CustomerInt(int value) {
       this.value = value;
   }

   public int getValue() {
       return value;
   }
}
Paket utama, java.lang, sudah memiliki implementasi kelas Boolean, Byte, Short, Character, Integer, Float, Long, Double, dan kita tidak perlu membuat apa pun sendiri, cukup menggunakan kembali yang sudah jadi. yang. Misalnya, kelas seperti itu memberi kita kemampuan untuk membuat, katakanlah, Daftar , karena Daftar hanya boleh berisi objek, sedangkan primitif tidak. Untuk mengonversi nilai bertipe primitif, terdapat metode valueOf statis, misalnya Integer.valueOf(4) akan mengembalikan objek bertipe Integer. Untuk konversi terbalik ada metode intValue(), longValue(), dll. Kompiler menyisipkan panggilan ke valueOf dan *Value sendiri, ini adalah inti dari autoboxing dan autounboxing. Seperti apa sebenarnya contoh autopacking dan autounpacking yang disajikan di atas:
Integer x = Integer.valueOf(9);
int n = new Integer(3).intValue();
Anda dapat membaca lebih lanjut tentang autopacking dan autounpacking di artikel ini .

Pemeran

При работе с примитивами существует такое понятие How приведение типов, одно из не очень приятных свойств C++, тем не менее приведение типов сохранено и в языке Java. Иногда мы сталкиваемся с такими ситуациями, когда нам нужно совершать взаимодействия с данными разных типов. И очень хорошо, что в некоторых ситуациях это возможно. В случае с ссылочными переменными, там свои особенности, связанные с полиморфизмом и наследованием, но сегодня мы рассматриваем простые типы и соответственно приведение простых типов. Существует преобразование с расширением и преобразование сужающее. Всё на самом деле просто. Если тип данных становится больше (допустим, был int, а стал long), то тип становится шире (из 32 бит становится 64). И в этом случае мы не рискуем потерять данные, т.к. если влезло в int, то в long влезет тем более, поэтому данное приведение мы не замечаем, так How оно осуществляется автоматически. А вот в обратную сторону преобразование требует явного указания от нас, данное приведение типа называется — сужение. Так сказать, чтобы мы сами сказали: «Да, я даю себе отчёт в этом. В случае чего — виноват сам».
public static void main(String []args){
   int intValue = 128;
   byte value = (byte)intValue;
   System.out.println(value);
}
Whatбы потом в таком случае не говорor что «Ваша Джава плохая», когда получат внезапно -128 instead of 128 ) Мы ведь помним, что в byteе 127 верхнее meaning и всё что находилось выше него соответственно можно потерять. Когда мы явно превратor наш int в byte, то произошло переполнение и meaning стало -128.

Область видимости

Это то место в codeе, где данная переменная будет выполнять свои функции и хранить в себе Howое-то meaning. Когда же эта область закончится, переменная перестанет существовать и будет стерта из памяти и. How уже можно догадаться, посмотреть or получить ее meaning будет невозможно! Так что же это такое — область видимости? Tipe primitif di Java: Mereka tidak begitu primitif - 6Область определяется "блоком" — вообще всякой областью, замкнутой в фигурные скобки, выход за которые сулит удаление данных объявленных в ней. Или How минимум — сокрытие их от других блоков, открытых вне текущего. В Java область видимости определяется двумя основными способами:
  • Классом.
  • Методом.
Как я и сказал, переменная не видна codeу, если она определена за пределами блока, в котором она была инициализирована. Смотрим пример:
int x;
x = 6;
if (x >= 4) {
   int y = 3;
}
x = y;// переменная y здесь не видна!
И How итог мы получим ошибку:

Error:(10, 21) java: cannot find symbol
  symbol:   variable y
  location: class com.javaRush.test.type.Main
Области видимости могут быть вложенными (если мы объявor переменную в первом, внешнем блоке, то во внутреннем она будет видна).

Заключение

Сегодня мы познакомorсь с восемью примитивными типами в Java. Эти типы можно разделить на четыре группы:
  • Целые числа: byte, short, int, long — представляют собой целые числа со знаком.
  • Числа с плавающей точкой — эта группа включает себе float и double — типы, которые хранят числа с точностью до определённого знака после запятой.
  • Булевы значения — boolean — хранят значения типа "истина/ложь".
  • Karakter - grup ini mencakup tipe char.
Seperti yang ditunjukkan teks di atas, primitif di Java tidak terlalu primitif dan memungkinkan Anda menyelesaikan banyak masalah secara efektif. Namun hal ini juga memperkenalkan beberapa fitur yang harus kita ingat jika kita tidak ingin menemui perilaku tak terduga dalam program kita. Seperti yang mereka katakan, Anda harus membayar semuanya. Jika kita menginginkan primitif dengan rentang "curam" (lebar) - sesuatu seperti panjang - kita mengorbankan alokasi memori yang lebih besar dan dalam arah yang berlawanan. Dengan menghemat memori dan menggunakan byte, kita mendapatkan rentang terbatas dari -128 hingga 127.
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION