Tại sao Java có các trường tạm thời?


Câu trả lời:


1673

Các transienttừ khóa trong Java được sử dụng để chỉ ra rằng một lĩnh vực không phải là một phần của serialization (có nghĩa là lưu lại, như vào một tập tin) quá trình.

Từ Đặc tả ngôn ngữ Java , Phiên bản Java SE 7 , Mục 8.3.1.3. transientLĩnh vực :

Các biến có thể được đánh dấu transientđể chỉ ra rằng chúng không phải là một phần của trạng thái bền bỉ của một đối tượng.

Ví dụ: bạn có thể có các trường có nguồn gốc từ các trường khác và chỉ nên được thực hiện theo chương trình, thay vì trạng thái được duy trì thông qua tuần tự hóa.

Đây là một GalleryImagelớp có chứa một hình ảnh và một hình thu nhỏ xuất phát từ hình ảnh:

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();
    }    
}

Trong ví dụ này, thumbnailImagehình ảnh thu nhỏ được tạo bằng cách gọi generateThumbnailphương thức.

Các thumbnailImagelĩnh vực được đánh dấu như transient, vì vậy chỉ bản gốc imageđược đăng chứ không phải là sự bền bỉ cả ảnh gốc và hình ảnh thu nhỏ. Điều này có nghĩa là sẽ cần ít bộ nhớ hơn để lưu đối tượng được tuần tự hóa. (Tất nhiên, điều này có thể hoặc không thể mong muốn tùy thuộc vào yêu cầu của hệ thống - đây chỉ là một ví dụ.)

Tại thời điểm khử lưu huỳnh, readObjectphương thức được gọi để thực hiện bất kỳ thao tác nào cần thiết để khôi phục trạng thái của đối tượng trở lại trạng thái mà tại đó xảy ra tuần tự hóa. Ở đây, hình thu nhỏ cần được tạo, do đó readObjectphương thức được ghi đè để hình thu nhỏ sẽ được tạo bằng cách gọi generateThumbnailphương thức.

Để biết thêm thông tin, Khám phá bí mật của bài viết API tuần tự hóa Java (vốn có sẵn trên Mạng của nhà phát triển Sun) có một phần thảo luận về việc sử dụng và trình bày một kịch bản trong đó transienttừ khóa được sử dụng để ngăn chặn việc tuần tự hóa các trường nhất định.


221
Nhưng tại sao nó là một từ khóa, mà không phải là một chú thích @DoNotSerialize?
Elazar Leibovich

333
Tôi đoán, đây là sở hữu cho đến thời điểm không có chú thích trong Java.
Peter Wippermann

46
Tôi thấy thật kỳ lạ khi tuần tự hóa là nội bộ đối với Java. Nó có thể được thực hiện như một giao diện hoặc lớp trừu tượng yêu cầu người dùng ghi đè các phương thức đọc và ghi.
caleb

7
@MJafar: readObject thường được kết nối thành các cơ chế khử lưu huỳnh và do đó được gọi tự động. Hơn nữa, trong nhiều trường hợp, bạn không cần ghi đè lên nó - việc triển khai mặc định thực hiện thủ thuật.
Mike Adler

13
@caleb có lẽ vì bản thân việc xử lý các định dạng nhị phân là cực kỳ đau đớn trong Java do thiếu các số nguyên không dấu.
đúng vào

435

Trước khi hiểu transienttừ khóa, người ta phải hiểu khái niệm tuần tự hóa. Nếu người đọc biết về tuần tự hóa, xin vui lòng bỏ qua điểm đầu tiên.

Tuần tự hóa là gì?

Tuần tự hóa là quá trình làm cho trạng thái của đối tượng liên tục. Điều đó có nghĩa là trạng thái của đối tượng được chuyển đổi thành một luồng byte được sử dụng để duy trì (ví dụ: lưu trữ byte trong tệp) hoặc truyền (ví dụ gửi byte qua mạng). Theo cùng một cách, chúng ta có thể sử dụng quá trình khử lưu huỳnh để đưa trạng thái của đối tượng trở lại từ byte. Đây là một trong những khái niệm quan trọng trong lập trình Java vì tuần tự hóa chủ yếu được sử dụng trong lập trình mạng. Các đối tượng cần truyền qua mạng phải được chuyển đổi thành byte. Với mục đích đó, mỗi lớp hoặc giao diện phải thực hiện Serializablegiao diện. Nó là một giao diện đánh dấu mà không có bất kỳ phương pháp.

