Java中有一些或常用,或不常用,但却不得不知关键字,本篇文章将讨论这些关键字的作用。

transient

transient关键字可能用的不是那么频繁,但却是一个很重要的关键字,它的作用是在对象序列化过程中体现的。如果一个类的变量被transient修饰,那么这个对象在序列化过程中,不会序列化这个变量,同时,在反序列化过程中,也不会去反序列这个变量。

笔者有时候会遇到这样一种情况,可能是因为笔者经验不足。在使用JPA进行数据库操作的时候,某些对象在序列化到数据库的时候,会有一些变量并不想要去存到数据库中,这个时候就可以用transient来修饰变量,解决这个问题。

instanceof

这个关键字就比较常用了,尤其是在一些大量采用反射的框架中,在需要判断某一个对象是否是某一类型(可以是接口,父类,父类的父类等)的时候,可以采用这个关键字。比如说,判断UserServiceImpl是否是UserService接口的类型,可以这样做:

if(userServiceImpl instanceof UserService){
//do some thing
}

  

笔者在自己的IOC框架中就用到了这个关键字,在将进行接口依赖注入的时候,使用该关键字判断容器中是否有相应接口的实例,然后将实例注入。

final

final关键字可以用来修饰变量、类、方法。

final修饰的变量,一旦在被赋值之后,将不能再次赋值,也就是说这个变量在后续的使用过程中,只能采取读的方式,变量具有不可变性。这里需要做一下区别,就是基本数据类型和引用数据类型在被final修饰后的情况。基本数据类型的不可变性往往体现在变量的值永远不会再变化,而引用类型则不是,引用类型的不变性是体现在引用的不变性。引用类型的变量一旦为一个引用数据类型赋值,那么变量就会指向对象在内存中的地址,final关键字修饰过后,变量所指向的地址就不能再被改变,但对象本身的状态还是可以改变的,可以看一下下面这段代码:

final int i = 0;

i = 1; //error

final int[] j = new int[10];

j = new int[20]; //error

j[0] = 1; //right

  

final修饰过的变量有一个好处,即它会是线程安全的。在Java中,final变量会进行指令重排序,确保所有线程在访问该变量的时候,变量已经被初始化过了。虽然在旧的版本中,会出现对象引用在构造函数中“逸出”的情况,但自从jsr133增强了final的内存语义之后,所有线程在看到final变量时,看到的都是已经初始化之后的值。final变量初始化之后又不会再改变,所以它是线程安全的。

final修饰的类,将具有不可继承性,即不能有子类。

final修饰的方法,将不可被重写,但可以重载。

static

static关键字可以用来修饰变量,方法。static修饰的变量和方法,将只属于类,可以通过类名.变量名(或方法名)的方式来引用,使用方式如下:

public class Demo{
public static int i = 0;
public static void hello(){
System.out.println(i);
}
}
//可以这么访问
int j = Demo.i;
Demo.hello();

  

其中static变量将会常驻内存中,不会在垃圾回收的过程中被回收掉,甚至会成为垃圾回收中的GC Root。static变量的初始化只能在static代码块中执行,它先于构造函数执行,使用方式如下:

 
public class Demo{
public static int i;
static{
i=0;
}
}

  

volatile

这个关键字是一个很重要的关键字,可以修饰变量。如果要进行多线程编程,那么这个关键字将会是一个重点。因为它有两个特性:可见性和原子性。

可见性是指,对一个volatile变量的读,总是能看到(任意线程)对这个volatile变量最后的写入。volatile变量再被修改的时候,如果有其他线程读取了该变量,它会通知其他线程变量已经实现,重新读取最新的值。

原子性是指,对任意单个volatile变量的读/写具有原子性,但类似于volatile++这种符合操作不具有原子性。其原理是因为volatile具有一定程度上的锁的语义,但并没有像synchronized那么重量级。

它的使用方式如下,以最常见的单例模式为示例。一般来说,我们比较喜欢使用double-check的方式实现单例模式,因为它既可以做延迟初始化又可以保证线程的安全,代码如下:

public class Demo{
private static Demo instance;
private Demo(){ }
public static Demo getInstance(){
if(instance == null){ //第一步,判断instance是否为null
synchronized(Demo.class){ //第二步,加锁
if(instance == null){ //第三步,再判断instance是否为null
instance = new Demo(); //第四步,实例化
}
}
}
return instance;
}
}

  

这段代码看似线程安全,但却存在一个很大的缺陷。如果有两个线程,两个线程都执行到了第二步,一个线程在拿到锁并进行实例化之后,另一个线程继续进入同步代码块,这个线程读到的instance可能还是null,之后就会导致线程安全问题。为什么会这样呢?其实在Java中,对象的实例化可以分为以下三个子阶段:

memory = allocate();  // 1:分配对象的内存空间
ctorInstance(memory); // 2:初始化对象
instance = memory;  // 3:设置instance指向刚分配的内存地址

  

由于Java会对指令进行重排序,可能会导致3和2的指令顺序相反,即

memory = allocate();  // 1:分配对象的内存空间
instance = memory;  // 3:设置instance指向刚分配的内存地址
ctorInstance(memory); // 2:初始化对象

  

问题就出现在这里,如果线程一的还没有执行完初始化对象这个子阶段,另一个线程将会认为这个实例为空,将会导致线程安全。要解决这个问题,可以加上volatile关键字,代码如下:

public class Demo{
private volatile static Demo instance;
private Demo(){ }
public static Demo getInstance(){
if(instance == null){ //第一步,判断instance是否为null
synchronized(Demo.class){ //第二步,加锁
if(instance == null){ //第三步,再判断instance是否为null
instance = new Demo(); //第四步,实例化
}
}
}
return instance;
}
}

  

volatile会禁止指令重排序,使得这个操作变得具有原子性,这样线程就可以读取到变量最新的状态,保证了线程的安全。

synchronized

synchronized可以说是一个非常常见的关键字了,在jdk1.6之前,它被称为重量级锁,不过jdk1.6之后经过优化和升级,已经没有那么夸张了。通过使用synchronized可以使代码同步,解决多线程环境下的一些问题。一般来说,它可以使用下面三种形式的锁:

  • 对于普通同步方法,锁是当前实例对象。
  • 对于静态同步方法,锁是当前类的Class对象。
  • 对于同步方法块,锁是synchronized括号里配置的对象。

当一个线程试图去访问同步代码块时,它必须先得到锁,退出或抛出异常时必须释放锁。其底层原理是通过Monitor对象来实现方法同步和代码块同步。代码块同步是使用monitorenter和monitorexit指令实现的,方法同步是使用另一种方法实现的。

monitorenter方法是在编译后插入到同步代码块的开始位置,而monitorexit是插入到方法结束处和异常处,JVM要保证每个monitorenter都有一个monitorexit与之配对。任何对象都有一个monitor与之关联,当且一个monitor被持有后,它将处于锁定状态。线程执行到monitorenter指令时,将会尝试获取对象所对应的monitor所有权,即尝试获得对象的锁。

 

