修饰符
abstract、static、final
abstract
在程序中,定义了多个类,如果这些类中有共同属性、共同方法,通常会将这些共性抽取出来,放在其父类中;如果这个父类只具备某种对象的特征,并不完整,那就将其定义为抽象类。
- abstract 修饰类被称为抽象类,不能「new」对象;
- 可以被子类继承,为子类提供共性的属性和方法;
- 可以声明引用,实现多态;
- 抽象类构造方法的作用:构建子类对象时,先构建父类对象。
abstract修饰类:不能 new 对象,但可以声明引用;abstract 修饰方法:只能声明方法,没有方法实现;抽象类中不一定有抽象方法,但有抽象方法的类一定是抽象类;子类继承抽象类后,必须重写抽象类中所有的抽象方法,否则子类仍要定义为抽象类。
public abstract class 类名 {
public abstract void 方法名(); // 抽象方法
public void 方法名() {
}
}
static
译为静态,static关键字可以修饰属性、方法和代码块。被static修饰的属性为「静态属性」(类属性),被static修饰的方法为「静态方法」(类方法);静态成员是全类所有对象共享的成员,只有一份;访问静态成员时,不必创建对象,如果在本类中,直接通过方法名进行调用,而在其他类中需要类名.属性名或类名.方法名进行调用。
实例属性:实例属性是每个对象各自的属性,每个对象都有自己独立的空间,对某一个对象属性的修改,不会影响其他对象的属性。
静态属性:静态属性是整个类共同持有的属性,在方法区中创建,只有一份,任何对象对其修改,都会造成影响。
静态方法特点
- 静态方法允许直接访问静态成员
- 静态方法不能直接访问非静态成员
- 静态方法中不允许使用
this或super关键字 - 静态方法可以继承,不能重写、没有多态
类加载
「JVM」首次使用某个类时,需通过「CLASSPATH」查找该类的「.class」文件。将「.class」文件中对类的描述信息加载到内存中,进行保存。如:包名、类名、父类、属性、方法、构造方法...。什么时候进行类加载呢?
- 创建对象
- 创建子类对象
- 访问静态属性
- 访问静态方法
- 主动加载:Class.forName("全限定名")
代码块
- 局部代码块
主要是限定变量的使用范围(基本不用)
public class CodeBlock {
public static void main(String[] args) {
// 局部代码块
{
int age = 10;
System.out.println(age);
}
int num = 20;
System.out.println(num);
}
}
- 动态代码块
动态代码块在创建对象时会执行,而且每创建一个对象就会执行一次。执行顺序为:字段初始化 -> 动态代码块 -> 构造器。下面的例子在编译时会报错Cannot read value of field 'name' before the field's definition正确的应该经报错位置改为System.out.println(this.name + this.age)
class Person {
// 动态代码块不能放在变量之前
// 无法在字段定义之前使用字段
{
System.out.println("动态代码块执行");
name = "john";
age = 10;
System.out.println(name + age); // 报错位置
}
String name;
int age;
public Person() {
System.out.println("Person构造器执行");
}
}
- 静态代码块
类加载时,执行静态代码块(仅执行一次)。在静态属性初始化之后执行静态代码块。作用:可为静态属性赋值,或必要的初始化行为。
当类加载时,触发静态代码块的执行,输出china。特殊的:如果将country静态变量放在代码块下面,将输出null。可根据反编译代码查到原因。
class Student {
static String country = "china";
static {
System.out.println(Student.country);
}
public void show() {
}
}
对象创建过程各属性和代码块加载顺序:
静态属性 -> 静态代码块 -> 实例属性 -> 动态代码块 -> 构造方法
带有继承的对象创建过程
父类静态属性 -> 父类静态代码块 -> 子类静态属性 -> 子类静态代码块 -> 父类实例属性 -> 父类动态代码块 -> 父类构造方法 -> 子类实例属性 -> 子类实例代码块 -> 子类构造方法
final
被final修饰的类不能被继承、属性不能再次修改、方法不能被覆盖。
final可修饰的内容:类、方法、属性。
常见的被final修饰的类:String、Math、System,均不能被继承。
- final 变量:「final」修饰基本数据类型,
final int num = 10,内容不可变。 - 实例常量:在类中声明,实例常量的赋值时机:显示初始化、动态代码块、构造方法,但一般都用前两种,因为如果在构造方法中进行赋值时,必须保证所有的构造方法都能对其进行正确赋值。
- 静态常量:
static final String SCHOOL_NAME;,赋值时机:显示初始化、静态代码块。 - 对象常量:「final」修饰引用数据类型,地址不可变,但内容可变
注意
abstract和final不能同时使用:抽象类或方法就是为了让继承而使用的,增加final又不让继承或覆盖,二者相矛盾。abstract和static不能同时使用:static直接对方法和属性进行调用,而方法没有方法体,二者相矛盾。