Bây giờ transienttừ khóa và mục đích của nó là gì?

Theo mặc định, tất cả các biến của đối tượng được chuyển đổi sang trạng thái liên tục. Trong một số trường hợp, bạn có thể muốn tránh tồn tại một số biến vì bạn không có nhu cầu duy trì các biến đó. Vì vậy, bạn có thể khai báo các biến đó là transient. Nếu biến được khai báo là transient, thì nó sẽ không được duy trì. Đó là mục đích chính của transienttừ khóa.

Tôi muốn giải thích hai điểm trên với ví dụ sau:

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);
    }
}

Và đầu ra sẽ như sau:

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

Tên đệm được khai báo là transient, vì vậy nó sẽ không được lưu trữ trong bộ lưu trữ liên tục.

Nguồn


26
Ví dụ này được lấy từ mã này, bạn có thể đọc nó ở đây: javabeat.net/2009/02/what-is-transient-keyword-in-java
Krishna

11
Phần này đánh tôi là kỳ quặc và có thể gây nhầm lẫn: "Điều đó có nghĩa là trạng thái của đối tượng được chuyển đổi thành một luồng byte và được lưu trữ trong một tệp ". Dường như với tôi rằng hầu hết thời gian tuần tự hóa không liên quan đến việc ghi vào một tệp (trường hợp cụ thể: các ví dụ về mạng theo sau)
Garcia Hurtado

5
Ví dụ là một cái xấu, vì tên đệm rõ ràng không phải là một tài sản tạm thời.
Raphael

1
@Raphael Đối với tôi, ví dụ này rất hữu ích và ít nhất là giải thích khái niệm này. Bạn sẽ cung cấp bất kỳ ví dụ tốt hơn nếu bạn nhận thức được?
Chaklader Asfak Arefe

@Yoda Chúng tôi có thể có một tài liệu tham khảo cho một NameFormatterổ đĩa được sử dụng toString(). Hoặc bất cứ điều gì khác liên quan đến cấu hình, hoặc xem, hoặc logic kinh doanh, ... trái ngược với dữ liệu.
Raphael

84

Để cho phép bạn xác định các biến mà bạn không muốn tuần tự hóa.

Trong một đối tượng, bạn có thể có thông tin mà bạn không muốn tuần tự hóa / tồn tại (có lẽ là một tham chiếu đến đối tượng nhà máy mẹ) hoặc có lẽ nó không có ý nghĩa để tuần tự hóa. Đánh dấu chúng là 'thoáng qua' có nghĩa là cơ chế tuần tự hóa sẽ bỏ qua các trường này.


36

Đóng góp nhỏ của tôi:

Một lĩnh vực thoáng qua là gì?
Về cơ bản, bất kỳ trường nào được sửa đổi với transienttừ khóa là một trường thoáng qua.

Tại sao các trường tạm thời cần thiết trong Java?
Các transienttừ khóa cung cấp cho bạn một số kiểm soát quá trình tuần tự và cho phép bạn loại trừ một số tài sản đối tượng từ quá trình này. Quá trình tuần tự hóa được sử dụng để duy trì các đối tượng Java, chủ yếu là để các trạng thái của chúng có thể được bảo tồn trong khi chúng được chuyển hoặc không hoạt động. Đôi khi, không có nghĩa là không tuần tự hóa các thuộc tính nhất định của một đối tượng.

