ทำไม Java มีเขตข้อมูลชั่วคราว


คำตอบ:


1673

transientคำหลักใน Java จะใช้ในการแสดงให้เห็นว่าสนามไม่ควรจะเป็นส่วนหนึ่งของอันดับ (ซึ่งหมายถึงการบันทึกไว้เช่นไปยังแฟ้ม) กระบวนการ

จากข้อกำหนดภาษา Java, Java SE 7 Edition , ส่วน 8.3.1.3 transientฟิลด์ :

ตัวแปรอาจถูกทำเครื่องหมายtransientเพื่อระบุว่าพวกเขาไม่ได้เป็นส่วนหนึ่งของสถานะถาวรของวัตถุ

ตัวอย่างเช่นคุณอาจมีเขตข้อมูลที่ได้มาจากเขตข้อมูลอื่นและควรทำโดยทางโปรแกรมแทนที่จะให้สถานะคงอยู่ผ่านการทำให้เป็นอนุกรม

นี่คือGalleryImageคลาสที่มีรูปภาพและรูปขนาดย่อที่ได้จากรูปภาพ:

class GalleryImage implements Serializable
{
    private Image image;
    private transient Image thumbnailImage;

    private void generateThumbnail()
    {
        // Generate thumbnail.
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        generateThumbnail();
    }    
}

ในตัวอย่างนี้thumbnailImageคือรูปภาพขนาดย่อที่สร้างขึ้นโดยการเรียกใช้generateThumbnailเมธอด

thumbnailImageฟิลด์ถูกทำเครื่องหมายเป็นtransientดังนั้นเพียงเดิมimageเนื่องมากกว่า persisting ทั้งภาพต้นฉบับและภาพ ซึ่งหมายความว่าจำเป็นต้องใช้ที่เก็บข้อมูลน้อยลงเพื่อบันทึกวัตถุที่ทำเป็นอนุกรม (แน่นอนว่าสิ่งนี้อาจเป็นที่พึงปรารถนาหรือไม่ขึ้นอยู่กับข้อกำหนดของระบบ - นี่เป็นเพียงตัวอย่าง)

ในช่วงเวลาของreadObjectการดีซีเรียลไลเซชันเมธอดจะถูกเรียกให้ดำเนินการใด ๆ ที่จำเป็นในการกู้คืนสถานะของออบเจกต์กลับสู่สถานะที่การทำให้เป็นอนุกรมเกิดขึ้น ที่นี่จะต้องสร้างรูปขนาดย่อเพื่อให้มีreadObjectการแทนที่วิธีการเพื่อให้รูปขนาดย่อจะถูกสร้างขึ้นโดยการเรียกgenerateThumbnailวิธีการ

สำหรับข้อมูลเพิ่มเติมค้นพบความลับของบทความJava Serialization API (ซึ่งเดิมมีอยู่ใน Sun Developer Network) มีส่วนที่กล่าวถึงการใช้งานและนำเสนอสถานการณ์ที่transientมีการใช้คำหลักเพื่อป้องกันการทำให้เป็นอนุกรมของบางฟิลด์


221
แต่ทำไมมันเป็นคำหลักและไม่ได้เป็นคำอธิบายประกอบ@DoNotSerialize?
Elazar Leibovich

333
ฉันเดาว่านี่เป็นของเวลาที่ไม่มีคำอธิบายประกอบใน Java
Peter Wippermann

46
ฉันคิดว่ามันแปลกที่ serializable อยู่ภายใน Java มันสามารถนำมาใช้เป็นอินเตอร์เฟซหรือระดับนามธรรมที่ต้องการให้ผู้ใช้แทนที่วิธีการอ่านและเขียน
คาเลบ

7
@MJafar: readObject มักจะถูกผูกมัดกับกลไกการดีซีเรียลไลซ์เซชันและเรียกว่าโดยอัตโนมัติ นอกจากนี้ในหลายกรณีคุณไม่จำเป็นต้องแทนที่มัน - การใช้งานเริ่มต้นจะหลอกลวง
Mike Adler

