像其他语言一样,Java可以使用修饰符来修饰类中方法和属性。主要有两类修饰符:
四个访问修饰符,解决了Java中类与类之间访问权限的设置问题。而非访问控制修饰符,各有各的妙用,且听我一一道来:
static 修饰符,可以用来修饰类方法和类变量。
来个实例:
class Person {
public static int totalnum; // totalnum为静态变量变量,static修饰
private String name;
private int age;
Person(String name,int age) {
this.name = name ;
this.age = age;
Person.totalnum++;
}
public void die(){
totalnum--;
}
public static void destroy() {
totalnum = 0;
// age = 18; 会报错,static方法中不能使用非static变量
}
}
public class Test {
public static void main(String[] args){
Person person1 = new Person("小猪",18);
System.out.println("小猪出生后,人类总人数:"+person1.totalnum); // Person.totalnum结果与一样
Person person2 = new Person("小牛",20);
System.out.println("小牛出生后,人类总人数:"+person2.totalnum); // Person.totalnum结果与一样
person2.die();
System.out.println("小牛死亡后,人类总人数:"+Person.totalnum);
Person.destroy();
System.out.println("人类灭亡后,人类总人数:"+Person.totalnum);
}
}
-------------------------------------------------
输出结果为:
小猪出生后,人类总人数:1
小牛出生后,人类总人数:2
小牛死亡后,人类总人数:1
人类灭亡后,人类总人数:0
我用比较白话的方式谈谈自己理解:被static 修饰,就是指这些变量和方法是类本身的东西,与具体的实例化对象无关,我们在调用时应该直接从类中调用:类名.变量/方法。所以调用static方法时,static方法内是不能操作非static变量的,因为非static变量都是属于实例化后的对象的,调用static方法是从类的层面调用,并不具体到某一个对象。
final:最终的、最后的。
final修饰符,可以用来修饰方法、变量以及类。
class Person {
public static final int max_totalnum = 10;
public static int totalnum;
private String name;
private int age;
Person(String name,int age) {
this.name = name ;
this.age = age;
Person.totalnum++;
}
}
public class Test {
public static void main(String[] args){
// Person.max_totalnum = 20 ; 会报错,无法修改final变量的值
}
}
class Person {
public static final int max_totalnum = 10;
public static int totalnum;
private String name;
private int age;
Person(String name,int age) {
this.name = name ;
this.age = age;
Person.totalnum++;
}
static final void destroy() {
Person.totalnum = 0;
}
}
class Woman extends Person {
Woman(String name, int age) {
super(name, age);
}
// void destroy(){ } 无法重写,会报错
}
final class Person {
private String name;
private int age;
Person(String name,int age) {
this.name = name ;
this.age = age;
}
}
class Woman extends Person {
// 会报错,无法继承,因为Person为final类
}
abstract修饰符用于抽象类与接口当中,关于抽象类与接口详细介绍见:《抽象类与接口》
被abstract修饰的类为抽象类,抽象类不能用来实例化对象,声明抽象类的唯一目的是为了将来对该类进行扩充。
一个类不能同时被 abstract 和 final 修饰。如果一个类包含抽象方法,那么该类一定要声明为抽象类,否则将出现编译错误。
抽象类可以包含抽象方法和非抽象方法。
abstract class Person {
//抽象类,注意不能同时被 abstract 和 final 修饰
public static int totalnum;
private String name;
private int age;
Person(String name,int age) {
this.name = name ;
this.age = age;
}
public abstract void die(); //抽象类中可以有抽象方法,有抽象方法一定要声明为抽象类
public static void destroy() {
//抽象类中也可以有非抽象方法
totalnum = 0;
}
}
public class Test {
public static void main(String[] args){
new Person(); // 报错,抽象类无法实例化
}
}
抽象方法是一种没有任何实现的方法,该方法的的具体实现由子类提供。
抽象方法不能被声明成 final 和 static。
任何继承抽象类的非抽象子类必须实现父类的所有抽象方法,除非该子类也是抽象类。
抽象方法的声明以分号结尾,如:public abstract void die(); 不能再加{}
abstract class Person {
public static int totalnum;
private String name;
private int age;
Person(String name,int age) {
this.name = name ;
this.age = age;
}
public abstract void die();
public static void destroy() {
totalnum = 0;
}
}
class Woman extends Person{
// Woman 为 Person 的 非抽象 子类
Woman(String name, int age) {
super(name, age);
}
@Override // 非抽象子类,必须实现抽象父类的所有抽象方法,也是一种重写
public void die() {
// TODO Auto-generated method stub
Person.totalnum--;
}
}
synchronized 关键字声明的方法同一时间只能被一个线程访问。synchronized 修饰符可以应用于四个访问修饰符。具体可以案例可以访问:《线程同步 synchronized》
volatile 修饰的成员变量在每次被线程访问时,都强制从共享内存中重新读取该成员变量的值。而且,当成员变量发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,两个不同的线程总是看到某个成员变量的同一个值。
一个 volatile 对象引用可能是 null。
public class MyRunnable implements Runnable
{
private volatile boolean active;
public void run()
{
active = true;
while (active) // 第一行
{
// 代码
}
}
public void stop()
{
active = false; // 第二行
}
}
通常情况下,在一个线程调用 run() 方法(在 Runnable 开启的线程),在另一个线程调用 stop() 方法。 如果 第一行 中缓冲区的 active 值被使用,那么在 第二行 的 active 值为 false 时循环不会停止。
但是以上代码中我们使用了 volatile 修饰 active,所以该循环会停止。
序列化的对象包含被 transient 修饰的实例变量时,java 虚拟机(JVM)跳过该特定的变量。
该修饰符包含在定义变量的语句中,用来预处理类和变量的数据类型。
public transient int limit = 55; // 不会持久化
public int b; // 持久化