Những lĩnh vực bạn nên đánh dấu thoáng qua?
Bây giờ chúng tôi biết mục đích củatransienttừ khóa và trường tạm thời, điều quan trọng là phải biết trường nào cần đánh dấu thoáng qua. Các trường tĩnh không được tuần tự hóa, do đó, từ khóa tương ứng cũng sẽ thực hiện thủ thuật. Nhưng điều này có thể làm hỏng thiết kế lớp học của bạn; đây là nơi mà ), thì không cần phải tuần tự hóa nó. Một ví dụ tốt là với số lượng từ bài viết. Nếu bạn đang lưu toàn bộ một bài viết, thực sự không cần phải lưu số từ, bởi vì nó có thể được tính khi bài viết được "giải trừ". Hoặc suy nghĩ về logger;transienttừ khóa đến để giải cứu. Tôi cố gắng không cho phép các trường có giá trị có thể được lấy từ các trường khác được nối tiếp, vì vậy tôi đánh dấu chúng là tạm thời. Nếu bạn có một trường được gọi là interestcó giá trị có thể được tính từ các trường khác ( principal, rate&time

Logger các trường hợp hầu như không bao giờ cần phải được tuần tự hóa, vì vậy chúng có thể được thực hiện tạm thời.


63
"Câu đơn giản" của bạn chỉ đơn thuần là một tautology. Nó không giải thích gì cả. Bạn sẽ tốt hơn nếu không có nó.
Hầu tước Lorne

1
Đây là một lời giải thích tốt nơi lĩnh vực nên đượctransient
Chaklader Asfak Arefe

1
lĩnh vực quan tâm và số từ là ví dụ tốt về các trường tạm thời.
Tarun

1
Một trường hợp sử dụng tốt khác: Nếu đối tượng của bạn có các thành phần như ổ cắm và nếu bạn muốn tuần tự hóa thì điều gì xảy ra với ổ cắm? Nếu vẫn còn, sau khi bạn khử lưu huỳnh thì ổ cắm sẽ giữ cái gì? Thật ý nghĩa khi biến đối tượng ổ cắm đó thànhtransient
Mohammed Siddiq

28

Một transientbiến là một biến có thể không được nối tiếp.

Một ví dụ về điều này có thể hữu ích trong tâm trí là, các biến chỉ có ý nghĩa trong ngữ cảnh của một đối tượng cụ thể và trở nên không hợp lệ khi bạn đã tuần tự hóa và giải tuần tự hóa đối tượng. Trong trường hợp đó, thật hữu ích khi có các biến đó trở thành nullđể bạn có thể khởi tạo lại chúng với dữ liệu hữu ích khi cần.


vâng, một số thứ như các thành viên trường "mật khẩu hoặc creditiCardPin" của một lớp.
Mateen

17

transientđược sử dụng để chỉ ra rằng một trường lớp không cần phải được tuần tự hóa. Có lẽ ví dụ tốt nhất là một Threadlĩnh vực. Thường không có lý do để tuần tự hóa một Thread, vì trạng thái của nó là rất 'cụ thể dòng chảy'.


Chỉnh sửa cho tôi nếu tôi sai, nhưng Thread không được tuần tự hóa nên nó sẽ bị bỏ qua?
TFennis

3
@TFennis: Nếu một lớp tuần tự hóa Atham chiếu một lớp không tuần tự hóa B(như Threadtrong ví dụ của bạn), thì Aphải đánh dấu tham chiếu là transientXOR phải ghi đè quá trình tuần tự hóa mặc định để làm điều gì đó hợp lý với BXOR giả định rằng chỉ các lớp con tuần tự hóa Bthực sự được tham chiếu (vì vậy lớp con thực tế phải chăm sóc cho cha mẹ "xấu" của họ B) XOR chấp nhận rằng việc xê-ri hóa sẽ thất bại. Chỉ có một trường hợp (được đánh dấu là thoáng qua) Bđược tự động và âm thầm bỏ qua.
AH

3
@TFennis Không, nó sẽ gây ra ngoại lệ.
Hầu tước Lorne

1
@AH: Tại sao XOR? Tôi nghĩ rằng mã đã thực hiện bất kỳ sự kết hợp nào của những thứ đó sẽ hoạt động và một số kết hợp có thể hữu ích (ví dụ: ghi đè quá trình tuần tự hóa mặc định có thể hữu ích ngay cả khi chỉ các lớp con tuần tự hóa của B được tham chiếu và ngược lại).
supercat

15

Các hệ thống tuần tự hóa khác với java gốc cũng có thể sử dụng công cụ sửa đổi này. Chẳng hạn, Hibernate sẽ không duy trì các trường được đánh dấu bằng @Transient hoặc công cụ sửa đổi tạm thời . Terracotta cũng tôn trọng sửa đổi này.

Tôi tin rằng ý nghĩa tượng trưng của công cụ sửa đổi là "trường này chỉ dành cho sử dụng trong bộ nhớ. Đừng kiên trì hoặc di chuyển nó ra ngoài VM cụ thể này theo bất kỳ cách nào. Nó không di động". tức là bạn không thể dựa vào giá trị của nó trong không gian bộ nhớ VM khác. Giống như dễ bay hơi có nghĩa là bạn không thể dựa vào ngữ nghĩa bộ nhớ và chủ đề nhất định.


14
Tôi nghĩ rằng đó transientsẽ không phải là một từ khóa nếu nó được thiết kế tại thời điểm này. Họ có thể sử dụng một chú thích.
Joachim Sauer

9

Bởi vì không phải tất cả các biến đều có tính chất tuần tự


42
Vui lòng cung cấp thêm thông tin khi bạn đưa ra câu trả lời.
Danny Gloudemans

7

Trước khi tôi trả lời câu hỏi này, tôi phải giải thích cho bạn SERIALIZATION , bởi vì nếu bạn hiểu ý nghĩa hóa trong máy tính khoa học, bạn có thể dễ dàng hiểu từ khóa này.

Tuần tự hóa Khi một đối tượng được truyền qua mạng / được lưu trên phương tiện vật lý (tệp, ...), đối tượng phải được "tuần tự hóa". Tuần tự hóa chuyển đổi chuỗi đối tượng trạng thái byte. Các byte này được gửi trên mạng / được lưu và đối tượng được tạo lại từ các byte này.
Thí dụ

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

Bây giờ NẾU BẠN MUỐN KHÔNG CHUYỂN ĐỔI / SAVED trường của đối tượng này SO , bạn có thể sử dụng từ khóa transient

private transient attr2;

Thí dụ


6

Điều đó là cần thiết khi bạn không muốn chia sẻ một số dữ liệu nhạy cảm đi kèm với tuần tự hóa.


7
Có những trường hợp sử dụng khác với dữ liệu nhạy cảm mà bạn có thể không muốn tuần tự hóa một trường. Ví dụ: có thể bạn sẽ không bao giờ muốn tuần tự hóa Thread(tín dụng cho @AH chẳng hạn), trong trường hợp đó bạn sẽ đánh dấu nó là tạm thời. Tuy nhiên, một luồng không phải là dữ liệu nhạy cảm trong chính nó, nó chỉ không có ý nghĩa logic để tuần tự hóa nó (và nó không được tuần tự hóa).
glen3b

1
@ glen3b Trường hợp đó không được loại trừ bởi câu trả lời này. Nó chắc chắn là cần thiết khi mọi thứ đứng trong trường hợp áp phích đề cập.
Hầu tước Lorne

3

Theo google nghĩa thoáng qua == chỉ tồn tại trong một thời gian ngắn; vô thường.

Bây giờ nếu bạn muốn làm bất cứ điều gì thoáng qua trong java, hãy sử dụng từ khóa thoáng qua.

Q: sử dụng tạm thời ở đâu?

Trả lời: Nói chung trong java, chúng ta có thể lưu dữ liệu vào các tệp bằng cách lấy chúng trong các biến và ghi các biến đó vào tệp, quá trình này được gọi là Tuần tự hóa. Bây giờ nếu chúng ta muốn tránh dữ liệu biến được ghi vào tệp, chúng ta sẽ biến biến đó thành tạm thời.

transient int result=10;

Lưu ý: các biến tạm thời không thể là cục bộ.


0

Nói một cách đơn giản, từ khóa java tạm thời bảo vệ các trường khỏi được Nối tiếp như là các phần không phải là trường tạm thời của chúng.

Trong đoạn mã này, lớp trừu tượng BaseJob của chúng tôi triển khai giao diện Nối tiếp, chúng tôi mở rộng từ BaseJob nhưng chúng tôi không cần tuần tự hóa các nguồn dữ liệu từ xa và cục bộ; chỉ tuần tự hóa các trường organName và isSynced.

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

Mã ví dụ đơn giản hóa cho từ khóa thoáng qua.

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

Một trường được khai báo với công cụ sửa đổi nhất thời, nó sẽ không tham gia vào quá trình tuần tự hóa. Khi một đối tượng được tuần tự hóa (được lưu trong bất kỳ trạng thái nào), các giá trị của các trường tạm thời của nó bị bỏ qua trong biểu diễn nối tiếp, trong khi trường không phải là các trường tạm thời sẽ tham gia vào quá trình tuần tự hóa. Đó là mục đích chính của từ khóa thoáng qua.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.