13
@caleb อาจเป็นเพราะการจัดการกับรูปแบบไบนารีด้วยตัวคุณเองนั้นมีความเจ็บปวดอย่างมากใน Java เนื่องจากไม่มีจำนวนเต็มที่ไม่ได้ลงนาม
rightfold

435

ก่อนที่จะเข้าใจtransientคำหลักเราต้องเข้าใจแนวคิดของการทำให้เป็นอันดับ หากผู้อ่านรู้เกี่ยวกับการทำให้เป็นอันดับโปรดข้ามจุดแรก

การทำให้เป็นอันดับคืออะไร

การทำให้เป็นอันดับเป็นกระบวนการของการทำให้สถานะของวัตถุถาวร นั่นหมายความว่าสถานะของวัตถุจะถูกแปลงเป็นสตรีมของไบต์ที่จะใช้สำหรับการคงอยู่ (เช่นการจัดเก็บไบต์ในไฟล์) หรือการถ่ายโอน (เช่นการส่งไบต์ผ่านเครือข่าย) ในทำนองเดียวกันเราสามารถใช้การดีซีเรียลไลเซชันเพื่อทำให้สถานะของวัตถุกลับมาเป็นไบต์ นี่เป็นหนึ่งในแนวคิดที่สำคัญในการเขียนโปรแกรม Java เพราะส่วนใหญ่จะใช้ในการเขียนโปรแกรมเครือข่าย วัตถุที่ต้องส่งผ่านเครือข่ายจะต้องถูกแปลงเป็นไบต์ เพื่อจุดประสงค์นั้นทุกคลาสหรือส่วนต่อประสานต้องใช้Serializableส่วนต่อประสานนี้ มันเป็นอินเตอร์เฟสเครื่องหมายโดยไม่มีวิธีการใด ๆ

ตอนนี้transientคำหลักและวัตถุประสงค์คืออะไร?

ตามค่าเริ่มต้นตัวแปรทั้งหมดของวัตถุจะถูกแปลงเป็นสถานะถาวร ในบางกรณีคุณอาจต้องการหลีกเลี่ยงการคงอยู่ของตัวแปรบางตัวเนื่องจากคุณไม่จำเป็นต้องคงอยู่ของตัวแปรเหล่านั้น transientดังนั้นคุณจึงสามารถประกาศตัวแปรเหล่านั้นเป็น หากประกาศตัวแปรเป็นtransientแล้วจะไม่คงอยู่ นั่นคือวัตถุประสงค์หลักของtransientคำหลัก

ฉันต้องการอธิบายสองจุดข้างต้นด้วยตัวอย่างต่อไปนี้:

package javabeat.samples;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class NameStore implements Serializable{
    private String firstName;
    private transient String middleName;
    private String lastName;

    public NameStore (String fName, String mName, String lName){
        this.firstName = fName;
        this.middleName = mName;
        this.lastName = lName;
    }

    public String toString(){
        StringBuffer sb = new StringBuffer(40);
        sb.append("First Name : ");
        sb.append(this.firstName);
        sb.append("Middle Name : ");
        sb.append(this.middleName);
        sb.append("Last Name : ");
        sb.append(this.lastName);
        return sb.toString();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        NameStore nameStore = new NameStore("Steve", "Middle","Jobs");
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("nameStore"));
        // writing to object
        o.writeObject(nameStore);
        o.close();

        // reading from object
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("nameStore"));
        NameStore nameStore1 = (NameStore)in.readObject();
        System.out.println(nameStore1);
    }
}

และผลลัพธ์จะเป็นดังต่อไปนี้:

First Name : Steve
Middle Name : null
Last Name : Jobs

ชื่อกลางถูกประกาศเป็นtransientดังนั้นจะไม่ถูกเก็บไว้ในที่เก็บข้อมูลถาวร

แหล่ง


26
ตัวอย่างนี้นำมาจากรหัสนี้คุณสามารถอ่านได้ที่นี่: javabeat.net/2009/02/what-is-transient-keyword-in-java
Krishna

