Final关键字(修饰变量)

本文详细解析了Java中的final关键字,探讨其如何确保类、方法及变量的最终性,并通过实例展示了final修饰的变量引用虽不可重新赋值,但其内部数据仍可修改的特点。

final关键字:保证被修饰的非抽象类、非抽象类成员方法和变量是最终态的

(网上收集)


但有种情况final不能保证被修饰的变量不会被改变:

class Final  
{  
    public static void main(String[] args)  
    {  
        Color.color[3] = "white";  
        for (String color : Color.color)  
            System.out.print(color+" ");  
    }  
} 
class Color  
{  
    public static final String[] color = { "red", "blue", "yellow", "black" };  
}
//result:red blue yellow white 

这个时候观察结果,发现“black”还是变成了white

原因是final只是让color这个引用不能被重新绑定(赋值),但是color这个引用的内部数据是可以更改的.

在wiki上有这样一张图:



final关键字的灵活性:

final是在被赋值一次后就不能再赋值了,但也只能在construct method和static块还有被定义时赋值:

class FinalTest {
	private final int num1 = 1;
	private final int num2;
	private final int num3;
	
	static {
		this.num2 = 1;
	}
		
	public FinalTest(int num) {
		num3 = num;
	}
}
这一定程度上使final关键字有了一定的灵活性


其实以上所有的描述 都可以化为下面一段代码:

public class Bat{
    final PI=3.14;          //在定义时便给址值
    final int i;            //因为要在构造方法中进行初始化,所以此处便不可再给值
    final List list;        //此变量也与上面的一样
    Bat(){
        i=100;
        list=new LinkedList();
    }
    Bat(int ii,List l){
        i=ii;               //可以在构造方法/static块中给final修饰的变量赋值,让final更加灵活
        list=l;
    }
    public static void main(String[] args){
        Bat b=new Bat();
        b.list.add(new Bat());  //可以修改final修饰的引用对象的内部数据
        //b.i=25;
        //b.list=new ArrayList(); //报错,被final修饰的引用不能被再次绑定
        System.out.println("I="+b.i+" List Type:"+b.list.getClass());
        b=new Bat(23,new ArrayList());
        b.list.add(new Bat());
        System.out.println("I="+b.i+" List Type:"+b.list.getClass());
    }
}


### final关键字修饰变量、方法、类的区别 | 修饰对象 | 作用 | 是否可变 | |----------|------|-----------| | **变量** | 表示常量,值不可改变(基本类型)或引用不可变(对象类型) | ❌ 不可修改(对象内容可变) | | **方法** | 表示该方法不能被子类重写(Override) | ✅ 方法内部的局部变量可以修改 | | **类** | 表示该类不能被继承 | ✅ 类中的方法可以修改(不是final的话),但不能被继承 | --- ### 1. `final` 修饰方法:方法里的数据能修改吗? ✅ **可以修改。** - `final` 修饰方法表示该方法**不能被子类重写**,但其**方法内部的数据是可以修改的**。 - 示例: ```java class MyClass { public final void show() { int x = 10; x++; // 合法,x是局部变量 System.out.println(x); } } ``` --- ### 2. `final` 修饰类:类中的方法可以修改吗?可以被重写吗? - ✅ **类中的方法可以修改源码**(如果你有源代码权限); - ❌ **类不能被继承**,因此其方法自然也无法被重写。 示例: ```java final class MyFinalClass { public void method() { System.out.println("Original"); } } // 编译错误:无法继承final类 class SubClass extends MyFinalClass { } ``` --- ### 3. 可以通过反射修改 `final` 修饰的属性吗? ✅ **在某些情况下可以,但需要绕过Java语言访问控制机制。** - Java的反射机制允许我们访问和修改私有字段,甚至包括 `final` 字段; - 修改过程通常涉及: - 获取字段对象 `Field` - 设置 `field.setAccessible(true)` - 使用 `field.set(obj, newValue)` #### 示例: ```java class MyClass { public final int value = 10; } public class Test { public static void main(String[] args) throws Exception { MyClass obj = new MyClass(); Field field = MyClass.class.getDeclaredField("value"); field.setAccessible(true); Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL); // 去掉final标志 field.set(obj, 20); // 修改final字段成功 System.out.println(obj.value); // 输出 20 } } ``` --- ### 4. 无论什么情况下都可以通过反射来修改 `final` 属性吗? ❌ **不一定,取决于运行时环境和JVM实现。** - 在 **Java 8及更早版本** 中,上述反射方式通常可行; - 在 **Java 9及以上模块化系统中**,由于模块系统的限制(Strong Encapsulation),默认情况下对 `setAccessible(true)` 的调用可能失败,除非使用 `--add-opens` 参数开启访问权限; - 某些安全策略(如安全管理器启用)会阻止这种操作; - Android等平台可能有不同的行为。 --- ### 总结 | 问题 | 答案 | |------|------| | final修饰变量、方法、类有什么区别? | 变量不可变,方法不可重写,类不可继承 | | final方法里的数据能修改吗? | ✅ 可以修改局部变量 | | final类的方法可以修改吗? | ✅ 可以改源码,但不能被继承 | | final类的方法可以被重写吗? | ❌ 不可以 | | final属性可以通过反射修改吗? | ✅ 通常可以,但需处理修饰符 | | 所有情况都能反射修改final属性吗? | ❌ 不一定,受JVM版本、安全策略影响 | ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值