Java中需要知道的关键字的更多相关文章

  1. Java中的两个关键字——super、this

    Java中的两个关键字——super.this 神话丿小王子的博客主页 一.super super 是java中方的一个关键字,用它可以引用父类中的成员: super可用于访问父类中定义的属性 sup ...

  2. Java中的50个关键字

    form:http://blog.csdn.net/luoweifu/article/details/6776240 Java中的50个关键字 关键字也称为保留字,是指java语言中规定了特定含义的标 ...

  3. 【每周一译】愚蠢的指标:Java中使用最多的关键字

    此翻译纯属个人爱好,由于水平所限,翻译质量可能较低.网络上可能存在其它翻译版本,原文地址:http://blog.jooq.org/2013/08/26/silly-metrics-the-most- ...

  4. Java中的标识符和关键字

    1.标识符 含义:标识符用于给程序中的类.变量.方法命名的符号. 组成:数字(0-9).字母(a-z)(A-Z).下划线(_).美元符号$. 命名规则:1.数字不能够作为命名符号的开头 2.不能够使用 ...

  5. java中this和super关键字的使用

    这几天看到类在继承时会用到this和super,这里就做了一点总结,与各位共同交流,有错误请各位指正~ this this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针. this ...

  6. Java中this和super关键字

    今天练习到Java中的this和super关键字,我有如下总结: 1.子类继承父类,子类初始化对象,必须先调用父类构造方法,因为随时有可能要使用父类的成员变量. 2.get和set方法只是对成员变量进 ...

  7. 1.3 Java中的标识符和关键字

    1.标识符 含义:标识符用于给程序中的类.变量.方法命名的符号. 组成:数字(0-9).字母(a-z)(A-Z).下划线(_).美元符号$. 命名规则:1.数字不能够作为命名符号的开头 2.不能够使用 ...

  8. java中的标识符、关键字、保留字

    Java中关键字(keyword)和保留字(reservedword) Keyword :Java的关键字对java的编译器有特殊的意义,他们用来表示一种数据类型,或者表示程序的结构等. Reserv ...

  9. 简析--Java中常见的一些关键字的解析

    在Java开发中我们经常会用到一些关键字,关键字的定义很有意思"Java事先定义好的,具有特殊含义的单词",那么我们怎么来用好关键字呢?下面我们对一些常见的关键字进行分析和比较; ...

随机推荐

  1. C# Conversion Keywords

    主要是解决类与其他不同数据类型的转换 类于类的显式转换: explicit  public static explicit operator B(A a) { return new B(){a.... ...

  2. android---EditText的多行输入框

    <EditText android:id="@+id/edt_order_note_text" android:layout_width="match_parent ...

  3. 如何在本地数据中心安装Service Fabric for Windows集群

    概述 首先本文只是对官方文档(中文,英文)的一个提炼,详细的安装说明还请仔细阅读官方文档. 虽然Service Fabric的官方名称往往被加上Azure,但是实际上(估计很多人不知道)Service ...

  4. SLogViewer下载及使用说明

    SLogViewer 1.0使用说明 SLogViewer是一个基本开源界面库SOUI开发的开源的通用的高性能LOG分析工具, 轻松支持上百万行级别的LOG过滤.  支持LOG格式配置. 只要是固定格 ...

  5. Codeforces 258D Little Elephant and Broken Sorting (看题解) 概率dp

    Little Elephant and Broken Sorting 怎么感觉这个状态好难想到啊.. dp[ i ][ j ]表示第 i 个数字比第 j 个数字大的概率.转移好像比较显然. #incl ...

  6. UOJ#373. 【ZJOI2018】线图 搜索,树哈希,动态规划

    原文链接www.cnblogs.com/zhouzhendong/p/UOJ373.html 前言 真是一道毒瘤题.UOJ卡常毒瘤++.我卡了1.5h的常数才过QAQ Orzjry 标算居然是指数做法 ...

  7. 关于<超文本>定义

    百度百科定义: 1, 超文本是用超链接的方法,将各种不同空间的文字信息组织在一起的网状文本.它更是一种用户界面范式,用以显示文本及与文本之间相关的内容.现时超文本普遍以电子文档方式存在,其中的文字包含 ...

  8. C - Thief in a Shop - dp完全背包-FFT生成函数

    C - Thief in a Shop 思路 :严格的控制好k的这个数量,这就是个裸完全背包问题.(复杂度最极端会到1e9) 他们随意原来随意组合的方案,与他们都减去 最小的 一个 a[ i ] 组合 ...

  9. 谈谈代码中的this

    js中我们常常会遇到this,this的具体指向问题对于很多同学来说是很懵懂的:就想lz刚开始接触时候就是一脸的懵逼,经常被一些题目转的眼花缭乱.那么今天lz就跟大家一起交流一下这个this的指向问题 ...

  10. LPC 语言基础

    LPC是一种基于C语言开发的编程语言 主要用于写MUD(多使用着迷宫)游戏 LPC是一种面向对象的语言,它有object的概念,但是没有class LPC有四中函数类型1> apply 只能被游 ...