11
ส่วนนี้ทำให้ฉันแปลกและอาจสับสน: "นั่นหมายความว่าสถานะของวัตถุจะถูกแปลงเป็นสตรีมไบต์และเก็บไว้ในไฟล์ " สำหรับฉันแล้วดูเหมือนว่าการทำให้เป็นอนุกรมส่วนใหญ่ไม่เกี่ยวข้องกับการเขียนลงไฟล์ (ตัวอย่าง: เครือข่ายตัวอย่างที่ตามมา)
Garcia Hurtado

5
ตัวอย่างเป็นชื่อที่ไม่ดีเนื่องจากชื่อกลางไม่ชัดเจนว่าเป็นทรัพย์สินชั่วคราว
ราฟาเอล

1
@ ราฟาเอลสำหรับฉันตัวอย่างนี้มีประโยชน์และอย่างน้อยก็อธิบายแนวคิด คุณจะยกตัวอย่างที่ดีกว่านี้หากคุณรู้หรือไม่?
Chaklader Asfak Arefe

@Yoda เราสามารถอ้างอิงNameFormatterถึงไดรฟ์ที่toString()ใช้ หรือสิ่งอื่นใดที่เกี่ยวข้องกับการกำหนดค่าหรือการดูหรือตรรกะทางธุรกิจ ... ตรงข้ามกับข้อมูล
Raphael

84

เพื่อให้คุณสามารถกำหนดตัวแปรที่คุณไม่ต้องการทำให้เป็นอนุกรม

ในวัตถุคุณอาจมีข้อมูลที่คุณไม่ต้องการทำให้เป็นอนุกรม / คงอยู่ (อาจเป็นการอ้างอิงถึงวัตถุหลักของโรงงาน) หรืออาจไม่เหมาะสมที่จะทำให้เป็นอนุกรม การทำเครื่องหมายเหล่านี้เป็น 'ชั่วคราว' หมายถึงกลไกการทำให้เป็นอนุกรมจะไม่สนใจฟิลด์เหล่านี้


36

ผลงานเล็ก ๆ ของฉัน:

เขตข้อมูลชั่วคราวคืออะไร
โดยพื้นฐานแล้วฟิลด์ใด ๆ ที่แก้ไขด้วยtransientคำหลักคือฟิลด์ชั่วคราว

เหตุใดจึงต้องใช้ฟิลด์ชั่วคราวใน Java คำหลักที่ช่วยให้คุณควบคุมบางกว่ากระบวนการอนุกรมและช่วยให้คุณสามารถยกเว้นคุณสมบัติของวัตถุจากกระบวนการนี้ กระบวนการทำให้เป็นอนุกรมใช้เพื่อคงอยู่วัตถุ Java ส่วนใหญ่เพื่อให้สถานะของพวกเขาสามารถรักษาในขณะที่พวกเขาจะถูกโอนหรือไม่ใช้งาน บางครั้งมันก็สมเหตุสมผลที่จะไม่ทำให้คุณสมบัติบางอย่างของวัตถุเป็นอนุกรม คุณควรทำเครื่องหมายฟิลด์ใดชั่วคราว ตอนนี้เรารู้จุดประสงค์ของการ
transient


transientฟิลด์คำหลักและฟิลด์ชั่วคราวสิ่งสำคัญคือการรู้ว่าต้องทำเครื่องหมายฟิลด์ใดชั่วคราว ฟิลด์คงที่ไม่ได้ต่อเนื่องกันดังนั้นคำสำคัญที่เกี่ยวข้องก็จะทำเคล็ดลับเช่นกัน แต่นี่อาจทำลายการออกแบบชั้นเรียนของคุณ นี่คือที่ที่transientคำหลักมาช่วยเหลือ ฉันพยายามที่จะไม่อนุญาตให้เขตที่มีค่าที่สามารถได้รับจากคนอื่นเป็นอนุกรมดังนั้นฉันทำเครื่องหมายพวกเขาชั่วคราว หากคุณมีเขตข้อมูลinterestที่มีค่าที่สามารถคำนวณได้จากเขตข้อมูลอื่น ( principal, rate& time) คุณไม่จำเป็นต้องทำให้เป็นอนุกรม

