>  기사  >  Java  >  Java의 임시 키워드에 대한 자세한 설명

Java의 임시 키워드에 대한 자세한 설명

angryTom
angryTom앞으로
2019-11-26 16:14:581812검색

솔직히 Java를 오랫동안 공부한 친구들은 아직도 Transient라는 키워드가 매우 낯설고 거의 사용하지 않습니다. 하지만 Transient라는 키워드는 Java에서 없어서는 안 될 역할을 합니다! 이에 대해 이야기하고 싶다면 IO 스트림의 개체 스트림(직렬화된 스트림이라고도 함)이 나타날 가능성이 가장 높은 곳이라고 생각합니다!

Java의 임시 키워드에 대한 자세한 설명

저는 많은 사람들이 이 키워드를 접하기 전까지는 이 키워드에 관심을 갖지 않을 것이라고 믿습니다. 블로거들이 처음으로 임시 키워드를 접한 것은 JDK 소스 코드를 읽을 때였음을 기억합니다. Java를 학습하는 과정에서 Transient 키워드가 드문 이유는 실제로 그 기능과 분리될 수 없습니다. Transient 키워드의 주요 기능은 Transient 키워드에 의해 수정된 일부 멤버 속성 변수가 직렬화되는 것을 방지하는 것입니다. 실제로 직렬화 작업이 학습 프로세스, 일반적으로 실제 개발에서 거의 사용되지 않는 것이 바로 이러한 이유입니다! 연재에 관해서는 많은 초보자들이 헷갈려하거나 구체적인 개념이 없다고 생각합니다. 이것은 문제가 되지 않습니다. 다음 블로거는 여러분에게 연재가 무엇인지 명확하게 알려줄 것이며, 평생 잊지 못할 것입니다. 조금 과장, 조금 가식, 맞을 것 같은 느낌)

1. 연재란?

직렬화와 함께 제공되는 또 다른 개념은 역직렬화입니다. 초보자 여러분, 직렬화를 기억하는 것은 역직렬화를 기억하는 것과 같습니다. 역직렬화는 직렬화의 반대이기 때문에 블로거는 개념만 기억할 것을 권장합니다. 혼란을 피하기 위해 직렬화를 사용합니다.

(추천 동영상: java 동영상 튜토리얼)

전문 용어로 정의된 직렬화:

Java는 객체 직렬화를 위한 메커니즘을 제공합니다. 객체는 객체의 데이터, 객체 유형, 객체에 저장된 속성과 같은 정보를 포함하는 바이트 시퀀스로 표현될 수 있습니다. 바이트 시퀀스가 ​​파일에 기록된 후 이는 파일에 개체 정보를 유지하는 것과 같습니다. 반대로, 파일에서 바이트 시퀀스를 다시 읽고 객체를 재구성하고 역직렬화할 수 있습니다. 객체의 데이터, 객체의 유형, 객체에 저장된 데이터 정보를 모두 사용하여 메모리에 객체를 생성할 수 있습니다.

직렬화: Byte -> Object

사실 제가 요약한 내용은 위의 결론입니다. 이해가 안 되시면 전문 용어의 정의를 참고하시면 됩니다. 기억나지 않아 죽여줘

직렬화 이해하기:

Java의 임시 키워드에 대한 자세한 설명

2. 왜 직렬화하는가?

직렬화의 개념은 이전 섹션에서 언급했습니다. 개념을 알고 나면 왜 직렬화를 해야 하는지 알아야 합니다.

연재가 필요한 이유에 대해 이야기하기 전에 블로거님, 예를 하나 들어보겠습니다.

길거리에서 야채를 사러 갈 때와 마찬가지로 일반적인 작업은 비닐봉지에 포장한 다음 집에 와서 요리할 때 야채를 꺼내세요. 그리고 이 일련의 작업은 직렬화 및 역직렬화와 같습니다!

Java에서 객체의 직렬화는 객체를 바이트 시퀀스 형태의 표현으로 변환하는 것을 의미합니다. 이러한 바이트 시퀀스에는 객체의 데이터와 정보가 포함되어 있으며 데이터베이스나 파일에 사용될 수도 있습니다. 일반적으로 캐시(하드 디스크에 로컬로 저장되는 메모리 공간이 충분하지 않을 수 있음)를 사용하거나 원격으로 rpc(네트워크 전송)를 호출할 때 엔터티 클래스가 직렬화 가능 인터페이스를 구현하도록 해야 하는 경우가 많습니다. 직렬화 가능합니다.

개발 과정에서 임시 키워드로 수정해야 하는 밤:

