Java 中的變數:它們是什麼以及如何使用它們
來源:
Hackernoon Java 中有四種不同類型的變量,取決於它們在程式中聲明的位置。今天您將學習每種類型的範例和差異。 1. 實例變數或
實例欄位是在類別內部不使用
static關鍵字但在方法、建構子或程式碼區塊外部宣告的變數。此類變數可以在類別中的任何位置聲明。您可以使用或不使用存取修飾符來聲明它們,例如
public、
private、
protected或
default(不是關鍵字)。
public class MyClass {
private String instanceField1;
public MyClass(){}
public int anotherInstanceField2;
public void setInstanceField(String parameterVariable) {...}
boolean instanceField3;
public static void main(String[] args) {
System.out.println("field 1 value: " + instanceField1);
System.out.println("field 2 value: " + anotherInstanceField2);
System.out.println("field 3 value: " + instanceField3);
}
}
如果實例欄位在宣告時未賦值,則如果它是基本類型,則為其指派預設值 0,例如(
int、
boolean、
long、
float),如果它不是基本類型,則為
null String、
Integer、
AnyClass)。它們被稱為字段或實例變量,因為它們屬於從聲明它們的類別創建的任何物件的實例。
public Main {
public static void main(String[] args) {
MyClass obj1 = new MyClass();
MyClass obj2 = new MyClass();
obj1.anotherInstanceField2 = 11;
obj2.anotherInstanceField2 = 33;
System.out.println(obj1.anotherInstanceField2);
System.out.println(obj2.anotherInstanceField2);
}
}
因此,每個實例欄位對其物件來說都是唯一的,如上面的程式碼片段所示。其中,
obj1和
obj2為各自的實例欄位分配了唯一的值。
2. 類別字段或
靜態字段是用static關鍵字聲明的字段。它們在類別內部聲明,但在方法、建構子或程式碼區塊外部聲明。它們還可以在類別中的任何位置聲明,無論是否帶有存取修飾符,例如
public、
private、
protected或
default(不是關鍵字)。
public class MyClass {
public static String staticField;
public MyClass(){}
}
class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.staticField
MyClass.staticField = "I am a static field";
System.out.println(MyClass.staticField);
}
}
靜態字段只能透過其類別訪問,而不能從任何物件訪問,如上面的程式碼片段所示。3.
參數或
參數變數是在方法簽署的左大括號和右大括號之間宣告的方法建構內的變數。它們用於將值或物件傳遞給方法。
public class MyClass {
public String instanceField;
public MyClass(){}
public void setInstanceField(String parameterVariable) {
instanceField = parameterVariable;
}
}
class Main {
public static void main(String[] args) {
MyClass obj = new MyClass();
obj.setInstanceField("From a parameter variable");
System.out.println(obj.instanceField);
}
}
4.
局部變數是在方法或任何程式碼區塊內宣告的變量,例如,在
if語句區塊、
for 迴圈、
while 迴圈、
switch語句區塊等內宣告的變數。
public Main {
public static void main(String[] args) {
MyClass obj1 = new MyClass();
int id = 1;
if (id > 1) {
String tempName = "Austin";
}
}
}
在此程式碼中,您可以注意到對某些變數使用了引用,而局部變數
id並未被提及為引用變數。任何非原始變數都是引用變數。例如,
obj1是MyClass類型的變數,
tempName是String類型的變數,這裡這兩種類型都不是原始類型。在本例中,
id是int型別的變量,它是原始資料型別。因此,它是一個非引用變數。
關於 Java 序列化和反序列化您應該了解的 5 件事
來源:
Devgenius 透過本教程,您將提高對序列化和反序列化工作原理的了解。 Java 中的序列化有助於將現有物件轉換為位元組流。相反,反序列化使位元組流成為物件。使用 Java 中的序列化和反序列化,可以將有關物件的資訊從一個 JVM 傳輸到另一個 JVM。
#1 序列化
在詳細介紹之前,我們先來看看
SerializeUtils.java和
Person.java類別。這裡他們將使用具體的例子來幫助我們進行序列化和反序列化。
SerializeUtils.java
package com.techteam.serialization;
import java.io.*;
public class SerializeUtils {
public static <T> void serialize(T input, String fileName) throws IOException {
FileOutputStream file = new FileOutputStream(fileName);
ObjectOutputStream out = new ObjectOutputStream(file);
out.writeObject(input);
out.close();
file.close();
}
public static <T> T deserialize(String fileName) throws IOException, ClassNotFoundException {
FileInputStream file = new FileInputStream(fileName);
ObjectInputStream in = new ObjectInputStream(file);
T result = (T) in.readObject();
return result;
}
public static void externalSeialize(Externalizable e, String fileName) throws IOException {
FileOutputStream file = new FileOutputStream(fileName);
ObjectOutputStream out = new ObjectOutputStream(file);
e.writeExternal(out);
out.close();
file.close();
}
public static void externalDeseialize(Externalizable e, String fileName) throws IOException, ClassNotFoundException {
FileInputStream file = new FileInputStream (fileName);
ObjectInputStream in = new ObjectInputStream (file);
e.readExternal(in);
in.close();
file.close();
}
}
人.java
package com.techteam.serialization;
import java.io.Serializable;
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
如前所述,序列化有助於將物件轉換為位元組流。這意味著有關物件的所有資訊也被轉換為位元組流,例如方法、屬性和資料。下面是一個物件如何序列化的範例:
package com.techteam.serialization;
import java.io.IOException;
public class SerializationMain {
public static void main(String[] args) throws IOException {
Person p = new Person();
p.setId(1);
p.setName("Tech team members");
p.setAge(20);
SerializeUtils.serialize(p, "/person.txt");
}
}
序列化過程之後,我們有一個包含以下內容的文件:
#2 反序列化
如果在前面的範例中我們透過序列化物件建立了位元組流,現在讓我們看看如何使用反序列化返回物件:
package com.techteam.serialization;
import java.io.IOException;
public class DeserializationMain {
public static void main(String[] args) throws IOException, ClassNotFoundException {
Person p = SerializeUtils.deserialize("/person.txt");
System.out.println("Person data:");
System.out.println(p.getId());
System.out.println(p.getName());
System.out.println(p.getAge());
}
}
這是反序列化後的資料:
#3 序列版本 UID
SerialVersionUID表示序列化和反序列化過程的每個版本的唯一識別號碼。該數字用於確保序列化和反序列化物件都使用相容的類別。對於
Person.java,我想將serialVersionUID增加到2。讓我們看看反序列化person.txt檔案後的輸出。
#4 關鍵字瞬態
在序列化和反序列化的過程中,有時我們並不需要序列化一個物件的所有資訊。透過對變數使用瞬態過程,我們可以忽略正在序列化的物件中的這些變數。下面的例子將有助於更清楚地理解這一點:
package com.techteam.serialization;
import java.io.IOException;
import java.io.Serializable;
public class PersonWithTransient implements Serializable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private transient int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
PersonWithTransient p = new PersonWithTransient();
p.setId(2);
p.setName("Tech team members(transient)");
p.setAge(50);
SerializeUtils.serialize(p, "/person_transient.txt");
PersonWithTransient deserializeP = SerializeUtils.deserialize("/person_transient.txt");
System.out.println("Person without transient data:");
System.out.println(deserializeP.getId());
System.out.println(deserializeP.getName());
System.out.println(deserializeP.getAge());
}
}
在上面的程式碼中,我們對
age變數使用了transient 關鍵字。這就是我們在序列化和反序列化過程之後所得到的結果。
#5 可外部化的接口
在Java中,當我們想要自訂序列化和反序列化過程時,我們可以使用一個轉換過程來忽略序列化和反序列化過程中不需要的變數。另一種簡化和提高效能的方法是使用
Externalized介面而不是Serialized介面。讓我們來看一個例子:
package com.techteam.serialization;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
public class PersonExternalizable implements Externalizable {
private static final long serialVersionUID = 1L;
private int id;
private String name;
private int age;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(this.name);
out.writeInt(this.age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.name = in.readUTF();
this.age = in.readInt();
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
PersonExternalizable p = new PersonExternalizable();
p.setId(3);
p.setName("Tech team members(Externalizable)");
p.setAge(30);
SerializeUtils.externalSeialize(p, "/person_externalizable.txt");
PersonExternalizable deserializeP = new PersonExternalizable();
SerializeUtils.externalDeseialize(deserializeP, "/person_externalizable.txt");
System.out.println("Person data:");
System.out.println(deserializeP.getId());
System.out.println(deserializeP.getName());
System.out.println(deserializeP.getAge());
}
}
正如您所看到的,使用
Externalized時,我們可以輕鬆編寫自訂邏輯,忽略變數並獲得比使用
Serialized更好的效能。現在讓我們來看看輸出:
結論
希望透過本文,您能夠清楚地了解 Java 中的序列化和反序列化是如何運作的,並且上面的範例可以對您將來的實踐有所幫助。
GO TO FULL VERSION