final,见名知意,就是最终的意思,那么它在java中可以修饰什么呢?又有什么作用呢?
一、final的使用
在java中,final可以修饰变量,方法,类。
1.1 final修饰变量
当变量被final修饰时,那么此时的变量也就称之为常量。当一旦final修饰的变量被初始化后,那么值(数值和引用地址值)将不能再被改变。
1.1.1 final修饰成员变量
当final修饰成员变量时,必须要显式初始化,也就是你必须要给它赋个值。
那么有哪些方式可以赋值呢?
1.1.1.1 成员变量为基本类型时
当成员变量为基本类型时,那么此时被final修饰的它们,一旦初始化后,数值将不可改变。
public class Demo {
public static void main(String[] args) {
Box b1=new Box();
System.out.println(b1);
System.out.println("=================");
Box b2=new Box(20);
System.out.println(b2);
}
}
class Box{
//Variable 'length' might not have been initialized
//final int length;
//一般对于常量,我们都全大写表示,为了演示方便,就不用了
//final int LENGTH=0;
final int length=5; //声明时初始化
final int width; //代码块中初始化
final int height; //构造器初始化
{
//Cannot assign a value to final variable 'length':不能将值赋给最终变量length
//length=10;
}
//代码块初始化
{
width=10;
}
public Box() {
this.height = 15;
}
public Box(int height) {
this.height = height;
}
@Override
public String toString() {
return "Box{" +
"length=" + length +
", width=" + width +
", height=" + height +
'}';
}
}
输出:
Box{length=5, width=10, height=15}
=================
Box{length=5, width=10, height=20}
通过上例代码,我们可以发现,当成员变量被final修饰时,我们可以通过声明初始化,代码块,构造器,为final修饰的成员变量进行赋值初始化操作,而在初始化后值将不能再改变
1.1.1.2 成员变量为引用类型
class Duck{
private String name;
public Duck() {
}
public Duck(String name) {
this.name = name;
}
}
class Dog {
private String name;
public Dog(String name) {
this.name = name;
}
//getter方法
public String getName() {
return name;
}
}
class Cat {
private String name;
public Cat(String name) {
this.name = name;
}
//getter方法
public String getName() {
return name;
}
}
class Mouse {
private String name;
public Mouse(String name) {
this.name = name;
}
//getter和setter方法
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
class Box {
Duck duck=new Duck();
final Dog dog = new Dog("Speike"); //声明初始化
final Cat cat; //代码块初始化
final Mouse mouse; //构造器初始化
//代码块初始化
{
cat = new Cat("Tom");
}
//代码块初始化
{
duck=new Duck("唐老鸭");
//Variable 'dog' might already have been assigned to
//dog = new Dog("大黄"); //编译不通过
}
//无参构造初始化
public Box() {
mouse = new Mouse("Jerry");
}
//有参构造初始化
public Box(Mouse mouse) {
this.mouse = mouse;
}
@Override
public String toString() {
return "Box{" +
"dog地址值:" + System.identityHashCode(dog) +
",dog值:" + dog.getName() +
", cat地址值:" + System.identityHashCode(cat) +
", cat值:" + cat.getName() +
", mouse地址值:" + System.identityHashCode(mouse) +
", mouse值:" + mouse.getName() +
'}';
}
}
public class Demo {
public static void main(String[] args) {
Box box=new Box();
System.out.println(box);
System.out.println("========================================分割线==============================================");
Mouse mouse = new Mouse("米老鼠");
Box b1 = new Box(mouse);
System.out.println("修改前:"+b1);
//修改mouse的值
mouse.setName("杰瑞");
System.out.println("修改后:"+b1);
}
}
输出:
Box{dog地址值:460141958,dog值:Speike, cat地址值:1163157884, cat值:Tom, mouse地址值:1956725890, mouse值:Jerry}
========================================分割线==============================================
修改前:Box{dog地址值:356573597,dog值:Speike, cat地址值:1735600054, cat值:Tom, mouse地址值:21685669, mouse值:米老鼠}
修改后:Box{dog地址值:356573597,dog值:Speike, cat地址值:1735600054, cat值:Tom, mouse地址值:21685669, mouse值:杰瑞}
在上例中,我们在Box中初始化无final修饰的Duck和有final修饰的Dog,Cat,Mouse。通过比较我们可以发现,final修饰的引用类型的成员变量亦是可以通过声明,代码块,构造器进行初始化,并且比较Duck和Dog后,还可以发现,final修饰的引用类型的成员变量在第一次初始化后,不可以被再次赋值,而Duck没被final修饰,则没有此限制。
接着我们在main方法中创建了一个mouse对象和b1对象,然后我们打印了下b1对象,接下了我们修改了mouse的name值,接着再次进行打印。比较一下修改前后的打印的值,发现在将mouse值由米老鼠修改成杰瑞时,他们的mouse对象的地址值并没有改变。由此我们可以确认,final修饰引用类型的成员变量时,在将它们初始化后,将不能再指向其他对象,但它们所指向对象的内容却是可以修改的。
1.1.2 final修饰局部变量
当使用final修饰局部变量时,在初始化后,将不可给它们再次赋值,也就是说,在第一次赋值后,它们的值(无论是数值还是地址值)都将不能改变。
1.1.2.1 局部变量类型为基本类型
public class Demo{
public static void main(String[] args) {
Box box=new Box();
box.show(10);
}
}
class Box{
public void info(){
final int ID=10;
//ID=10; //Cannot assign a value to final variable 'ID'
}
public void show(final int price){
//Cannot assign a value to final variable 'price'
//price=10;
System.out.println(price);
}
}
输出:
10
通过上例,我们可以发现在final修饰基本类型的局部变量(参数列表也是局部变量)时,数值在第一次赋值后将不能再被改变。
1.1.2.2 局部变量类型为引用类型
class Box {
public void info() {
final Gift gift=new Gift();
//Cannot assign a value to final variable 'gift'
//gift=new Gift();
}
public void showFinal(final Gift gift){
//Cannot assign a value to final variable 'gift'
//gift=new Gift();
System.out.println(gift);
}
public void show(Gift gift){
gift=new Gift();
System.out.println(gift);
}
}
在上例,final修饰的引用类型的局部变量在初始化后,会发现不能改变它们指向的引用地址值了。
1.2 final修饰方法
当方法被final所修饰时,那么这个方法将不能被重写(覆盖)。
class Animal{
final void info(){
}
}
class Cat extends Animal{
//'info()'cannot override 'info()'in 'Animal';overridden method is final
//info()方法不能被重写
// void info() {
// super.info();
// }
}
1.3 final修饰类
当类被final所修饰时,那么这个类将不会被其他类所继承。
public class Demo {
public static void main(String[] args) {
Animal cat=new Animal();
cat.name="Tom";
cat.info();
}
}
final class Animal{
String name;
final int age=1;
void info(){
System.out.println(name+":"+age+"岁");
}
}
//Cannot inherit from final 'Animal' //无法继承最终类A
//class Cat extends Animal{
//
//}
输出:
Tom:1岁
上述代码中,当类Animal被final修饰后,Cat类将不可以继承Animal类,这时编译是不会通过的,理所当然的,既然类不能被继承,那么类中的方法自然也不会被重写(覆盖)。对于属性name,age可以发现在最终类Animal中,属性可以为final所修饰,也可以不被final修饰。
在java中也有许多类被final修饰,比如说:String类,System类等等。它们都不能被继承。
二、总结
通过以上可以总结出:
final可以修饰变量,方法,类。
当final修饰变量时,此时的变量被称为常量。当变量经过初始化后,它们的数值或者引用地址值是不能再次改变的。
- final修饰成员变量:成员变量为基本数据类型时,在初始化后,就不能改变数值了。成员变量为引用数据类型时,在初始化后,成员变量就不能指向其他的对象了。对于初始化,成员变量可以通过声明初始化,代码块初始化,构造器初始化三种方式。
- final修饰局部变量:局部变量在初始化后,它的数值或引用地址值将不能改变。
final修饰方法:当方法被final修饰时,将不能被重写。
final修饰类:当类被final修饰时,将不能被继承,而由此方法也必定不会被重写。
最后:static关键字可以和final连用。可以用来修饰属性和方法()。
当修饰属性时,此时变量为全局常量,并且它在类的加载时就会初始化。