JavaRush /จาวาบล็อก /Random-TH /การทำกล่องอัตโนมัติและการแกะกล่องใน Java
DSergey_Kh
ระดับ

การทำกล่องอัตโนมัติและการแกะกล่องใน Java

เผยแพร่ในกลุ่ม
ในบทความนี้ เราจะดูคุณลักษณะใน Java ที่เรียกว่าautoboxing /unboxing การทำกล่องอัตโนมัติและการแกะกล่องเป็นฟังก์ชันในการแปลงประเภทดั้งเดิมเป็นประเภทวัตถุและในทางกลับกัน การทำกล่องอัตโนมัติและการแกะกล่องใน Java - 1กระบวนการทั้งหมดดำเนินการโดยอัตโนมัติโดย Java Runtime Environment (JRE) แต่คุณควรระมัดระวังเมื่อใช้ฟังก์ชันนี้ เนื่องจาก... อาจส่งผลต่อประสิทธิภาพของโปรแกรมของคุณ

การแนะนำ

ในเวอร์ชันที่ต่ำกว่า JDK 1.5 ไม่ใช่เรื่องง่ายที่จะแปลงประเภทข้อมูลพื้นฐาน เช่น, , intเป็นcharคลาสwrapper Integer, Character, Float, Double ตั้งแต่ JDK 5 เป็นต้นไป ฟังก์ชันการทำงานนี้ซึ่งแปลงประเภทดั้งเดิมเป็นอ็อบเจ็กต์ที่เทียบเท่ากัน จะถูกนำไปใช้โดยอัตโนมัติ คุณสมบัตินี้เรียกว่าAutoboxing กระบวนการย้อนกลับตามลำดับคือUnboxingเช่น กระบวนการแปลงวัตถุให้เป็นประเภทดั้งเดิมที่สอดคล้องกัน โค้ดตัวอย่างสำหรับ autoboxing และ unboxing มีดังต่อไปนี้: Autoboxingfloatdouble
Integer integer = 9;
แกะกล่อง
int in = 0;
in = new Integer(9);
การบรรจุและแกะกล่องอัตโนมัติจะใช้เมื่อใด? Autoboxing ถูกใช้โดยคอมไพเลอร์ Java ภายใต้เงื่อนไขต่อไปนี้:
  • เมื่อค่าของประเภทดั้งเดิมถูกส่งผ่านไปยังวิธีการเป็นพารามิเตอร์วิธีการ ซึ่งคาดว่าวัตถุของคลาส wrapper ที่สอดคล้องกัน
  • เมื่อกำหนดค่าประเภทดั้งเดิมให้กับตัวแปรของคลาส wrapper ที่สอดคล้องกัน
พิจารณาตัวอย่างต่อไปนี้: รายการ 1:รหัสอย่างง่ายที่แสดงกล่องอัตโนมัติ
public int sumEvenNumbers(List<Integer> intList ) {
int sum = 0;
for (Integer i: intList )
if ( i % 2 == 0 )
sum += i;
return sum;
}
ก่อนหน้า jdk 1.5 โค้ดด้านบนจะทำให้เกิดข้อผิดพลาดในการคอมไพล์เนื่องจากตัวดำเนินการส่วนที่เหลือ % และ unary plus += ไม่สามารถนำไปใช้กับคลาส wrapper ได้ แต่ใน jdk 1.5 และสูงกว่าโค้ดนี้จะคอมไพล์โดยไม่มีข้อผิดพลาด โดยแปลง Integer เป็นint. Unboxing ถูกใช้โดยคอมไพเลอร์ Java ภายใต้เงื่อนไขต่อไปนี้:
  • เมื่อวัตถุถูกส่งผ่านเป็นพารามิเตอร์ไปยังวิธีการที่คาดว่าจะมีชนิดดั้งเดิมที่สอดคล้องกัน
  • เมื่อวัตถุถูกกำหนดให้กับตัวแปรประเภทดั้งเดิมที่สอดคล้องกัน
ลองพิจารณาตัวอย่างต่อไปนี้: รายการ 2:โค้ดธรรมดาที่แสดงการแกะกล่อง
import java.util.ArrayList;
import java.util.List;