อีกตัวอย่างที่ดีคือการนับจำนวนคำในบทความ หากคุณกำลังบันทึกบทความทั้งหมดคุณไม่จำเป็นต้องบันทึกจำนวนคำเนื่องจากสามารถคำนวณได้เมื่อบทความได้รับการ "ดีซีเรียลไลซ์" หรือคิดเกี่ยวกับคนตัดไม้Logger อินสแตนซ์แทบไม่จำเป็นต้องถูกทำให้เป็นอนุกรมดังนั้นจึงสามารถทำให้เป็นแบบชั่วคราวได้


63
'ประโยคง่ายๆ' ของคุณเป็นเพียงการพูดซ้ำซาก มันอธิบายอะไร คุณน่าจะดีกว่าถ้าไม่มี
user207421

1
นี่เป็นคำอธิบายที่ดีว่าควรใช้ฟิลด์ใดtransient
Chaklader Asfak Arefe

1
ฟิลด์ความสนใจและการนับจำนวนคำเป็นตัวอย่างที่ดีของฟิลด์ชั่วคราว
Tarun

1
อีกกรณีการใช้ที่ดี: หากวัตถุของคุณมีส่วนประกอบเช่นซ็อกเก็ตและหากคุณต้องการทำให้เป็นอนุกรมแล้วเกิดอะไรขึ้นกับซ็อกเก็ต ถ้าหากยังคงอยู่หลังจากที่คุณยกเลิกการย่อท้อสิ่งที่ซ็อกเก็ตจะถือ? มันสมเหตุสมผลแล้วที่จะทำให้วัตถุซ็อกเก็ตนั้นเป็นtransient
Mohammed Siddiq

28

transientตัวแปรเป็นตัวแปรที่อาจไม่ต่อเนื่อง

ตัวอย่างหนึ่งของเมื่อสิ่งนี้อาจมีประโยชน์ที่ควรคำนึงถึงคือตัวแปรที่มีความหมายเฉพาะในบริบทของอินสแตนซ์ของวัตถุที่เฉพาะเจาะจงเท่านั้น ในกรณีนั้นมันมีประโยชน์ที่จะให้ตัวแปรเหล่านั้นกลายเป็นnullแทนเพื่อให้คุณสามารถเริ่มต้นใหม่ได้ด้วยข้อมูลที่เป็นประโยชน์เมื่อจำเป็น


ใช่บางอย่างเช่น "รหัสผ่านหรือ creditiCardPin" สมาชิกสนามของชั้นเรียน
Mateen

17

transientใช้เพื่อระบุว่าฟิลด์คลาสไม่จำเป็นต้องต่อเนื่องกัน อาจเป็นตัวอย่างที่ดีที่สุดคือThreadสนาม มักจะไม่มีเหตุผลในการทำให้เป็นอนุกรม a Threadเนื่องจากสถานะเป็น 'flow specific' มาก


ถูกต้องฉันถ้าฉันผิด แต่กระทู้ไม่ได้เป็นแบบอนุกรมดังนั้นมันจะถูกข้ามไปหรือไม่
TFennis

3
@TFennis: ถ้า serializable ระดับAอ้างอิงชั้นไม่ serializable B(เช่นThreadในตัวอย่างของคุณ) แล้วAจะต้องทำเครื่องหมายอ้างอิงเป็นtransientแฮคเกอร์ต้องแทนที่กระบวนการอนุกรมเริ่มต้นเพื่อที่จะทำบางสิ่งบางอย่างที่เหมาะสมกับBแฮคเกอร์คิดว่า subclasses เพียง serializable ของBมีการอ้างอิงจริง (ดังนั้นคลาสย่อยจริงต้องดูแลพาเรนต์ "bad" B) XOR ยอมรับว่าการทำให้เป็นอนุกรมจะล้มเหลว ในกรณีเดียว (ทำเครื่องหมายเป็นชั่วคราว) Bจะถูกข้ามโดยอัตโนมัติและเงียบ
อา

3
@TFennis ไม่มันจะทำให้เกิดข้อยกเว้น
user207421

