基础知识梳理&修饰符

private 修饰符

1.private修饰的变量和方法只在类内部可见。

2.在类内部,该类的所有的属性和方法都是可以访问的。

子类继承父类的所有属性和方法或子类拥有父类的所有属性和方法是对的。但是父类的私有属性和方法,对子类不可见,子类是无法直接访问到的。即只是拥有,但是无法使用

public 修饰符

被声明为 public 的类、方法、构造方法和接口能够被任何其他类访问。如果几个相互访问的 public 类分布在不同的包中,则需要导入相应 public 类所在的包。由于类的继承性,类所有的公有方法和变量都能被其子类继承。

protected 修饰符

1.子类与基类在同一包中:被声明为 protected 的变量、方法和构造器能被同一个包中的任何其他类访问;

2.子类与基类不在同一包中:那么在子类中,子类实例可以访问其从基类继承而来的 protected 方法,而不能访问基类实例的protected方法。

protected 可以修饰数据成员,构造方法,方法成员,不能修饰类(内部类除外)。

default 修饰符

default (即缺省,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。

static 修饰符

1.静态变量:

类变量也称为静态变量,在类中以 static 关键字声明,但必须在方法之外

无论一个类创建了多少个对象,类只拥有类变量的一份拷贝。

静态变量储存在静态存储区。经常被声明为常量,很少单独使用static声明变量。

静态变量在第一次被访问时创建,在程序结束时销毁。

与实例变量具有相似的可见性。但为了对类的使用者可见,大多数静态变量声明为public类型。

默认值和实例变量相似。数值型变量默认值是0,布尔型默认值是false,引用类型默认值是null。变量的值可以在声明的时候指定,也可以在构造方法中指定。此外,静态变量还可以在静态语句块中初始化。

静态变量可以通过:ClassName.VariableName的方式访问。

2.静态方法:static 关键字用来声明独立于对象的静态方法。静态方法不能使用类的非静态变量。静态方法从参数列表得到数据,然后计算这些数据。

3.静态内部类:声明为static的内部类,成员内部类不能有static数据和static方法,但嵌套内部类可以。

final 修饰符

1.final静态变量:

如果final修饰的是一个基本类型,就表示这个变量被赋予的值是不可变的。

如果final修饰的是一个对象,就表示这个变量被赋予的引用是不可变的。

静态final变量可以在静态初始化块中初始化

2.final非静态变量:

final修饰的非静态变量在定义的时候初始化

非静态final变量在初始化块中初始化,不可在静态初始化块中初始化

非静态final变量可以在类的构造器中初始化,但是静态final变量不可以

非静态final变量可以在类的构造器中初始化,但是静态final变量不可以

3.final 方法:

类中的 final 方法可以被子类继承,但是不能被子类修改。声明 final 方法的主要目的是防止该方法的内容被修改。

4.final 类:

final 类不能被继承,没有类能够继承 final 类的任何特性。

abstract 修饰符

1.抽象类:抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。

2.抽象方法:抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。抽象方法不能被声明成 final 和 static。任何继承抽象类的子类必须实现父类的所有抽象方法,除非该子类也是抽象类。如果一个类包含若干个抽象方法,那么该类必须声明为抽象类。抽象类可以不包含抽象方法。

synchronized 修饰符

1.同步实例方法

Java中的同步实例方法在拥有该方法的实例(对象)上同步。因此,每个实例的同步方法在不同的对象上同步:拥有它的实例。在一个同步实例方法中,只有一个线程可以执行。如果存在多个实例,则一次只能有一个线程可以在每个实例的同步实例方法内执行。每个实例一个线程。

2.同步静态方法

同步静态方法在同步静态方法所属的类的类对象上同步。由于每个类在Java VM中只存在一个类对象,因此在同一个类中的静态同步方法中只能执行一个线程。

如果静态同步方法位于不同的类中,则一个线程可以在每个类的静态同步方法内执行。每个类一个线程,无论它调用哪个静态同步方法。

3.实例方法中的同步块

Java synchronized块构造如何在括号中获取对象——使用synchronized(this),由synchronized构造在括号中获取的对象称为监视器对象。据说代码在监视器对象上同步。同步实例方法使用它所属的对象作为监视对象。只有一个线程可以在同一监视器对象上同步的Java代码块内执行。

4.静态方法中的同步块

synchronized(Class.class)不同的对象上同步,那么一个线程可以同时在每个方法内执行。

transient 修饰符
  1. transient的作用及使用方法
    我们都知道一个对象只要实现了Serilizable接口,这个对象就可以被序列化,java的这种序列化模式为开发者提供了很多便利,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化。然而在实际开发过程中,我们常常会遇到这样的问题,这个类的有些属性需要序列化,而其他属性不需要被序列化,打个比方,如果一个用户有一些敏感信息(如密码,银行卡号等),为了安全起见,不希望在网络操作(主要涉及到序列化操作,本地序列化缓存也适用)中被传输,这些信息对应的变量就可以加上transient关键字。换句话说,这个字段的生命周期仅存于调用者的内存中而不会写到磁盘里持久化。

总之,java 的transient关键字为我们提供了便利,你只需要实现Serilizable接口,将不需要序列化的属性前添加关键字transient,序列化对象的时候,这个属性就不会序列化到指定的目的地中。

  1. transient 使用小结
    一旦变量被transient修饰,变量将不再是对象持久化的一部分,该变量内容在序列化后无法获得访问。

transient关键字只能修饰变量,而不能修饰方法和类。注意,本地变量是不能被transient关键字修饰的。变量如果是用户自定义类变量,则该类需要实现Serializable接口。

被transient关键字修饰的变量不再能被序列化,一个静态变量不管是否被transient修饰,均不能被序列化。

  1. transient使用细节——被transient关键字修饰的变量真的不能被序列化吗?
    我们知道在Java中,对象的序列化可以通过实现两种接口来实现,若实现的是Serializable接口,则所有的序列化将会自动进行,若实现的是Externalizable接口,则没有任何东西可以自动序列化,需要在writeExternal方法中进行手工指定所要序列化的变量,这与是否被transient修饰无关。
volatile 修饰符

volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。一个 volatile 对象引用可能是 null。

1.保证可见性

将当前处理器 内部缓存 的数据写回到 系统内存。

这个写回内存的操作会使在其他处理器里 缓存了该内存地址的数据无效,当这些处理器对这个数据进行修改操作的时候,会重新从系统内存中把数据读到处理器缓存里。

2.禁止指令重排序

当程序执行到volatile 变量的读操作或者写操作时,在其前面的操作的更改肯定全部已经进行,且结果已经对后面的操作可见;在其后面的操作肯定还没有进行;

在进行指令优化时,不能将在对volatile 变量访问的语句放在其后面执行,也不能把volatile变量后面的语句放到其前面执行。

3.性能问题

volatile 相对于synchronized的优势主要原因是两点:简易和性能。如果从读写两方便来考虑:

volatile 读操作开销非常低,几乎和非volatile 读操作一样

volatile 写操作的开销要比非volatile 写操作多很多,因为要保证可见性需要实现 内存界定,即便如此,volatile的总开销仍然要比锁获取低。volatile 操作不会像锁一样 造成阻塞。

以上两个条件表明,可以被写入volatile 变量的这些有效值 独立于任何程序的状态,包括变量的当前状态。大多数的编程情形都会与这两个条件的其中之一冲突,使得volatile 不能像synchronized那样普遍适用于实现线程安全。

因此,在能够安全使用volatile 的情况下,volatile 可以提供一些优于锁的可伸缩特性。如果读操作的次数要远远超过写操作,与锁相比,volatile变量通常能够减少同步的性能开销。

4.应用场景

要使volatile 变量提供理想的线程安全,必须同时满足以下两个条件:

对变量的 写操作不依赖于当前值。例如x++这样的增量操作,它实际上是一个由读取、修改、写入操作序列组成的组合操作,必须以原子方式执行,而volatile 不能提供必须的原子特性。

该变量 没有包含在其它变量的不变式中。

避免滥用volatile最重要的准则就是:只有在 状态真正独立于程序内其它内容时 才能使用volatile

5.状态标志

用volatile 来修饰一个Boolean状态标志,用于指示发生了某一次的重要事件,例如完成初始化或者请求停机

6.volatile bean 模式

volatile bean模式适用于将JavaBean作为“荣誉结构”使用的框架。在volatile bean模式中,JavaBean被用作一组具有getter和/或setter方法的独立属性的容器。

volatile bean模式的基本原理是:很多框架为易变数据的持有者提供了容器,但是放入这些容器中的对象必须是线程安全的。

在volatile bean模式中,JavaBean的所有数据成员都是volatile 类型的,并且 getter和setter方法必须非常普通,除了获取或设置相应的属性外,不能包含任何逻辑。此外,对于对象引用的数据成员,引用的对象必须是有效不可变的。

7.开销较低的读/写锁策略

如果读操作远远超过写操作,您可以结合使用内部锁和volatile变量来减少公共代码路径的开销。下面的代码中使用synchronized确保增量操作是原子的,并使用volatile保证当前结果的可见性。如果更新不频繁的话,该方法可实现更好的性能,因为读路径的开销仅仅涉及volatile读操作,这通常要优于一个无竞争的锁获取的开销。

你可能感兴趣的:(基础知识梳理&修饰符)