Java中的关键字不少,至少有50个左右,常见的new,final,try,catch等等,其中大多数关键字的意义都很简单,基本上根据英文意思就能知道其功能,本文不会对那些简单的关键字作介绍,仅挑选了几个使用频率较高,但又可能致使“迷惑”的关键字来讨论。java
transient关键字可修饰于类成员变量,做用是当类的对象发生序列化的时候,最终的序列化内容不包括被修饰的成员变量。下面的代码演示了transient的功能:编程
public class User implements Serializable {
private String username;
private transient String password;
@Override
public String toString() {
return "User{" +
"username='" + username + '\'' +
", password='" + password + '\'' +
'}';
}
//setter and getter
}
public class TransientTest {
public static void main(String[] args) {
User user = new User();
user.setUsername("yeonon");
user.setPassword("admin");
System.out.println("在序列化以前:");
System.out.println(user);
System.out.println("----------------------");
try (ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream(
"E:\\Java_project\\effective-java\\src\\top\\yeonon\\ch11\\user.txt"))){
oos.writeObject(user);
oos.flush();
} catch (IOException e) {
e.printStackTrace();
}
try (ObjectInputStream ois = new ObjectInputStream(
new FileInputStream("E:\\Java_project\\effective-java\\src\\top\\yeonon\\ch11\\user.txt"))){
User user1 = (User) ois.readObject();
System.out.println("序列化以后读取到的:");
System.out.println(user1);
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
复制代码
User类首先得实现Serializable接口,而后我在password成员变量上增长了transient关键字,在主类中,用ObjectOutputStream和ObjectInputStream来作序列化和反序列化。安全
执行后的输出结果以下:并发
在序列化以前:
User{username='yeonon', password='admin'}
----------------------
序列化以后读取到的:
User{username='yeonon', password='null'}
复制代码
发现序列化以后,再读取时,password是null,这说明序列化的内容没有包括password。ide
顺便说一下,在实际写代码的时候最好不要使用user1这种变量名,这里只是为了方便,随手写的。学习
这是一个二元操做符,也算是关键字,做用是判断左边的对象是不是右边类的实例。以下所示:spa
User user = new User();
if (user instanceof User) {
System.out.println("user object is instance of User class");
} else {
System.out.println("user object is'n instance of User class");
}
复制代码
这里确定会输出user object is instance of User class。若是咱们将User替换成Object,也同样会输出这段话,这说明instanceof还能够用于继承体系,便可以用来判断继承体系中子类的实例是不是父类的实现。线程
这个多用于并发环境下,功能有两个:code
关于volatile的介绍,在我以前的文章 Java虚拟机(二):Java内存模型 有详细解释,在此再也不赘述。对象
和volatile同样,多用于并发环境下,其做用就是给某个代码段或者方法加上内置锁。拿并发编程中的“Hello,World”来举个例子:
public class SyncTest {
private int count = 0;
public void add() {
count += 1;
}
public int getCount() {
return count;
}
public static void main(String[] args) throws InterruptedException, TimeoutException, ExecutionException {
ExecutorService service = Executors.newFixedThreadPool(4);
SyncTest syncTest = new SyncTest();
for (int j = 0; j < 4; j++) {
service.execute(() -> {
for (int i = 0; i < 10000; i++) {
syncTest.add();
}
});
}
service.shutdown();
service.awaitTermination(1000, TimeUnit.SECONDS);
System.out.println(syncTest.getCount());
}
}
复制代码
这里输出的结果会是什么呢?40000?答案是不必定,多是40000,也多是比40000小的数,但确定不会比40000大,由于这里至少有4个线程在并发的对count进行修改,而又没有什么同步措施,故答案不对。若是在add方法上加入synchronized关键字,就能够保证线程安全了,以下所示:
public synchronized void add() {
count += 1;
}
复制代码
这样以后,不管运行多少次代码,结果都会是40000。由于synchronized其实是内置锁,同一时刻仅有一个线程能获取到锁,并对其进行修改,最后执行完毕释放锁,其余线程可再次竞争锁,而后如此往复,知道任务完成。
那synchronized除了做用在方法还能做用在哪呢?下面是synchronized的使用方式:
做用在实例方法上(没有static修饰的方法),至关于给对应的对象加锁,即也不能访问该对象其余的有synchronized修饰的方法,其余实例对象不受影响。
做用静态方法上,至关于给类加锁,此时的做用范围就是该类的全部实例对象,即该类的全部对象同一时刻只能访问有一个对象能访问到synchronized静态方法,并且不能访问该类的其余synchronized静态方法。
做用在代码块中,以下所示:
private String lock = "lock";
synchronized(lock) {
//do something
}
//或者
synchronized(Test.class) {
//do something
}
复制代码
这又有两种状况,一种是括号里的是对象实例,这种状况是对对象实例加锁,对其余对象没有影响。另外一种是括号里的是类对象,这种状况是对类加锁,该类的其余对象都会受到影响。
关于synchronized的其余内容(例如在虚拟机里是如何实现的?有哪些相应的指令?)就很少说了,比较本文不是专门讲并发的。
final最容易让人记住的功能就是将一个变量声明成常量了,但实际上它的做用不只仅是这个,还能够防止指令重排,在我以前的文章Java虚拟机(二):Java内存模型有比较详细的介绍,在此再也不赘述。
static的做用也比较明显,就是将类、方法、成员变量声明成静态的。
静态类做用就是方便使用,若是一个类不依赖外部类的成员变量、方法等,那么最好将其声明成静态类。
静态方法其实也是为了方便使用,在调用的时候能够直接经过类名.方法的形式调用而不须要建立一个新的实例对象,静态工厂模式就很是依赖这个特性。
静态成员变量仍是为了方便使用,咱们常常能在程序源代码中看到相似public static final String XXX = "YYY"的声明,这是由于静态变量能够直接访问,不管是在实例方法里,仍是静态方法里都同样,这样就能避免经过参数传递了。
本文简单的介绍了几个经常使用的关键字,但实际上它们的功能或者原理都远远不止于此,若是想深刻了解,建议到网上搜索资料进行学习。