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