public class UnboxingCheck {

public static void main(String[] args) {
Integer in = new Integer(-8);

// 1. Распаковка через вызов метода
int absVal = absoluteValue(in);
System.out.println("absolute value of " + in + " = " + absVal);

List<Double> doubleList = new ArrayList<Double>();

// Автоупаковка через вызов метода
doubleList.add(3.1416);

// 2. Распаковка через присвоение
double phi = doubleList.get(0);
System.out.println("phi = " + phi);
}

public static int absoluteValue(int i) {
return (i < 0) ? -i : i;
}
}
การทำกล่องอัตโนมัติและการแกะกล่องช่วยให้นักพัฒนาสามารถเขียนโค้ดที่อ่านและเข้าใจได้ง่าย ตารางต่อไปนี้แสดงประเภทข้อมูลดั้งเดิมและออบเจ็กต์ wrapper ที่เกี่ยวข้อง
ประเภทดั้งเดิม คลาสเชลล์
บูลีน บูลีน
ไบต์ ไบต์
ถ่าน อักขระ
ลอย ลอย
ภายใน จำนวนเต็ม
ยาว ยาว
สั้น สั้น
ตารางที่ 1:ประเภทดั้งเดิมและคลาส wrapper ที่เทียบเท่ากับตัวดำเนินการเปรียบเทียบ สามารถใช้ Autoboxing และ unboxing กับตัวดำเนินการเปรียบเทียบได้ ข้อมูลโค้ดต่อไปนี้แสดงให้เห็นว่าสิ่งนี้เกิดขึ้นได้อย่างไร: รายการ 3:โค้ดตัวอย่างที่แสดง autoboxing และ unboxing ด้วยตัวดำเนินการเปรียบเทียบ
public class BoxedComparator {
  public static void main(String[] args) {
      Integer in = new Integer(25);
      if (in < 35)
          System.out.println("Value of int = " + in);
  }
}
การบรรจุอัตโนมัติและการแกะบรรจุภัณฑ์เมื่อมีการโอเวอร์โหลดวิธีการ การบรรจุอัตโนมัติและการแกะบรรจุภัณฑ์จะดำเนินการเมื่อมีการโอเวอร์โหลดวิธีการตามกฎต่อไปนี้:
  • การขยายตัว "เอาชนะ" บรรจุภัณฑ์ในสถานการณ์ที่มีตัวเลือกระหว่างการขยายและบรรจุภัณฑ์ การขยายจะดีกว่า
รายการ 4:โค้ดตัวอย่างที่แสดงประโยชน์ของการโอเวอร์โหลด
public class WideBoxed {
  public class WideBoxed {
  static void methodWide(int i) {
       System.out.println("int");
   }

  static void methodWide( Integer i ) {
      System.out.println("Integer");
  }

  public static void main(String[] args) {
      short shVal = 25;
      methodWide(shVal);
  }
 }
}
เอาต์พุตของโปรแกรม - ประเภทint
  • การขยายตัวเอาชนะจำนวนอาร์กิวเมนต์ที่แปรผันได้ ในสถานการณ์ที่กลายเป็นตัวเลือกระหว่างการขยายและจำนวนอาร์กิวเมนต์ที่แปรผัน การขยายจะดีกว่า
รายการ 5:โค้ดตัวอย่างที่แสดงประโยชน์ของการโอเวอร์โหลด
public class WideVarArgs {

    static void methodWideVar(int i1, int i2) {
      System.out.println("int int");
    }

    static void methodWideVar(Integer... i) {
       System.out.println("Integers");
    }

   public static void main( String[] args) {
       short shVal1 = 25;
      short shVal2 = 35;
     methodWideVar( shVal1, shVal2);
   }
  }
  • การบรรจุจะเอาชนะจำนวนอาร์กิวเมนต์ที่แปรผันได้ ในสถานการณ์ที่กลายเป็นตัวเลือกระหว่างการบรรจุและจำนวนอาร์กิวเมนต์ที่แปรผันได้ การบรรจุจะดีกว่า
รายการ 6:โค้ดตัวอย่างที่แสดงประโยชน์ของการโอเวอร์โหลด
public class BoxVarargs {
     static void methodBoxVar(Integer in) {
         System.out.println("Integer");
     }

     static void methodBoxVar(Integer... i) {
         System.out.println("Integers");
     }
     public static void main(String[] args) {
         int intVal1 = 25;
         methodBoxVar(intVal1);
    }
}
คุณควรคำนึงถึงสิ่งต่อไปนี้ในขณะที่ใช้การบรรจุอัตโนมัติ: ดังที่เราทราบ คุณสมบัติที่ดีทุกประการย่อมมีข้อเสียเปรียบ บรรจุภัณฑ์อัตโนมัติก็ไม่มีข้อยกเว้นในเรื่องนี้ หมายเหตุสำคัญบางประการที่นักพัฒนาซอฟต์แวร์ควรคำนึงถึงเมื่อใช้คุณลักษณะนี้:
  • การเปรียบเทียบวัตถุกับ==ตัวดำเนินการ ' ' อาจทำให้เกิดความสับสน เนื่องจากสามารถนำไปใช้กับประเภทและวัตถุดั้งเดิมได้ เมื่อนำตัวดำเนินการนี้ไปใช้กับออบเจ็กต์ ตัวดำเนินการจะเปรียบเทียบการอ้างอิงกับออบเจ็กต์ ไม่ใช่ตัวออบเจ็กต์เอง
