三个修饰符
- 三个修饰符
- 一、abstract
- 1.1 修饰类
- 1.2 修饰方法
- 二、final
- 2.1 修饰类
- 2.2 修饰方法
- 2.3 修饰变量
- 2.3.1 修饰属性
- 2.3.2 修饰局部变量
- 2.3.3 修饰方法的参数
- 2.3.4 常量
- 三、static关键字
- 3.1 修饰属性
- 3.2 修饰方法
- 3.3 修饰代码块
- 3.4 继承时的执行顺序
三个修饰符
一、abstract
abstract,抽象的。
1.1 修饰类
有的类是抽象出来的概念,只能作为父类存在,而不应该直接创建对象,此时,可以在类上加上abstract关键,设置该类为抽象类,不能直接创建对象,只能作为父类。
public abstract class Animal {private String name;public void eat() {System.out.println("动物在吃...");}
}
public class Demo1 {public static void main(String[] args) {// Animal a = new Animal(); // 报错,不能直接创建对象Animal a = new Dog(); // 使用子类创建对象}
}
1.2 修饰方法
在父类中,可能存在一些方法,必须要在子类中重写,那么可以在该方法前面加上abstract关键字,指定该方法在子类中应该重写。
public abstract class Animal {private String name;// 只需要方法的声明,不需要实现,所以没有大括号,直接使用分号结束public abstract void eat();
}
public class Dog extends Animal{@Overridepublic void eat() {System.out.println("狗在吃...");}
}
注意:
- 一个抽象类中可以没有抽象方法
- 有抽象方法的类必然是抽象类
- 抽象方法不能使用private,没有意义
- 当子类继承一个有抽象方法的抽象类时,会报错。此时有两种解决方案:
- 将子类也设置为抽象类
- 实现(重写)父类中所有的抽象方法
二、final
final,最终的,最后的,终结的,不可更改的。
2.1 修饰类
表示该类不能被继承。
注意:final不能和abstract一起使用。
2.2 修饰方法
表示该方法不能被重写。
2.3 修饰变量
表示该变量一旦赋值,不能改变,称为常量。
2.3.1 修饰属性
该属性必须在创建对象后,要有值。赋值的时机:
直接在属性定义时赋值
public class Dog{private final String name = ""; }
在代码块中赋值
public class Dog{private final String name;{name = "";} }
在构造方法中赋值
public class Dog{private final String name;public Dog() {this.name = "";}public Dog(String name) {this.name = name;} }
注意:不能再次赋值,所以当在代码块中赋值后,不能在构造方法中赋值,因为代码块在构造方法前执行。
2.3.2 修饰局部变量
public class Dog extends Animal{public void m1() {// 先声明,后赋值final int n; n = 6;// n = 5; 会报错,不能重复赋值// 声明的同时赋值final int m = 3;}
}
2.3.3 修饰方法的参数
public class Dog extends Animal{public void m2(final int n) {
// n = 5; 会报错, 表示该值不能修改}
}
2.3.4 常量
在类中一般会定义一些变量,声明为final修饰,视作常量。
在项目中,固定使用的一些常数,不希望在使用过程中被改变,会定义成常量。
常量定义的规范:单词全大写,多个单词使用下划线隔开。
// Integer类中的整数最大值:
public static final int MAX_VALUE = 0x7fffffff;
// Math类中的PI的值:
public static final double PI = 3.14159265358979323846;
三、static关键字
3.1 修饰属性
表示该属性为静态属性,也叫类属性。
同一个类共享同一个类型属性空间,也可以使用对象操作。但是不推荐。应该使用类名访问。
创建的对象在堆中,而类属性在方法区。
注意:不能修饰局部变量。不需要创建对象就可以使用类属性。
public class Student {public String name;public int age;public static String className;public void introduce() {
// static int n = 5; // 报错,不能修饰局部变量System.out.println(className);}
}
public class Demo1 {public static void main(String[] args) {Student s1 = new Student();s1.name = "张三";s1.age = 20;s1.className = "0班"; // 可以操作,但是不推荐Student.className = "1班"; // 静态属性,类属性Student s2 = new Student();s2.name = "李四";s2.age = 18;Student.className = "2班";System.out.println(s1.name + "," + s1.age + "," + Student.className + "---" + s2.name + "," + s2.age + "," + Student.className);}
}
在实例方法中是否可以调用静态属性?
- 可以,因为静态属性不需要创建对象就可以访问。创建了对象也可以访问。
3.2 修饰方法
表示该方法为静态方法(类方法)。
即直接使用类名调用的方法,不需要创建对象即可调用。
public class Student {public String name;public int age;public static String className;public static int count = 0;public Student() {count++;System.out.println("对象被创建了"+count+"次");}public void introduce() {
// static int n = 5; // 报错,不能修饰局部变量System.out.println(className);}// 静态方法,类方法public static void m1() {System.out.println("m1===被调用");}
}
注意:
- 静态方法不需要创建对象即可使用,直接用类名访问。
- 在静态方法中可以调用其他静态方法,但是不能调用非静态方法(实例方法)。
- 静态方法中可以调用静态属性,但是不能调用非静态属性(实例属性)。
- 静态方法中不能使用this和super。
- 静态方法可以继承,不能重写,没有多态。
3.3 修饰代码块
动态代码块:在类中直接使用一对大括号中的代码。创建对象时执行。
执行顺序:
- 初始化属性
- 执行动态代码块
- 执行构造方法
public class A {public String name = "aaa";{System.out.println(name);System.out.println("动态代码块");}public A() {System.out.println("构造方法");}
}public class Demo2 {public static void main(String[] args) {new A();}
}
静态代码块:使用static修饰的代码块叫静态代码块。类加载时执行。而且只执行一次。
创建对象时会先加载类。
加载类:将类的信息加载到内存中的方法区,以便得到对象所需的空间大小,方便创建对象。
执行顺序:
- 静态属性初始化(仅一次)
- 静态代码块(仅一次)
- 实例属性
- 动态代码块
- 构造方法
public class A {public static String sname = "静态属性";public String name = "实例属性";{System.out.println(name);System.out.println("动态代码块");}public A() {System.out.println("构造方法");}static {System.out.println(sname);
// System.out.println(name); // 不能访问实例属性System.out.println("静态代码块");}
}public class Demo2 {public static void main(String[] args) throws ClassNotFoundException {
// new A();// 加载类
// Class.forName("com.qf.day13.A");new A(); // 会先加载类
// new A();}
}
3.4 继承时的执行顺序
经典面试题:执行顺序:
父类静态属性(仅一次)
父类静态代码块(仅一次)
子类静态属性(仅一次)
子类静态代码块(仅一次)父类实例属性
父类动态代码块
父类构造方法
子类实例属性
子类动态代码块
子类构造方法
public class A {public static String sname = "父类静态属性";public String name = "父类实例属性";{System.out.println(name);System.out.println("父类动态代码块");}public A() {System.out.println("父类构造方法");}static {System.out.println(sname);System.out.println("父类静态代码块");}
}public class B extends A{public static String sname1 = "子类静态属性";public String name1 = "子类实例属性";{System.out.println(name1);System.out.println("子类动态代码块");}public B() {System.out.println("子类构造方法");}static {System.out.println(sname1);System.out.println("子类静态代码块");}
}public class Demo2 {public static void main(String[] args){new B();}
}