一、static
static 可以用来修饰变量、方法、代码块。
1. static 修饰变量:
被 static 修饰的变量叫静态变量或类变量, 没有被 static 修饰的变量叫实例变量。
在运行时期, JVM 在加载类的时候将完成对静态变量/类变量分配一次内存空间, 且在内存上只存在一份拷贝, 类的所有实例将共享这份拷贝。
静态变量/类变量独立于该类的任何对象, 它不依赖类的特定实例, 可以通过类名来访问得到, 也可以通过实例名来访问(不建议)。
而对于实例变量, 是每次创建类的实例的时候都会为实例变量分配一次内存空间, 实例变量在内存上可能存在多个拷贝, 但它们之间互不影响。
2. static 修饰方法
被 static 修饰的方法称为静态方法, 与静态变量相似的, 它独立于该类的任何对象, 它不依赖类的特定实例。
因此静态方法中不能使用 this、super 关键字, 也不能调用非静态的变量或方法(因为非静态是需依赖于具体的实例, 如果调用, 则不能保证其被正确初始化,
而 Java 编译器是不允许你这么做的)。静态方法可以通过类名来访问得到, 也可以通过实例名来访问(不建议)。
3. static 修饰代码块
被 static 修饰的代码块叫静态代码块, JVM 在加载类的时候就会执行这些静态代码块, 而且只会被执行一次, 因此静态代码块会比类的构造方法优先执行。
如果一个类中的静态代码块有多个,JVM 将按照它们在类中出现的先后顺序依次执行它们。
4.静态导入Static import
要使用静态成员(方法和变量)我们必须给出提供这个静态成员的类。
使用静态导入可以使被导入类的静态变量和静态方法在当前类直接可见,使用这些静态成员无需再给出他们的类名。
静态导入也是JDK5.0引入的新特性,下面以实例来说明静态导入的用法:
比如先在一个包中定义一个这样的类:
package com.example.learnjava; public class Common { public static final int AGE = 10; public static void output() { System.out.println("Hello World!"); } }
在另一个包中使用时,如果不用静态导入,是这样用的:
package com.example.learnjava2; import com.example.learnjava.Common; public class StaticImportTest { public static void main(String[] args) { int a = Common.AGE; System.out.println(a); Common.output(); } }
前面加入了导入语句,将Common类导入,使用其中的静态成员变量和静态方法时需要加上类名。
使用静态导入
静态导入的语法是:
import static 包名.类名.静态成员变量;
import static 包名.类名.静态成员函数;
注意导入的是成员变量和方法名。
如前面的程序使用静态导入后:
package com.example.learnjava2; import static com.example.learnjava.Common.AGE; import static com.example.learnjava.Common.output; public class StaticImportTest { public static void main(String[] args) { int a = AGE; System.out.println(a); output(); } }
缺点
过度地使用静态导入会在一定程度上降低代码的可读性。
二、final
final 译成中文是最终的和不可更改的意思, 它可以用来修饰非抽象类, 非抽象成员方法和变量。
1. final 修饰类
final 不能用来修饰 abstract 的类, 不能被继承, 它是顶级类, 没有子类, 像我们常用的 String 类
2. final 修饰变量
final 用来修饰变量, 那就意味着该变量一旦初始化完成, 那么它的值就不能够再被改变。
因此, final 修饰的变量必须由程序员手动去做初始化给变量赋值, 而且初始化的位置只能是: 定义处、构造方法、普通代码块(不能是静态代码块)。
而且这三个位置中只能选择一处来做初始化。
[小延伸: 普通代码块实际上会被提取到构造方法中来执行, 而且会比构造方法体内的代码优先执行。]
3. final 修饰方法
final 用来修饰方法表示不允许其子类来覆盖这个方法。
final 不能用来修饰构造器(构造方法、构造函数、构造子), 因为父类的构造器不能够被继承, 类内的 private 方法也不能够被子类继承,
也就不存在覆盖之说法, 覆盖仅适用于成员方法, private 修饰的方法实际上默认也是 final 类型的。
三、transient
这个比较陌生, 其实我压根就没用过.... -_-|| 在 java 源码里见到过, 不过没有用到的东西向来学了就忘的很干脆, 这次是为了找工作, 重新整理一遍。
@Transient 相信很多人都认识这个, 在编一个实体类写 JPA(Java Persistence API, Java 持久化 API)注解的时候, 会常常用到这个注解。
而这里的 transient 和 @Transient 的作用很相似:
Java 的 Serializable 提供了一种持久化对象实例的机制。当一个对象发生持久化时, 可能会有一些特殊的数据成员,
是我们不希望用 Serializable 机制来保存的。为了在一个特定对象的一个或多个域上关闭持久化, 可以在这个域前加上关键字 transient。
transient 是 Java 的关键字, 用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候, 被声明成 transient 的变量的值
不会包括在串行化里面。
示例:
package test;
import java.io.Serializable;
public class Admin implements Serializable{
private static final long serialVersionUID = 1L ;
private String name;
private transient String nickname;
public String getName() {
return name;
}
public void setName(String name) {
this .name = name;
}
public String getNickname() {
return nickname;
}
public void setNickname(String nickname) {
this .nickname = nickname;
}
}
package test;
/**
* <!--
* Author : fancy
* Email : fancydeepin@yeah.net
* Date : 2013-02-07
* --!>
*/
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class AdminTest {
public static void main(String[] args) throws Exception{
Admin admin = new Admin();
admin.setName( " 店小三 " );
admin.setNickname( " 小菜一叠 " );
writeObject(admin);
System.out.println( " <------------- 序列化之前 -------------> " );
System.out.println( " 姓名: " + admin.getName());
System.out.println( " 昵称: " + admin.getNickname());
admin = (Admin)readObject();
System.out.println( " <------------- 反序列化后 -------------> " );
System.out.println( " 姓名: " + admin.getName());
System.out.println( " 昵称: " + admin.getNickname());
/**
* 控制台执行输出结果:
*
* <------------- 序列化之前 ------------->
* 姓名: 店小三
* 昵称: 小菜一叠
* <------------- 反序列化后 ------------->
* 姓名: 店小三
* 昵称: null
*/
}
// 序列化
public static void writeObject(Object obj) throws Exception{
ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream( " admin.ser " ));
oos.writeObject(obj);
}
// 反序列化
public static Object readObject() throws Exception{
ObjectInputStream ois = new ObjectInputStream( new FileInputStream( " admin.ser " ));
return ois.readObject();
}
}