1
@AH: ทำไมต้องแฮคเกอร์ ฉันคิดว่ารหัสที่รวมกันของสิ่งเหล่านี้จะใช้งานได้และการรวมกันบางอย่างอาจมีประโยชน์ (เช่นการแทนที่กระบวนการเริ่มต้นการทำให้เป็นอนุกรมอาจมีประโยชน์แม้ว่าการอ้างอิงเฉพาะ subclasses ของ B ที่อ้างอิงได้และในทางกลับกัน)
supercat

15

ระบบการทำให้เป็นอนุกรมอื่นที่ไม่ใช่ native java one ยังสามารถใช้ตัวดัดแปลงนี้ ตัวอย่างเช่นไฮเบอร์เนตจะไม่คงอยู่ในฟิลด์ที่มีเครื่องหมาย@Transientหรือตัวดัดแปลงชั่วคราว ดินเผาและเคารพตัวแก้ไขนี้

ฉันเชื่อว่าความหมายของอุปมาอุปไมยคือ "ฟิลด์นี้มีไว้สำหรับใช้ในหน่วยความจำเท่านั้นอย่าคงอยู่หรือย้ายออกนอก VM นี้โดยเฉพาะในทางใดทางหนึ่งมันไม่ใช่แบบพกพา" เช่นคุณไม่สามารถพึ่งพาค่าในพื้นที่หน่วยความจำ VM อื่น การระเหยง่ายหมายถึงคุณไม่สามารถพึ่งพาความจำและความหมายของเธรดได้


14
ฉันคิดว่าtransientจะไม่เป็นคำหลักหากได้รับการออกแบบในเวลานี้ พวกเขาอาจใช้คำอธิบายประกอบ
โจอาคิมซาวเออ

9

เนื่องจากไม่ใช่ตัวแปรทั้งหมดที่มีลักษณะเป็นอนุกรม


42
กรุณาให้ข้อมูลเพิ่มเติมเมื่อคุณให้คำตอบ
Danny Gloudemans

7

ก่อนที่ฉันจะตอบคำถามนี้ฉันต้องอธิบายให้คุณรู้จักSERIALIZATIONเพราะถ้าคุณเข้าใจความหมายของอนุกรมในคอมพิวเตอร์วิทยาศาสตร์คุณสามารถเข้าใจคำหลักนี้ได้ง่าย

การทำให้เป็นอันดับ เมื่อวัตถุถูกถ่ายโอนผ่านเครือข่าย / บันทึกบนสื่อทางกายภาพ (ไฟล์, ... ), วัตถุนั้นจะต้อง "ต่อเนื่อง" การทำให้เป็นอนุกรมจะแปลงชุดวัตถุสถานะไบต์ ไบต์เหล่านี้ถูกส่งบนเครือข่าย / บันทึกและวัตถุถูกสร้างขึ้นใหม่จากไบต์เหล่านี้
ตัวอย่าง

public class Foo implements Serializable 
{
 private String attr1;
 private String attr2;
 ...
}

ตอนนี้ถ้าคุณต้องการที่จะทำไม่TRANSFERT / รอดฟิลด์ของวัตถุนี้ดังนั้นคุณสามารถใช้คำหลัก transient

private transient attr2;

ตัวอย่าง


6

จำเป็นเมื่อคุณไม่ต้องการแบ่งปันข้อมูลที่สำคัญที่มีการทำให้เป็นอนุกรม


7
มีกรณีการใช้งานอื่นนอกเหนือจากข้อมูลที่สำคัญซึ่งคุณอาจไม่ต้องการทำให้เป็นเขตข้อมูล ตัวอย่างเช่นคุณอาจไม่ต้องการทำให้เป็นอนุกรมThread(เครดิตกับ @AH เป็นตัวอย่าง) ซึ่งในกรณีนี้คุณจะทำเครื่องหมายว่าเป็นชั่วคราว อย่างไรก็ตามเธรดไม่ได้เป็นข้อมูลที่ละเอียดอ่อนในตัวมันเองมันก็ไม่สมเหตุสมผลที่จะทำให้เป็นอนุกรม (และมันไม่ได้เป็นอนุกรม)
glen3b