รายการ 7:โค้ดตัวอย่างที่แสดงการเปรียบเทียบ
public class Comparator {
   public static void main(String[] args) {
     Integer istInt = new Integer(1);
       Integer secondInt = new Integer(1);

       if (istInt == secondInt) {
         System.out.println("both one are equal");

       } else {
          System.out.println("Both one are not equal");
      }
   }
}
  • การผสมอ็อบเจ็กต์และชนิดดั้งเดิมด้วยความเท่าเทียมกันและตัวดำเนินการเชิงสัมพันธ์ หากเราเปรียบเทียบประเภทดั้งเดิมกับวัตถุ วัตถุนั้นจะไม่ถูกแกะกล่อง ซึ่งสามารถโยนได้NullPointerExceptionหากวัตถุnullนั้น
  • การแคชวัตถุ วิธีการvalueOf()สร้างคอนเทนเนอร์ของวัตถุดั้งเดิมที่แคชไว้ เนื่องจากค่าถูกแคชไว้ในช่วง -128 ถึง 127 รวมแล้ว ออบเจ็กต์ที่แคชไว้เหล่านี้อาจมีพฤติกรรมแตกต่างออกไป
  • ประสิทธิภาพการทำงานลดลง การทำ Autoboxing หรือ Unboxing จะทำให้ประสิทธิภาพของแอปพลิเคชันลดลง เนื่องจากจะสร้างวัตถุที่ไม่ต้องการซึ่งบังคับให้ตัวรวบรวมขยะทำงานบ่อยขึ้น
ข้อเสียของ AutoBoxing แม้ว่า AutoBoxing มีข้อดีหลายประการ แต่ก็มีข้อเสียดังต่อไปนี้ รายการ 8:โค้ดตัวอย่างที่แสดงปัญหาด้านประสิทธิภาพ
public int sumEvenNumbers(List intList) {
          int sum = 0;
          for (Integer i : intList) {
              if (i % 2 == 0) {
                  sum += i;
              }
          }
         return sum;
   }
ในโค้ดส่วนนี้sum +=i จะขยายเป็นsum = sum + i. เริ่มต้นด้วย+ตัวดำเนินการ ' ' JVM จะเริ่มแกะกล่องเนื่องจาก+ไม่สามารถใช้ตัวดำเนินการ ' ' กับอ็อบเจ็กต์จำนวนเต็มได้ จากนั้นผลลัพธ์ก็จะถูกบรรจุกลับอัตโนมัติ ก่อน JDK 1.5 ชนิดข้อมูลintและจำนวนเต็มจะแตกต่างกัน ในกรณีที่วิธีการโอเวอร์โหลด ทั้งสองประเภทนี้ก็ถูกนำมาใช้โดยไม่มีปัญหา เมื่อมีการบรรจุ/แกะกล่องอัตโนมัติ การดำเนินการนี้กลายเป็นเรื่องยากมากขึ้น ตัวอย่างนี้คือวิธีการโอเวอร์โหลดremove()ในArrayList. คลาสArrayListมีสองวิธีการลบ - remove(index)และremove(object). ในกรณีนี้ วิธีการโอเวอร์โหลดจะไม่เกิดขึ้น และวิธีการที่เกี่ยวข้องจะถูกเรียกพร้อมกับพารามิเตอร์ที่เหมาะสม

บทสรุป

การทำกล่องอัตโนมัติเป็นกลไกในการแปลงประเภทข้อมูลดั้งเดิมเป็นคลาส wrapper (อ็อบเจ็กต์) ที่สอดคล้องกันโดยปริยาย คอมไพเลอร์ใช้วิธี การแปลงประเภทดั้งเดิมเป็นอ็อบเจ็กต์ และvalueOf()วิธีการ ฯลฯ เพื่อให้ได้ประเภทดั้งเดิมของอ็อบเจ็กต์ Autoboxing แปลงประเภทบูลีนเป็นบูลีน เป็นไบต์ เป็นอักขระลอยเป็นจำนวนเต็ม เป็นยาวเป็นสั้น การแกะบรรจุภัณฑ์เกิดขึ้นในทิศทางตรงกันข้าม บทความต้นฉบับIntValue()doubleValue()booleanbytecharfloatintlongshort
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION