ทำไม Java มีเขตข้อมูลชั่วคราว
ทำไม Java มีเขตข้อมูลชั่วคราว
คำตอบ:
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
มีการใช้คำหลักเพื่อป้องกันการทำให้เป็นอนุกรมของบางฟิลด์
ก่อนที่จะเข้าใจ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
ดังนั้นจะไม่ถูกเก็บไว้ในที่เก็บข้อมูลถาวร
NameFormatter
ถึงไดรฟ์ที่toString()
ใช้ หรือสิ่งอื่นใดที่เกี่ยวข้องกับการกำหนดค่าหรือการดูหรือตรรกะทางธุรกิจ ... ตรงข้ามกับข้อมูล
เพื่อให้คุณสามารถกำหนดตัวแปรที่คุณไม่ต้องการทำให้เป็นอนุกรม
ในวัตถุคุณอาจมีข้อมูลที่คุณไม่ต้องการทำให้เป็นอนุกรม / คงอยู่ (อาจเป็นการอ้างอิงถึงวัตถุหลักของโรงงาน) หรืออาจไม่เหมาะสมที่จะทำให้เป็นอนุกรม การทำเครื่องหมายเหล่านี้เป็น 'ชั่วคราว' หมายถึงกลไกการทำให้เป็นอนุกรมจะไม่สนใจฟิลด์เหล่านี้
ผลงานเล็ก ๆ ของฉัน:
เขตข้อมูลชั่วคราวคืออะไร
โดยพื้นฐานแล้วฟิลด์ใด ๆ ที่แก้ไขด้วยtransient
คำหลักคือฟิลด์ชั่วคราว
เหตุใดจึงต้องใช้ฟิลด์ชั่วคราวใน Java คำหลักที่ช่วยให้คุณควบคุมบางกว่ากระบวนการอนุกรมและช่วยให้คุณสามารถยกเว้นคุณสมบัติของวัตถุจากกระบวนการนี้ กระบวนการทำให้เป็นอนุกรมใช้เพื่อคงอยู่วัตถุ Java ส่วนใหญ่เพื่อให้สถานะของพวกเขาสามารถรักษาในขณะที่พวกเขาจะถูกโอนหรือไม่ใช้งาน บางครั้งมันก็สมเหตุสมผลที่จะไม่ทำให้คุณสมบัติบางอย่างของวัตถุเป็นอนุกรม คุณควรทำเครื่องหมายฟิลด์ใดชั่วคราว
ตอนนี้เรารู้จุดประสงค์ของการtransient
transient
ฟิลด์คำหลักและฟิลด์ชั่วคราวสิ่งสำคัญคือการรู้ว่าต้องทำเครื่องหมายฟิลด์ใดชั่วคราว ฟิลด์คงที่ไม่ได้ต่อเนื่องกันดังนั้นคำสำคัญที่เกี่ยวข้องก็จะทำเคล็ดลับเช่นกัน แต่นี่อาจทำลายการออกแบบชั้นเรียนของคุณ นี่คือที่ที่transient
คำหลักมาช่วยเหลือ ฉันพยายามที่จะไม่อนุญาตให้เขตที่มีค่าที่สามารถได้รับจากคนอื่นเป็นอนุกรมดังนั้นฉันทำเครื่องหมายพวกเขาชั่วคราว หากคุณมีเขตข้อมูลinterest
ที่มีค่าที่สามารถคำนวณได้จากเขตข้อมูลอื่น ( principal
, rate
& time
) คุณไม่จำเป็นต้องทำให้เป็นอนุกรม
อีกตัวอย่างที่ดีคือการนับจำนวนคำในบทความ หากคุณกำลังบันทึกบทความทั้งหมดคุณไม่จำเป็นต้องบันทึกจำนวนคำเนื่องจากสามารถคำนวณได้เมื่อบทความได้รับการ "ดีซีเรียลไลซ์" หรือคิดเกี่ยวกับคนตัดไม้Logger
อินสแตนซ์แทบไม่จำเป็นต้องถูกทำให้เป็นอนุกรมดังนั้นจึงสามารถทำให้เป็นแบบชั่วคราวได้
transient
transient
transient
ตัวแปรเป็นตัวแปรที่อาจไม่ต่อเนื่อง
ตัวอย่างหนึ่งของเมื่อสิ่งนี้อาจมีประโยชน์ที่ควรคำนึงถึงคือตัวแปรที่มีความหมายเฉพาะในบริบทของอินสแตนซ์ของวัตถุที่เฉพาะเจาะจงเท่านั้น ในกรณีนั้นมันมีประโยชน์ที่จะให้ตัวแปรเหล่านั้นกลายเป็นnull
แทนเพื่อให้คุณสามารถเริ่มต้นใหม่ได้ด้วยข้อมูลที่เป็นประโยชน์เมื่อจำเป็น
transient
ใช้เพื่อระบุว่าฟิลด์คลาสไม่จำเป็นต้องต่อเนื่องกัน อาจเป็นตัวอย่างที่ดีที่สุดคือThread
สนาม มักจะไม่มีเหตุผลในการทำให้เป็นอนุกรม a Thread
เนื่องจากสถานะเป็น 'flow specific' มาก
A
อ้างอิงชั้นไม่ serializable B
(เช่นThread
ในตัวอย่างของคุณ) แล้วA
จะต้องทำเครื่องหมายอ้างอิงเป็นtransient
แฮคเกอร์ต้องแทนที่กระบวนการอนุกรมเริ่มต้นเพื่อที่จะทำบางสิ่งบางอย่างที่เหมาะสมกับB
แฮคเกอร์คิดว่า subclasses เพียง serializable ของB
มีการอ้างอิงจริง (ดังนั้นคลาสย่อยจริงต้องดูแลพาเรนต์ "bad" B
) XOR ยอมรับว่าการทำให้เป็นอนุกรมจะล้มเหลว ในกรณีเดียว (ทำเครื่องหมายเป็นชั่วคราว) B
จะถูกข้ามโดยอัตโนมัติและเงียบ
ระบบการทำให้เป็นอนุกรมอื่นที่ไม่ใช่ native java one ยังสามารถใช้ตัวดัดแปลงนี้ ตัวอย่างเช่นไฮเบอร์เนตจะไม่คงอยู่ในฟิลด์ที่มีเครื่องหมาย@Transientหรือตัวดัดแปลงชั่วคราว ดินเผาและเคารพตัวแก้ไขนี้
ฉันเชื่อว่าความหมายของอุปมาอุปไมยคือ "ฟิลด์นี้มีไว้สำหรับใช้ในหน่วยความจำเท่านั้นอย่าคงอยู่หรือย้ายออกนอก VM นี้โดยเฉพาะในทางใดทางหนึ่งมันไม่ใช่แบบพกพา" เช่นคุณไม่สามารถพึ่งพาค่าในพื้นที่หน่วยความจำ VM อื่น การระเหยง่ายหมายถึงคุณไม่สามารถพึ่งพาความจำและความหมายของเธรดได้
transient
จะไม่เป็นคำหลักหากได้รับการออกแบบในเวลานี้ พวกเขาอาจใช้คำอธิบายประกอบ
เนื่องจากไม่ใช่ตัวแปรทั้งหมดที่มีลักษณะเป็นอนุกรม
ก่อนที่ฉันจะตอบคำถามนี้ฉันต้องอธิบายให้คุณรู้จักSERIALIZATIONเพราะถ้าคุณเข้าใจความหมายของอนุกรมในคอมพิวเตอร์วิทยาศาสตร์คุณสามารถเข้าใจคำหลักนี้ได้ง่าย
การทำให้เป็นอันดับ
เมื่อวัตถุถูกถ่ายโอนผ่านเครือข่าย / บันทึกบนสื่อทางกายภาพ (ไฟล์, ... ), วัตถุนั้นจะต้อง "ต่อเนื่อง" การทำให้เป็นอนุกรมจะแปลงชุดวัตถุสถานะไบต์ ไบต์เหล่านี้ถูกส่งบนเครือข่าย / บันทึกและวัตถุถูกสร้างขึ้นใหม่จากไบต์เหล่านี้
ตัวอย่าง
public class Foo implements Serializable
{
private String attr1;
private String attr2;
...
}
ตอนนี้ถ้าคุณต้องการที่จะทำไม่TRANSFERT / รอดฟิลด์ของวัตถุนี้ดังนั้นคุณสามารถใช้คำหลัก transient
private transient attr2;
จำเป็นเมื่อคุณไม่ต้องการแบ่งปันข้อมูลที่สำคัญที่มีการทำให้เป็นอนุกรม
Thread
(เครดิตกับ @AH เป็นตัวอย่าง) ซึ่งในกรณีนี้คุณจะทำเครื่องหมายว่าเป็นชั่วคราว อย่างไรก็ตามเธรดไม่ได้เป็นข้อมูลที่ละเอียดอ่อนในตัวมันเองมันก็ไม่สมเหตุสมผลที่จะทำให้เป็นอนุกรม (และมันไม่ได้เป็นอนุกรม)
ตามความหมายของ Google ชั่วคราว == ยาวนานเพียงช่วงเวลาสั้น ๆ ; อนิจจัง.
ตอนนี้ถ้าคุณต้องการทำอะไรชั่วคราวใน java ใช้คำสำคัญชั่วคราว
ถาม: จะใช้ transient ที่ไหน?
ตอบ:โดยทั่วไปในจาวาเราสามารถบันทึกข้อมูลลงในไฟล์โดยการรับพวกมันเป็นตัวแปรและการเขียนตัวแปรเหล่านั้นไปยังไฟล์กระบวนการนี้เรียกว่า Serialization ตอนนี้ถ้าเราต้องการหลีกเลี่ยงการเขียนข้อมูลตัวแปรไปยังไฟล์เราจะทำให้ตัวแปรนั้นเป็นแบบชั่วคราว
transient int result=10;
หมายเหตุ:ตัวแปรชั่วคราวไม่สามารถอยู่ในท้องที่ได้
ใส่เพียงแค่คำหลักชั่วคราวของ 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;
}
}
รหัสตัวอย่างที่ง่ายขึ้นสำหรับคำหลักชั่วคราว
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);
}
}
ฟิลด์ที่ประกาศพร้อมด้วยตัวแก้ไขชั่วคราวจะไม่เข้าร่วมในกระบวนการที่ทำให้เป็นอนุกรม เมื่อวัตถุถูกทำให้เป็นอนุกรม (บันทึกในสถานะใด ๆ ) ค่าของเขตข้อมูลชั่วคราวจะถูกละเว้นในการแทนแบบอนุกรมในขณะที่เขตข้อมูลอื่นที่ไม่ใช่เขตข้อมูลชั่วคราวจะมีส่วนร่วมในกระบวนการทำให้เป็นอนุกรม นั่นคือวัตถุประสงค์หลักของคำหลักชั่วคราว
@DoNotSerialize
?