final:意为最终,不可变,是一个修饰词
有时候一个类地功能被开发好了,不想让子类重写,修改,这里就会用到final关键字
final修饰类:
不可以被继承,但是可以继承其他类
示例:
public final class Fu { public void show(){ System.out.println("最终类的方法"); } //这个类不能被继承 //使用方法不变 }
public class Test { public static void main(String[] args) { Fu f = new Fu(); f.show(); } }
final修饰方法:
不可以被子类重写
示例:
public class Fu { public final void show(){ System.out.println("父类的最终方法"); } public void function(){ System.out.println("父类的一般方法"); } }
public class Zi extends Fu { public void function(){ System.out.println("子类重写父类的一般方法"); } //不可以重写父类的show方法 }
public class Test { public static void main(String[] args) { Zi z = new Zi(); //方法的使用方式没有改变 z.function(); z.show(); } }
final修饰的变量称为常量,只能被赋值一次:
一次赋值,终身不变
如果final修饰引用数据类型,那么保存变量的内存地址将终身不变
final修饰成员变量:
成员变量保存在堆内存中,是有默认值的,所以final修饰成员变量必须要赋值
由于成员变量的赋值方式有两种:直接赋值;构造方法赋值,所以final修饰的成员变量可以选择其中一种进行赋值
但是要保证只能被赋值一次
示例:
public class Person { //直接赋值(实际中建议这样方式): //final int age = 18; //构造方法赋值: final int age; public Person(int age){ this.age = age; } }
static:
意义举例:
一个学校里有一群学生对象,他们都有不同的姓名和年龄,但是他们的学校名都是相同的,
创建学生对象的时候,成员变量中的学校名在每次新建对象的时候都会存入堆内存,但是每次存的数据都是相同的,造成了内存的浪费
于是想到,能否将学校名提出来,放到某个地方,让多个对象共享,节省内存
于是,出现了static关键字:
静态多了一种调用方式
被静态修饰的成员,可以被类的名字直接调用
示例:
public class Person { String name; static String className; }
public class Test { public static void main(String[] args) { Person p1 = new Person(); Person p2 = new Person(); p1.name = "张三"; p2.name = "李四"; p1.className = "一班"; //共享数据的特性:一处改,其他对象跟着改 System.out.println(p2.className); System.out.println(Person.className); } } //输出:一班
根据这个示例对static内存的分析:
内存中,静态优先于非静态存在的
1.Test.class文件中的main方法进入数据共享区(静态区),
2.Person.class文件中的className变量进入数据共享区,并赋默认值null
3.开始执行,运行main方法,JVM到静态区将main方法复制一份,压栈执行
4.创建对象,堆中开空间存对象,成员变量跟随,静态不进入,因为静态变量早进入了静态区
5.JVM到静态区,找到属于Person类的静态属性className,进行修改等操作
静态的注意事项:
静态不能调用非静态:
原因:声明周期
静态优先于非静态存在于内存在,无法调用不存在的
比如古人无法访问现代人
非静态可以调用静态
比如现代人可以访问古人(可能有点不恰当...理解就行)
静态不能用this,super方法,
同样,静态在创建对象前就存在,不允许访问不存在的
而在实际中,通常静态对静态,非静态对非静态
示例:
public class Student { private String name; private static int age; public static void function(){ //System.out.println(name); //这里的静态方法不能调用非静态 } public void show(){ System.out.println(age); //非静态可以调用静态 } }
静态修饰应用场景:
本身是一个成员修饰符,可以修饰成员变量,可以修饰成员方法
多个事物之间是否存在共性数据?这里就可以将这个共性数据定义成静态
只要方法没有调用过非静态成员,则将其定义为静态
对象中的静态调用:
这里是之前多态中的一个难点:
示例:
public class Fu { static int i = 1; public static void show(){ System.out.println("父类的静态方法"); } }
public class Zi extends Fu { static int i = 2; public static void show(){ System.out.println("子类的静态方法"); } }
public class Test { public static void main(String[] args) { Fu f = new Zi(); System.out.println(f.i); f.show(); } } /*输出: 1 父类的静态方法 */ /* 多态中,编译看等号左边的,父类有编译成功,父类没有,编译失败 运行看等右边的, 如果是静态方法,运行的是父类中的静态方法 如果是非静态方法,运行的是子类重写的非静态方法 成员变量: 无论静态非静态,编译运行都是父类的 根本原因:静态属于类,不输入对象 多态性是讨论对象的性质,而静态和对象无关, */
最后,
在开发中,有时候需要定义静态常量,并且常量名要求全大写,空格用_代替
固定格式:public static final String THIS_NAME = "XXXX"