第七讲:修饰符与关键字
Java中修饰符分为访问控制修饰符和非访问控制修饰符两种,主要用于修饰类、属性、方法等,一般放在语句的最前端,修饰后面的语句进而达到某种目的;如访问控制、是否可修改等。
关键字不像修饰符一样其用于修饰类或属性等,它用于代指或判断等;如代替指当前对象调用方法、判断某个对象的类型等。
访问控制修饰符
可以使用访问控制符来保护对类、属性、方法和构造方法的访问。Java 支持 4 种不同的访问权限。
- default (即默认,什么也不写): 在同一包内可见,不使用任何修饰符。使用对象:类、接口、变量、方法。
- private : 在同一类内可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
- public : 对所有类可见。使用对象:类、接口、变量、方法。
- protected : 对同一包内的类和所有子类可见。使用对象:变量、方法。 注意:不能修饰类(外部类)
修饰符 | 当前类 | 同一包内 | 子孙类(同一包) | 子孙类(不同包) | 其他包 |
---|---|---|---|---|---|
public | yes | yes | yes | yes | yes |
protected | yes | yes | yes | yes/no | no |
default | yes | yes | yes | no | no |
private | yes | no | no | no | no |
非访问控制修饰符
非访问控制修饰符的作用主要是让类、属性、方法等具有某种特殊的功能,不存在访问权限的限制。
- static 修饰符,用来修饰类方法和类变量。
- final 修饰符,用来修饰类、方法和变量,final 修饰的类不能够被继承,修饰的方法不能被继承类重新定义,修饰的变量为常量,是不可修改的。
- abstract 修饰符,用来创建抽象类和抽象方法。
- synchronized 和 volatile 修饰符,主要用于线程的编程。
static修饰符
被static修饰变量和方法也被成为静态变量和静态方法,它们只属于类本身,无论这个根据这个类创建类多少个对象,静态属性和静态方法都只有一份,所有对象所共享。
注意:
- 局部变量不能声明为static变量。
- 静态方法不能使用类的非静态变量,非静态方法可以使用静态变量。
示例:
class Demo {
static int a = 10; // 静态变量
int b = 10; // 非静态变量
public static void main(String[] args) {
Demo demo1 = new Demo(); // 创建第一个对象demo1
demo1.a++; // 修改(类的)静态变量的值
demo1.b++; // 修改(对象demo1)非静态变量的值
System.out.println(demo1.a);
System.out.println(demo1.b);
Demo demo2 = new Demo(); // 创建第二个对象demo2
demo2.a++; // 修改(类的)静态变量的值
demo2.b++; // 修改(对象demo2)非静态变量的值
System.out.println(demo2.a);
System.out.println(demo2.b);
staticMethod(); // 静态方法可以直接调用静态方法
// method(); // 静态方法不可以直接调用非静态方法
demo2.method(); // 通过对象可以在静态方法中调用非静态方法
}
public static void staticMethod() { // 静态方法
System.out.println("a的值为:" + a); // 静态方法可以使用静态变量
// System.out.println("b的值为:" + b); // 静态方法不可以使用非静态变量
}
public void method() { // 非静态方法
System.out.println("a的值为:" + a); // 非静态方法可以使用静态变量
}
}
输出:
11
11
12
11
a的值为:12
a的值为:12
final修饰符
final修饰的变量其实就是一个常量,一但赋值就不可改变。
示例:
class Demo {
static final int a = 10;
public static void main(String[] args) {
// a = 20; // final修饰的变量是一个常量,值不可变
System.out.println("a的值是:" + a);
}
}
输出:
a的值是:10
final修饰的方法可以被子类继承,但是不能被子类重写。声明 final 方法的主要目的是防止该方法的内容被修改。
语法:
public final void method() {
// 方法体
}
final修饰的类不能被继承,也就是说final修饰的类不会有子类。
语法:
public final class Demo {
// 类体
}
abstract修饰符
abstract可以修饰类和方法,修饰的类是抽象类,修饰的方法是抽象方法。
注意:
- 抽象方法只有声明,没有方法体,具体实现依靠子类实现。
- 抽象类和抽象方法不能被final修饰,因为需要子类继承抽象类并实现它的抽象方法。
- 抽象类不一定有抽象方法,但是有抽象方法的一定是抽象类。
- 抽象类不能用来创建对象。
语法:
abstract class Demo { // 抽象类
abstract void test(); // 抽象方法
}
class SubClass extends Demo { // 子类继承抽象类
void test() { // 实现抽象类中的抽象方法
System.out.println("success");
}
}
synchronized修饰符
synchronized修饰的变量或方法在同一时间只能被一个线程访问。(详情在多线程部分具体介绍)
注意:
- synchronized可以修饰变量、方法、类、代码块等,使用范围较广。
- synchronized可以保证有序性、原子性、可见性。
- synchronized使用可能会造成线程阻塞。
volatile修饰符
volatile修饰的变量在每次被线程访问时,都强制从共享内存中重新读取该变量的值。而且,当变量的值发生变化时,会强制线程将变化值回写到共享内存。这样在任何时刻,不同的线程总是看到某个成员变量的同一个值。(详情在多线程部分具体介绍)
注意:
- volatile只能修饰变量。
- volatile可以保证有序性、可见性,不能保证原子性。
- volatile使用不会造成线程阻塞。
this关键字
this可以代指当前对象,使用this可以调用该对象的属性和方法等。
示例:
class Demo {
int a = 10;
public Demo(int a) {
System.out.println("this的值:" + this);
this.a = a; // this调用当前对象的属性a接收构造参数中参数a的值
}
public static void main(String[] args) {
Demo demo = new Demo(20); // 创建一个demo对象
System.out.println("demo的值:" + demo);
System.out.println(demo.a); // demo对象调用属性a,但是这里不可以用this.a
}
}
输出:
this的值:com.study.test8.Demo@76ed5528
demo的值:com.study.test8.Demo@76ed5528
20
通过上面的示例可以发现,this的值和demo对象的值是一致的,所以this代指的其实就是创建的demo对象。
扩展:
问:既然this代指的是demo对象,为什么 System.out.println(demo.a); // demo对象调用属性a,但是这里不可以用this.a ?
答:因为this只能在属于对象自己的方法内部使用,也就是可以在非静态方法内部使用;静态方法属于类而不属于某个对象,所以在静态方法中不能使用this。
instanceof关键字
在Java中,instanceof关键字是二进制运算符,它用于检查对象是否是特定类的实例。
语法:
result = objectName instanceof ClassName // result的值只能是true或false
示例:
class Demo {
public static void main(String[] args) {
Demo demo = new Demo();
boolean result = false;
if (result = demo instanceof Demo) { // 判断demo是否是Demo类的一个对象
System.out.println("demo是Demo类的一个对象:" + result);
} else {
System.out.println("demo不是Demo类的一个对象:" + result);
}
}
}
输出:
demo是Demo类的一个对象:true
扩展:
-
如果子类继承了父类,然后创建了一个子类对象,判断它是否是父类的一个对象?结果为:是。
-
如果类实现了一个接口,然后通过该类创建了一个对象,判断它是否是接口的一个对象?结果为:是。
示例:
class SubClass extends Demo {
// 类体
}
class Demo {
public static void main(String[] args) {
SubClass subClass = new SubClass();
if (subClass instanceof Demo) {
System.out.println("是");
} else {
System.out.println("不是");
}
}
}
输出:
是
示例:
interface DemoInterface {
// 接口体
}
class Demo implements DemoInterface {
public static void main(String[] args) {
Demo demo = new Demo();
if (demo instanceof Demo) {
System.out.println("是");
} else {
System.out.println("不是");
}
}
}
输出:
是