사용자가 일부 비밀번호 및 기타 정보를 가지고 있고 보안을 위해 네트워크 운영 중에 전송을 원하지 않는 경우에 해당하는 변수 이 정보는 임시 키 문자를 사용하여 추가할 수 있습니다. 즉, 이 필드의 수명 주기는 호출자의 메모리에만 존재하며 지속성을 위해 디스크에 기록되지 않습니다.

개발 과정에서 임시 키워드 수정이 필요하지 않은 예:

1. 클래스의 필드 값은 다른 필드를 기반으로 파생될 수 있습니다.

2. 특정 비즈니스 요구 사항에 따라 어떤 필드를 연재하지 말아야 하는지 궁금합니다.

왜 연재하면 안 되는지 생각해 보셨나요? 사실 주로 저장 공간을 절약하기 위한 것입니다. 프로그램을 최적화하세요!

PS: HashMap 소스 코드를 볼 때 필드가 일시적으로 수정된 것을 발견했습니다. modCount 필드는 주로 의미가 없기 때문에 실제로 의미가 있다고 생각합니다. HashMap을 판단하는 데 사용됩니다. 수정 여부(넣고 제거하는 동안 modCount가 자동으로 증가함) 이러한 종류의 변수의 경우 처음에는 어떤 값이든 가능하며 0도 허용됩니다(새 항목이 나오면 역직렬화 또는 복제)가 0인 경우 해당 값을 유지할 필요가 없습니다.

물론, 직렬화 후의 최종 목적은 직렬화를 해제하여 원래 Java 객체로 복원하는 것입니다. 그렇지 않으면 식료품을 구매하는 것처럼 비닐봉지에 싸서 편리함과 안전을 위해 최종적으로 플라스틱을 제거하는 것입니다. 집에 돌아가는 과정이므로 직렬화된 바이트 시퀀스를 Java 객체로 복원할 수 있습니다.

3. 직렬화 및 임시 사용

1. 직렬화해야 하는 객체 클래스는 Java Most에서 직렬화 인터페이스인 Java.lang.Serialized 인터페이스(추상 메서드가 없는 플래그 인터페이스)를 구현해야 합니다. 클래스는 String, Integer 등과 같은 이 인터페이스를 구현합니다. 이 인터페이스를 구현하지 않는 클래스는 상태를 직렬화하거나 역직렬화하지 않으며 NotSerializedException을 발생시킵니다.

2. 하위 계층에서는 현재 객체가 Serialized의 인스턴스인 경우 Serialize의 Java 객체 인스턴스를 사용하여 판단합니다.

3. Java에서 객체 스트림 ObjectOutputStream을 사용하여 직렬화 및 ObjectInputStream 스트림 역직렬화를 완료합니다.

==ObjectOutputStream: writeObject() 메서드를 통한 직렬화 작업== 

==ObjectInputStream: readObject() 메서드를 통해 역직렬화 작업 수행==

4. 이 클래스의 모든 속성은 직렬화 가능해야 합니다. 직렬화할 필요가 없는 속성이 있는 경우 해당 속성을 임시로 표시하고 임시 키워드를 사용하여 수정해야 합니다.

Java의 임시 키워드에 대한 자세한 설명

바이트 때문에 스트림 연산이 포함되어야 합니다. 즉, 객체 스트림은 직렬화된 스트림이라고도 합니다. ObjectOutputstream 직렬화된 연산 코드를 다양한 상황에서 분석해 보겠습니다!

여기서 이춘 블로그를 읽는 독자들에게 정말 강력히 추천합니다. 타이핑을 해보고, 한눈에 가져가거나 복사해서 실행하는 것을 잊지 마세요. 특히 작은 흰색 어린이 신발의 경우 저를 믿으세요! 당신은 확실히 뭔가 다른 것을 얻을 것입니다. !

3.1.직렬화 가능 인터페이스를 구현하지 않은 직렬화

package TransientTest;
import java.io.*;

