在Java这门面向对象编程语言中,有几个关键字是必须了解的,下面是我在学习的记录笔记。
static
在平时,我们调用一个类里面的属性或者方法的时候,需要new一个新的类,然后调用类的方法或者属性。
static表示全局或者静态的意思。可用来修饰成员变量或者方法。被static修饰的成员变量和方法独立于该类的任何对象,也就是说,它不依赖类特定的实例,就是被这个修饰的不需要实例化就可以使用,就可以被类的所有实例共享。
static代码块也叫静态代码块,在类中独立于类成员的static语句块,JVM加载时 会执行这些静态代码块。
在静态方法中,不能访问非静态方法或者是非静态变量。如代码中,准确的来说,只有被static修饰的变量和方法,才能不需要实例化直接使用,即使在static修饰的方法中,也不能直接调用没有实例化的非静态方法或者是非静态变量。
final
一旦使用了final,该变量就不可修改;如果方法被final修饰,那么这个方法就不可被子类重写;final类,是不能被子类继承的。这里有一篇博客讲的挺详细的。
- final 修饰类,表示该类不可以被继承
- final 修饰变量,分两种情况,如果修饰的是基本类型变量,那么只能被赋值一次,不能被赋值两次, 如果修饰的是引用类型变量,那么引用指向的内存地址将不可变,但是引用类型内的属性可以被修改
- final 修饰方法,表示该方法不可以被子类重写,但是可以被子类继承使用
final的好处:
- final关键字提高了性能。JVM和java的应用都会缓存final变量
- final变量可以安全的在多线程环境下进行共享;
- 使用final关键字,JVM会对方法、变量及类进行优化。
final修饰的变量是引用类型变量,那么引用指向的内存地址将不可变,但是引用类型内的属性可以被修改。
1 | final StringBuffer a = new StringBuffer("hello"); |
abstract
抽象类里面不一定有抽象方法,但是有抽象方法,那么这个类就是抽象类。
使用abstract关键字修饰的话,类可以进行扩展,但是方法不能实例化,如下面的代码。
1 | public abstract class AbstractTest { |
虽然抽象方法不能实例化,但是可以通过继承,在子类中进行重写。其实Java中接口interface就是一个抽象类。
1 | public class MainTest extends AbstractTest{ |
顺便我们来下看接口类的方法中,我们咋样来写方法。
1 | public interface interfaceTest { |
volatile
volatile则是轻量级的synchronized。如果一个变量使用volatile,则它比使用synchronized的成本更加低,因为它不会引起线程上下文的切换和调度。Java语言规范对volatile的定义如下:
Java编程语言允许线程访问共享变量,为了确保共享变量能被准确和一致地更新,线程应该确保通过排他锁单独获得这个变量。
1 | i = i + 1; |
对于这语句,在执行的过程中,会先从内存中读取i的值,然后复制一份到高速缓存中,然后CPU执行指令对进行加1操作,然后将数据写入高速缓存,最后将高速缓存中最新的值刷新到主存中
volatile保证了下面这两点:
- 可见性
- 禁止重排序
Java提供volatile关键字来保证可见性。当一个共享变量被修饰的时,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,它会去内存中读取新值。
volatile变量规则:对一个变量的写操作先行发生于后面对这个变量的读操作。
volatile修饰符组织了变量访问前后的指令重排,保证指令执行顺序,但是不能保证线程安全,因为不能保证原子性。
下面的代码起了20个线程,每个线程对race自增10000,理论上应该是200000,但是最后输出的结果并不是,而且每次运行都不一样。
1 | public class VolatileTest { |
this
this 只能在方法内使用,表示对调用的方法的对象的引用。
transient
如果一个对象中的某个属性不希望被序列化,则可以使用transient关键字进行声明。