ב-Java immutability פירושה שברגע שנוצר אובייקט לא ניתן לשנות את המצב הפנימי שלו. מחלקות בלתי ניתנות לשינוי ב-Java מספקות יתרונות רבים כמו בטיחות חוט ניפוי קל והכל. בג'אווה כל שיעורי עטיפה (כמו Integer Boolean Byte Short) והמחלקה String היא בלתי ניתנת לשינוי. אנחנו יכולים ליצור גם מחלקה בלתי משתנה משלנו.
במאמר זה אנו הולכים ללמוד:
- מה המשמעות של חוסר שינוי
- למה זה שימושי
- איך ליצור מעמד בלתי משתנה משלנו
- מדוע העתקה עמוקה חשובה
- מהן המגבלות שיש לסוגי רשומות Java
מהי מחלקה בלתי ניתנת לשינוי?
מחלקה בלתי ניתנת לשינוי היא מחלקה שלא ניתן לשנות את האובייקטים שלה לאחר שנוצרה. אם נעשה שינוי כלשהו זה גורם לאובייקט חדש. שיטה זו משמשת ביישומים במקביל.
כללים ליצירת מחלקה בלתי ניתנת לשינוי
- יש להכריז על המחלקה כ סוֹפִי כך שלא ניתן ליצור כיתות ילדים.
- יש להצהיר על חברי הנתונים בכיתה פְּרָטִי כך שאסור גישה ישירה.
- יש להצהיר על חברי הנתונים בכיתה סוֹפִי כך שלא נוכל לשנות את ערכם לאחר יצירת האובייקט.
- בנאי בעל פרמטרים צריך לאתחל את כל השדות המבצעים א עותק עמוק כך שלא ניתן לשנות את חברי הנתונים באמצעות הפניה לאובייקט.
- יש לבצע העתקה עמוקה של אובייקטים בשיטות getter כדי להחזיר עותק במקום להחזיר את הפניה לאובייקט בפועל.
פֶּתֶק : לא צריכים להיות קובעים או במונחים פשוטים יותר לא צריכה להיות אפשרות לשנות את הערך של משתנה המופע.
כמה אפס למיליון
דוגמה: יישום מחלקה בלתי ניתנת לשינוי
Student.java
Java// Java Program to Create An Immutable Class import java.util.HashMap; import java.util.Map; // declare the class as final final class Student { // make fields private and final private final String name; private final int regNo; private final Map<String String> metadata; // initialize all fields via constructor public Student(String name int regNo Map<String String> metadata) { this.name = name; this.regNo = regNo; // deep copy of mutable object (Map) Map<String String> tempMap = new HashMap<>(); for (Map.Entry<String String> entry : metadata.entrySet()) { tempMap.put(entry.getKey() entry.getValue()); } this.metadata = tempMap; } // only provide getters (no setters) public String getName() { return name; } public int getRegNo() { return regNo; } // return deep copy to avoid exposing internal state public Map<String String> getMetadata() { Map<String String> tempMap = new HashMap<>(); for (Map.Entry<String String> entry : this.metadata.entrySet()) { tempMap.put(entry.getKey() entry.getValue()); } return tempMap; } }
בדוגמה זו יצרנו מחלקה סופית בשם סטוּדֶנט. יש לו שלושה חברי נתונים סופיים, בנאי עם פרמטרים ושיטות גטר. שימו לב שאין כאן שיטת מגדיר. כמו כן, שים לב שאיננו צריכים לבצע העתקה עמוקה או שיבוט של חברי נתונים מסוגי עטיפה מכיוון שהם כבר בלתי ניתנים לשינוי.
Geeks.java:
Java string indexofJava
import java.util.HashMap; import java.util.Map; public class Geeks { public static void main(String[] args) { // create a map and adding data Map<String String> map = new HashMap<>(); map.put('1' 'first'); map.put('2' 'second'); // create an immutable Student object Student s = new Student('GFG' 101 map); // accessing data System.out.println(s.getName()); System.out.println(s.getRegNo()); System.out.println(s.getMetadata()); // try to modify the original map map.put('3' 'third'); System.out.println(s.getMetadata()); // try to modify the map returned by getMetadata() s.getMetadata().put('4' 'fourth'); System.out.println(s.getMetadata()); } }
גם לאחר שינוי המפה המקורית או המוחזרת המצב הפנימי של אובייקט הסטודנט נשאר ללא שינוי. זה מאשר את מושג הבלתי משתנה.
תְפוּקָה:
GFG
101
{1=first 2=second}
{1=first 2=second}
{1=first 2=second}
הגבלה של רשומת Java עם שדות ניתנים לשינוי
Java 14 הוצג רְשׁוּמָה . זוהי דרך ברורה ותמציתית להגדיר מחלקות כמו בלתי ניתנות לשינוי:
java שווה
record Student(שם מחרוזת int regNo Map
מטא נתונים) {}
אבל זה רק מציע אי-שינוי רדודה. אם המפה משתנה באופן חיצוני, המצב הפנימי של הרשומה משתנה:
מַפָּה
מפה = HashMap חדש<>(); map.put('1' 'first');
Java ממיין מערך
Student s = new Student('ABC' 101 map);
// משנה מצב פנימי - לא בטוח
map.put('2' 'second');
s.metadata().put('3' 'third');
פֶּתֶק : השתמש ברשומה רק אם כל השדות הם סוגים בלתי ניתנים לשינוי כמו String int או רשומות אחרות.
מחרוזת למספר שלם