1. final
1)被final关键字修饰的变量不能改变 (变量的引用不能改变,变量的内容是可以改变的)
2)被final关键字修饰的方法不能被重写
3)被final关键字修饰的类不能被继承
1.1 final变量
1.当final修饰基本数据类型变量,变量值不可改变
2.当修饰引用数据类型变量,变量的引用不可以被改变,但是变量本身指向的对象或者数组的值可以改变
package org.yunqing.myDemo;
public class FinalTest {
public static void main(String[] args) {
//基本数据类型
final int i = 1;
i = 2;//直接报错The final local variable i cannot be assigned.
//It must be blank and not using a compound assignment
//引用类型,引用test类
final Test t = new Test("66");
System.out.println(t.getStr());
t.setStr("77");//重新setStr的值,没问题,说明变量本身指向的对象的值可以改变
System.out.println(t.getStr());
t = new Test("99");//试着重新new一个test给t对象,
//报错The final local variable i cannot be assigned.
//说明变量的引用不可以改变
}
}
class Test{
private String str;
public test(String str) {
this.str = str;
}
public String getStr() {
return str;
}
public void setStr(String a) {
this.str = a;
}
}
1.2 final方法
方法前面加上 final 关键字,代表这个方法不可以被子类重写。如果你认为一个方法的功能已经足够完整了,子类中不需要改变的话,你可以声明此方法为 final。final 方法比非 final 方法要快,因为在编译的时候已经静态绑定了,不需要在运行时再动态绑定。
class PersonalLoan{
public final String getName(){
return "personal loan";
}
}
class CheapPersonalLoan extends PersonalLoan{
@Override
public final String getName(){
return "Chean personal loan"; // Compilation error:overridden method is final
}
}
1.3 final类
final 类通常功能是完整的,他们不能被继承。Java 中有许多类是 final 的,譬如 String、Integer 以及其他包装类。
final class PersonalLoan{ }
class CheanPersonalLoan extends PersonalLoan { // Compilation error:cannot inherit form final class
}
1.4 final关键字好处
1)final 关键字提高了性能。JVM 和 Java 应用都会缓存 final 变量。
2)final 变量可以安全的在多线程环境下进行共享,而不需要额外的同步开销。
3)使用 final 关键字,JVM 会对方法、变量及类进行优化。
2. static
关于 static 关键字的使用,它可以用来修饰的成员变量和成员方法,被修饰的成员是属于类的,而不是单单是属于某个对象的。也就是说,既然属于类,就可以不靠创建对象来调用了。
2.1 类变量
当 static 修饰成员变量时,该变量称为类变量。该类的每个对象都共享同一个类变量的值。任何对象都可以更改该类变量的值,但也可以在不创建该类的对象的情况下对类变量进行操作。
public class Student {
private String name;
private int age;
// 学生的id
private int sid;
// 类变量,记录学生数量,分配学号
public static int numberOfStudent = 0;
public Student(String name, int age){
this.name = name;
this.age = age;
// 通过 numberOfStudent 给学生分配学号
this.sid = ++numberOfStudent;
}
// 打印属性值
public void show() {
System.out.println("Student : name=" + name + ", age=" + age + ", sid=" + sid );
}
}
public class StuDemo {
public static void main(String[] args) {
Student s1 = new Student("张三", 23);
Student s2 = new Student("李四", 24);
Student s3 = new Student("王五", 25);
Student s4 = new Student("赵六", 26);
s1.show(); // Student : name=张三, age=23, sid=1
s2.show(); // Student : name=李四, age=24, sid=2
s3.show(); // Student : name=王五, age=25, sid=3
s4.show(); // Student : name=赵六, age=26, sid=4
}
}
2.2 静态方法
当 static 修饰成员方法时,该方法称为类方法 。静态方法在声明中有 static ,建议使用类名来调用,而不需要创建类的对象。静态方法在类加载的时候就存在了,他不依赖于任何实例。所以静态方法必须有实现,也就是说它不能是抽象方法。
public class StuDemo2 {
public static void main(String[] args) {
// 访问类变量
System.out.println(Student.numberOfStudent);
// 调用静态方法
Student.showNum();
}
}
注意事项:
1) 静态方法可以直接访问类变量和静态方法。
2) 静态方法 不能直接访问普通成员变量或成员方法。反之,成员方法可以直接访问类变量或静态方法。
3) 静态方法中,不能使用 this和super关键字。
4) 静态方法只能访问静态成员
2.3 静态语句块
特点:当第一次用到本类时,静态代码块执行唯一的一次。 静态内容总是优先于非静态,所以静态代码块比构造方法先执行。
public class Game {
public static int number;
public static ArrayList<String> list;
static {
// 给类变量赋值
number = 2;
list = new ArrayList<String>();
// 添加元素到集合中
list.add("张三");
list.add("李四");
}
}
2.4 初始化顺序
静态变量和静态语句块优先于实例变量和普通语句块,静态变量和静态语句块的初始化顺序取决于它们在代码中的顺序
存在继承的情况下,初始化顺序:
父类(静态变量、静态代码块)
子类(静态变量、静态代码块)
父类(实例变量、普通语句块)
父类(构造函数)
子类(实例变量、普通语句块)
子类(构造函数)