class UserInfo { //================================注意这里没有实现Serializable接口
    private String name;
    private transient String password;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) {

        UserInfo userInfo = new UserInfo("老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt"));
            output.writeObject(new UserInfo("老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

실행 결과

Java의 임시 키워드에 대한 자세한 설명

3.2.직렬화 가능 인터페이스를 구현한 직렬화

직렬화 가능 인터페이스를 추가하고 다시 실행하면 프로젝트에 사용자 정보가 나타나는 것을 확인할 수 있습니다. .txt 파일의 내용은 다음과 같습니다.

Java의 임시 키워드에 대한 자세한 설명

사실 요점은 직렬화 작업이 성공했다는 것입니다!

3.3.일반적인 직렬화 상황

package TransientTest;
import java.io.*;

class UserInfo implements Serializable { //第一步实现Serializable接口
    private String name;
    private String password; //都是普通属性==============================

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo = new UserInfo("程序员老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作
            output.writeObject(new UserInfo("程序员老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作
            Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException
            System.out.println("序列化之后信息:" + o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

실행 결과:

序列化之前信息:UserInfo{name='程序员老王', password='123'}
序列化之后信息:UserInfo{name='程序员老王', password='123'}

3.4.일시적 직렬화 상황

package TransientTest;
import java.io.*;

class UserInfo implements Serializable { //第一步实现Serializable接口
    private String name;
    private transient String password; //特别注意:属性由transient关键字修饰===========

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo = new UserInfo("程序员老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作
            output.writeObject(new UserInfo("程序员老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作
            Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException
            System.out.println("序列化之后信息:" + o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

실행 결과:

序列化之前信息:UserInfo{name='程序员老王', password='123'}
序列化之后信息:UserInfo{name='程序员老王', password='null'}

결과에 특히 주의하세요. 임시 수정으로 추가된 속성 값은 기본값인 null입니다. Transient에 의해 수정된 속성이 int 유형인 경우 직렬화된 후 해당 값은 0이어야 합니다. 이것이 의미하는 바는 무엇입니까? 이는 개체가 직렬화될 때 임시로 표시된 속성이 저장되지 않는다는 의미입니다(또는 변수가 지속되지 않음)

3.5, 정적 직렬화 상황

package TransientTest;
import java.io.*;

class UserInfo implements Serializable { //第一步实现Serializable接口
    private String name;
    private static String password; //特别注意:属性由static关键字修饰==============

    public UserInfo(String name, String psw) {
        this.name = name;
        this.password = psw;
    }

    @Override
    public String toString() {
        return "UserInfo{" +
            "name='" + name + '\'' +
            ", password='" + password + '\'' +
            '}';
    }
}

public class TransientDemo {
    public static void main(String[] args) throws ClassNotFoundException {

        UserInfo userInfo = new UserInfo("程序员老王", "123");
        System.out.println("序列化之前信息:" + userInfo);

        try {
            ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作
            output.writeObject(new UserInfo("程序员老王", "123"));
            output.close();
        } catch (IOException e) {
            e.printStackTrace();
        }

        try {
            ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作
            Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException
            System.out.println("序列化之后信息:" + o);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

실행 결과:

序列化之前信息:UserInfo{name='程序员老王', password='123'}
序列化之后信息:UserInfo{name='程序员老王', password='123'}

이때, 실수로 정적 수정도 직렬화되어 있다고 생각했는데, 사실 여기서는 헷갈리기 쉽습니다! 분명히 null(기본값)을 빼면 그것이 직렬화되지 않을 것이라는 것을 알 수 있습니다. 왜 아직도 static이 직렬화되지 않을 것이라고 말하는가?

사실 deserialization 후 클래스의 정적 변수 이름 값은 실제로 현재 JVM의 해당 정적 변수 값입니다. 이 값은 JVM에 있으며 deserialization에서 파생되지 않습니다. 즉, static으로 수정된 변수는 직렬화에 참여하지 않습니다! 하지만 증거 없이는 말할 수 없습니다. 두 프로그램을 비교해보면 이해가 될 것입니다.

첫 번째 프로그램: 정적으로 수정되지 않은 이름 속성 프로그램입니다.

package Thread;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {
    private String name;
    private transient String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }

    public String toString() {
        return "name=" + name + ", psw=" + psw;
    }
}
public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("程序员老过", "456");
        System.out.println(userInfo);
        try {
            // 序列化,被设置为transient的属性没有被序列化
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        try {
            //在反序列化之前改变name的值 =================================注意这里的代码
            userInfo.setName("程序员老改");
            // 重新读取内容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));
            UserInfo readUserInfo = (UserInfo) in .readObject();
            //读取后psw的内容为null
            System.out.println(readUserInfo.toString());
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

실행 결과:

name=程序员老过, psw=456name=程序员老过, psw=null

프로그램 실행 결과에서 볼 수 있듯이 deserialization 전에 name 값을 변경해 보세요. 프로그래머를 위해 이를 변경하려고 노력했지만 결과는 성공하지 못했습니다!

두 번째 프로그램: 이것은 static으로 수정된 이름 속성 프로그램입니다:

package Thread;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

class UserInfo implements Serializable {
    private static final long serialVersionUID = 996890129747019948 L;
    private static String name;
    private transient String psw;

    public UserInfo(String name, String psw) {
        this.name = name;
        this.psw = psw;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPsw() {
        return psw;
    }

    public void setPsw(String psw) {
        this.psw = psw;
    }

    public String toString() {
        return "name=" + name + ", psw=" + psw;
    }
}
public class TestTransient {
    public static void main(String[] args) {
        UserInfo userInfo = new UserInfo("程序员老过", "456");
        System.out.println(userInfo);
        try {
            // 序列化,被设置为transient的属性没有被序列化
            ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt"));
            o.writeObject(userInfo);
            o.close();
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
        try {
            //在反序列化之前改变name的值
            userInfo.setName("程序员老改");
            // 重新读取内容
            ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt"));
            UserInfo readUserInfo = (UserInfo) in .readObject();
            //读取后psw的内容为null
            System.out.println(readUserInfo.toString());
        } catch (Exception e) {
            // TODO: handle exception
            e.printStackTrace();
        }
    }
}

실행 결과:

name=程序员老过, psw=456name=程序员老改, psw=null

프로그램 실행 결과에서 볼 수 있듯이, 프로그래머가 모두 변경하도록 역직렬화하기 전에 이름 값을 변경해 보십시오. 시간, 결과는 성공적이었습니다! 이제 두 프로그램을 비교해 보면 매우 명확해졌나요?

static 키워드로 수정된 멤버 속성은 비정적 멤버 속성보다 메모리에 더 잘 로드됩니다. 동시에 static은 메모리에 들어가는 개체보다 좋습니다. 직렬화된 모든 개체는 정적 변수일 수 없습니다. . 객체 상태의 일부가 아니므로 직렬화에 참여하지 않습니다. 따라서 정적 변수를 임시 변수로 선언하는 것은 쓸모가 없습니다. 따라서 deserialization 후 클래스의 정적 변수 이름 값은 실제로 현재 JVM의 해당 정적 변수 값입니다. 이 값은 JVM에 있으며 deserialization에서 파생되지 않습니다.

3.6.최종 직렬화 상황

최종 변수는 값을 통해 직접 직렬화에 참여하게 되며, 코드 프로그램은 더 이상 최종 수정본을 사용해 검증해 볼 수 없습니다. 그것!

가장 중요한 점은 final과 temporary가 동시에 동일한 변수를 수정할 수 있으며 결과가 동일하다는 점입니다. 여기서는 주로 언급할 때 혼동하지 마시기 바랍니다. 앞으로 개발 과정에서 이러한 상황에 직면하게 될 것입니다!

4. Java 클래스에서 serialVersionUID의 역할

transient 키워드를 언급했으니 직렬화를 언급했으니 serialVersionUID가 무엇인가요? 기본적으로 이 serialVersionUID는 직렬화가 있는 경우 존재합니다.

Java의 임시 키워드에 대한 자세한 설명

serialVersionUID는 Java의 직렬화 메커니즘에 적합합니다. 간단히 말해서 Java의 직렬화 메커니즘은 클래스의 serialVersionUID를 판단하여 버전 일관성을 확인합니다. 역직렬화할 때 JVM은 전달된 바이트 스트림의 serialVersionUID를 해당 로컬 엔터티 클래스의 serialVersionUID와 비교합니다. 동일하면 일관성이 있는 것으로 간주되고 역직렬화될 수 있습니다. 그렇지 않으면 직렬화된 버전이 일치하지 않습니다. 즉, InvalidCastException은 개발 중에 작성되거나 작성되지 않는 경우가 있으므로 작성하는 것이 좋습니다.

5. 임시 키워드 요약

1. 임시로 변수를 수정하면 해당 변수는 직렬화되지 않습니다.
2 임시 키워드는 변수만 수정할 수 있으며 메서드와 클래스는 수정할 수 없습니다.
3. static 키워드로 수정된 변수는 직렬화에 참여하지 않습니다.
4. 최종 변수 값은 직렬화에 참여하고 동시에 최종 과도는 변수를 수정합니다. 최종은 과도에 영향을 주지 않으며 직렬화에 참여하지 않습니다. 일시적인 키워드. 변수가 사용자 정의 클래스 변수인 경우 클래스는 직렬화 가능 인터페이스를 구현해야 합니다. 세 번째로 주목해야 할 점은 역직렬화 후 클래스의 정적 변수 값은 실제로 현재 클래스의 해당 정적 변수 값입니다. JVM 이 값은 JVM에 있으며 역직렬화에서 파생되지 않습니다.

결론: 임시 키워드로 수정하면 직렬화되지 않습니다. 장점은 저장 공간을 절약할 수 있다는 것입니다. 프로그램을 최적화하세요! 다음은 Transient에 의해 수정된 필드가 다시 계산되고 초기화된다는 것입니다!

이 기사는 PHP 중국어 웹사이트,

java tutorial

칼럼에서 가져온 것입니다. 환영합니다!

위 내용은 Java의 임시 키워드에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 cnblogs.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제