String类的分析:

在IDEA程序中我们在运用String类时都会比较好奇,String类中到底是什么样的,博主就看了一部分,并了解其中用法。
在这里插入图片描述
在这代码中final:不可被继承,是String中的重要一部分,它主要保证string具有不可变性,如果没有final,String可能会被恶意删改。

常量池和缓存的基础:

String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");

System.out.println(s1 == s2);  // true,指向常量池同一对象
System.out.println(s1 == s3);  // false,新建对象

// 如果 String 可被继承,常量池无法保证对象行为一致

哈希值的缓存:

public final class String {
    private int hash;  // 缓存哈希值
    
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            // 计算并缓存
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + value[i];
            }
            hash = h;
        }
        return h;
    }
}

因为final保证了不可变性,才有哈希值的安全缓存;

让我用一个具体的例子来说明,如果没有 final修饰,子类如何破坏 String的行为:

假设String类没有final。

// 定义一个恶意的 String 子类
class MaliciousString extends String {
    private boolean tampered = false;
    
    public MaliciousString(String original) {
        super(original);
    }
    
    // 重写 equals 方法,制造安全漏洞
    @Override
    public boolean equals(Object obj) {
        // 总是返回 true,无论比较什么!
        tampered = true;
        return true;
    }
    
    // 重写 charAt 方法,返回错误的值
    @Override
    public char charAt(int index) {
        // 总是返回 'X'
        return 'X';
    }
    
    // 重写 hashCode 方法
    @Override
    public int hashCode() {
        // 返回固定值,破坏 HashMap 的性能
        return 1;
    }
}

实际攻击示例:

  1. 破坏密码验证:
public class PasswordValidator {
    // 验证密码的方法
    public boolean validatePassword(String inputPassword) {
        String realPassword = "secret123";  // 真实密码
        
        // 正常情况下应该比较字符串内容
        return realPassword.equals(inputPassword);
    }
    
    public static void main(String[] args) {
        PasswordValidator validator = new PasswordValidator();
        
        // 攻击者使用恶意的 String 子类
        MaliciousString fakePassword = new MaliciousString("wrong_password");
        
        // 由于 equals 被重写为总是返回 true
        // 验证会通过,即使密码错误!
        boolean result = validator.validatePassword(fakePassword);
        System.out.println("验证结果: " + result);  // 输出:true(被黑了!)
    }
}
  1. 破坏 HashMap 的完整性:
import java.util.HashMap;
import java.util.Map;

public class HashMapAttack {
    public static void main(String[] args) {
        // 使用 String 作为键的 HashMap
        Map<String, String> userDatabase = new HashMap<>();
        userDatabase.put("admin", "管理员权限");
        userDatabase.put("user1", "普通用户权限");
        
        // 插入恶意键
        MaliciousString maliciousKey = new MaliciousString("admin");
        userDatabase.put(maliciousKey, "攻击者权限");
        
        // 问题1:查找行为异常
        System.out.println("查找 admin: " + userDatabase.get("admin"));
        // 可能返回 "攻击者权限" 而不是 "管理员权限"
        
        // 问题2:HashMap 内部结构被破坏
        System.out.println("HashMap 大小: " + userDatabase.size());
        // 可能显示 3,但实际上键 "admin" 被覆盖了
        
        // 问题3:性能被破坏
        for (int i = 0; i < 10000; i++) {
            userDatabase.put(new MaliciousString("key" + i), "value");
        }
        // 所有键的 hashCode 都是 1,HashMap 退化为链表,O(1) → O(n)
    }
}
  1. 破坏字符串操作:
public class StringOperationBreaker {
    public static void main(String[] args) {
        String str = "Hello World";
        MaliciousString malicious = new MaliciousString("Hello World");
        
        // 正常 String
        System.out.println("正常字符串:");
        for (int i = 0; i < str.length(); i++) {
            System.out.print(str.charAt(i));
        }
        // 输出: Hello World
        
        System.out.println("\n恶意字符串:");
        for (int i = 0; i < malicious.length(); i++) {
            System.out.print(malicious.charAt(i));
        }
        // 输出: XXXXXXXXXXX (全部是 X!)
        
        // 更严重的问题:方法调用链
        String processed = str.toUpperCase().substring(2, 5);
        System.out.println("\n正常处理: " + processed);  // 输出: LLO
        
        String processed2 = malicious.toUpperCase().substring(2, 5);
        System.out.println("恶意处理: " + processed2);  // 输出: XXX
    }
}

为什么final可以防止这些问题:

// String 的实际定义
public final class String {  // ← 这个 final 是关键!
    // 类体...
}

// 尝试继承会编译错误
class MaliciousString extends String {  // ❌ 编译错误:无法从 final String 继承
    // ...
}

以上就是今天内容,如有错误或者想法都可以提出来,大家一起讨论。

更多推荐