[Java].java and .class

今天在看《Java编程思想》第五章-隐藏实施过程时候,对有句话很迷惑。

原文是这样的:编译一个.java文件时,我们会获得一个名字完全相同的输出文件;但对于.java文件中的每个类,它们都有一个.class扩展名。

因此,我们最终从少量的.java文件里有可能获得数量众多的.class文件。

所以,关于这些我的个人理解是:一个.java文件会出现 >= 1 个的.class文件。所以很疑惑,查了下资料。


在stackflow中查找到了相关解释:https://stackoverflow.com/questions/1031962/multiple-class-files-generated-for-a-class。

给出了下面的Demo

class Foo {
   class Bar { }
   static class Baz { }
   void run() {
      Helper t = new Helper() {//这个是匿名内部类
         int helpMethod() {
            return 2;
         }
      };
    }
}

上面代码的解释为:

These are for inner classes(非静态嵌套类,又称内部类) and static nested classes(静态嵌套类). The ones with numbers are anonymous inner classes.

This will produce class files Foo.class, Foo$Bar.class,Foo$Baz.class and Foo$1.class (for the implementation of theHelper interface)。


看老外对代码的解释有点晕,然后查找了关于inner classes(内部类的资料):

https://www.cnblogs.com/lgk1002/p/6069784.html <--这里总结得比较全。

嵌套类分为静态嵌套类和非静态嵌套类。

静态嵌套类:使用很少。

非静态嵌套类:最重要是非静态嵌套类,又称为内部类。

内部类又分成三类:

1.在一个类(外部类)中直接定义的内部类;

2.在一个方法(外部类的方法)中定义的内部类;

3.匿名内部类。

然后自己写了一个Demo编译了一下:

package innerclass;

//demo from https://stackoverflow.com/questions/1031962/multiple-class-files-generated-for-a-class
class Foo {
   class Bar { }
   static class Baz { }
   int run() {
      Object t = new Object() {
    	  //new Object() {......}  <-- 匿名内部类
    	//这里重写了Object的hashCode方法,原方法中的访问修饰符是public,所以这里必须为public
         public int hashCode() {
            return 2;
         }
      };
     return t.hashCode();
    }
   
   public static void main(String[] args) {
	 Foo foo = new Foo();
	 System.out.println(foo.run());
}
}


查看了一下编译结果:

在src同一级的bin目录下有:


除了Foo$1.class之外,其他3个还是比较清楚的,然后打开Foo$1.class看了下:

里面有innerclass/Foo$1 java/lang/Object

LocalVariableTable this Linnerclass/Foo$1; hashCode ()I  等字样,应该是给就是  new Object() {......}  <-- 匿名内部类 的.class文件。


另外至于.java 与.class的关系就是:

.java为Java的源文件后缀,编写的代码需要写在.java文件中。
而.class是字节码文件,是.java源文件通过javac命令编译后生成的文件。
Java虚拟机就是去运行.class文件从而实现程序的运行。
负责加载Java class的这部分就叫做Class Loader

你遇到的错误: ``` class java.util.HashMap cannot be cast to class java.lang.Long (java.util.HashMap and java.lang.Long are in module java.base of loader 'bootstrap') ``` 这个异常是 **`ClassCastException`**,表示你试图将一个 `HashMap` 对象强制转换成 `Long` 类型,这是不可能的,因为两者完全不兼容。 --- ### ❌ 错误原因分析: 这种错误通常出现在以下几种场景中: #### 场景 1:错误地遍历 Map ```java Map<Long, Long> map = new HashMap<>(); // ... 添加数据 for (Long key : map) { // ❌ 错误!map 本身不是 Iterable<Long>,不能直接 for-each 遍历 } ``` 你写成了: ```java for (Long l : map) // 编译报错或运行时类型混淆 ``` 而正确的方式应该是遍历 `map.keySet()`、`map.values()` 或 `map.entrySet()`。 #### 场景 2:错误地进行类型转换(强转) ```java Map<Long, Long> map = new HashMap<>(); Long value = (Long) map; // ❌ 明显错误:把整个 map 强转为 Long ``` 这行代码会导致你在运行时得到: > java.util.HashMap cannot be cast to java.lang.Long #### 场景 3:从集合中取值时类型混乱(常见于原始类型和泛型擦除) 例如使用了非泛型 Map: ```java Map map = new HashMap(); // 原始类型,失去泛型约束 map.put("key", 100L); Long value = (Long) map; // ❌ 又是把 map 整体强转为 Long ``` 或者: ```java Map<String, Object> map = new HashMap<>(); map.put("total", 100L); Long total = (Long) map.get("total"); // ✅ 正确:取的是 value ``` 但如果误写成: ```java Long total = (Long) map; // ❌ 把整个 map 当作 Long 来强转 → 抛出 ClassCastException ``` --- ### ✅ 正确做法:如何安全地计算 `Map<Long, Long>` 的 value 总和? 确保你操作的是 `map.values()`,而不是 `map` 本身。 #### ✅ 正确代码示例: ```java import java.util.HashMap; import java.util.Map; public class SumMapValues { public static void main(String[] args) { Map<Long, Long> map = new HashMap<>(); map.put(1L, 100L); map.put(2L, 200L); map.put(3L, 300L); // 使用 Stream 求和 long sum = map.values().stream() .mapToLong(Long::longValue) .sum(); System.out.println("总和: " + sum); // 输出: 600 } } ``` 关键点: - `map.values()` 是 `Collection<Long>`,可以流式处理。 - 不要对 `map` 本身做 `(Long)` 强制转换! --- ### 🔍 如何避免此类错误? 1. **不要对容器对象进行基本类型强转** 比如:`(Long) map`, `(String) list` 等都是逻辑错误。 2. **使用泛型明确类型** ```java Map<Long, Long> map = new HashMap<>(); // 推荐 ``` 而不是: ```java Map map = new HashMap(); // 原始类型,容易出错 ``` 3. **调试技巧:打印对象类型** ```java System.out.println(map.getClass()); // class java.util.HashMap System.out.println(value.getClass()); // class java.lang.Long ``` 4. **IDE 提示要重视**:如果看到 `.stream()` 或 `.iterator()` 调用失败,说明你可能在错误的对象上调用方法。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值