1
@ glen3b กรณีนี้ไม่ได้ถูกแยกออกโดยคำตอบนี้ เป็นสิ่งจำเป็นอย่างแน่นอนเพราะสิ่งที่ยืนในกรณีที่โปสเตอร์ดังกล่าว
user207421

3

ตามความหมายของ Google ชั่วคราว == ยาวนานเพียงช่วงเวลาสั้น ๆ ; อนิจจัง.

ตอนนี้ถ้าคุณต้องการทำอะไรชั่วคราวใน java ใช้คำสำคัญชั่วคราว

ถาม: จะใช้ transient ที่ไหน?

ตอบ:โดยทั่วไปในจาวาเราสามารถบันทึกข้อมูลลงในไฟล์โดยการรับพวกมันเป็นตัวแปรและการเขียนตัวแปรเหล่านั้นไปยังไฟล์กระบวนการนี้เรียกว่า Serialization ตอนนี้ถ้าเราต้องการหลีกเลี่ยงการเขียนข้อมูลตัวแปรไปยังไฟล์เราจะทำให้ตัวแปรนั้นเป็นแบบชั่วคราว

transient int result=10;

หมายเหตุ:ตัวแปรชั่วคราวไม่สามารถอยู่ในท้องที่ได้


0

ใส่เพียงแค่คำหลักชั่วคราวของ Java ปกป้องเขตข้อมูลจากการได้รับเป็นอันดับเป็นเขตข้อมูลที่ไม่ใช่ชั่วคราวของพวกเขาเคาน์เตอร์ชิ้นส่วน

ในโค้ดนี้ BaseJob คลาสนามธรรมของเราใช้อินเตอร์เฟสแบบ Serializable เราขยายจาก BaseJob แต่เราไม่ต้องการซีเรียลไลซ์แหล่งข้อมูลระยะไกลและท้องถิ่น ซีเรียลไลซ์เฉพาะชื่อองค์กรและฟิลด์ที่ถูกซิงค์

public abstract class BaseJob implements Serializable{
   public void ShouldRetryRun(){}
}

public class SyncOrganizationJob extends BaseJob {

   public String organizationName;
   public Boolean isSynced

   @Inject transient RemoteDataSource remoteDataSource;
   @Inject transient LocalDaoSource localDataSource;

   public SyncOrganizationJob(String organizationName) {
     super(new 
         Params(BACKGROUND).groupBy(GROUP).requireNetwork().persist());

      this.organizationName = organizationName;
      this.isSynced=isSynced;

   }
}

0

รหัสตัวอย่างที่ง่ายขึ้นสำหรับคำหลักชั่วคราว

import java.io.*;

class NameStore implements Serializable {
    private String firstName, lastName;
    private transient String fullName;

    public NameStore (String fName, String lName){
        this.firstName = fName;
        this.lastName = lName;
        buildFullName();
    }

    private void buildFullName() {
        // assume building fullName is compuational/memory intensive!
        this.fullName = this.firstName + " " + this.lastName;
    }

    public String toString(){
        return "First Name : " + this.firstName
            + "\nLast Name : " + this.lastName
            + "\nFull Name : " + this.fullName;
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        buildFullName();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("ns"));
        o.writeObject(new NameStore("Steve", "Jobs"));
        o.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("ns"));
        NameStore ns = (NameStore)in.readObject();
        System.out.println(ns);
    }
}

0

ฟิลด์ที่ประกาศพร้อมด้วยตัวแก้ไขชั่วคราวจะไม่เข้าร่วมในกระบวนการที่ทำให้เป็นอนุกรม เมื่อวัตถุถูกทำให้เป็นอนุกรม (บันทึกในสถานะใด ๆ ) ค่าของเขตข้อมูลชั่วคราวจะถูกละเว้นในการแทนแบบอนุกรมในขณะที่เขตข้อมูลอื่นที่ไม่ใช่เขตข้อมูลชั่วคราวจะมีส่วนร่วมในกระบวนการทำให้เป็นอนุกรม นั่นคือวัตถุประสงค์หลักของคำหลักชั่วคราว

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.