没人回答, 我自己把源码给改了下, 最终个人分析, 应该是源码的设计没有设计好, 下面是源码, 我把源码改成的类型变量的通配符改成了String, 结果运行不会出错. 
public Enumeration<?> propertyNames() { 
            Hashtable h = new Hashtable(); 
                 enumerate(h); 
                 return h.keys(); 
    } 
    private synchronized void enumerate(Hashtable h) { 
            if (defaults != null) { 
                    defaults.enumerate(h); 
            } 
           for (Enumeration e = keys(); e.hasMoreElements();) { 
                    String key =  (String)e.nextElement(); 
                    h.put(key, get(key)); 
            } 
    } 
 
而且源码还有个很大的问题就是, 当我们用Properties对象添加属性时, 我们可以用它的父类Hashtable<Object, Object>的put<Key k, Value v>方法来添加, 如果用put添加, 那么就可以是添加任意类型的键值对了, 但是如果我们真的给键添加了其它类型(非String), 这样在使用propertyNames()方法来获取所有键的枚举时, 会发现有个ClassCastException,类型转换异常, 这个原因是因为当调用  propertryNames()方法时, 该方法内部会创建一个Hashtable对象, 该对象没有记录键值对, 而之前在使用put方法时, Hashtable中有键值对, 那么这时新的对象要拥有键值对,就要把之前put方法添加的键值对添加到新的Hashtable中, 但是在添加过程中, 源码做了一个强转动作   String key =  (String)e.nextElement(); 该强转动作要能正确执行, 那么也就是说put方法添加的那个老值就必须是String类型的才能强转. 所以我个人觉得这就是源码上的缺陷, 如果把源码中的 public Enumeration<?> propertyNames()方法中Enumeration的通配符改成String, 那么当用户使用时, 就不会去添加其它类型.  或者不改通配符, 那么就把强转给改以下, 改成步强转, 用Object来接受要传递给新Hashtable中的老值, 这样也不会出错, 下面是出错代码: 
import java.util.Enumeration; 
import java.util.Hashtable; 
 
 
class Demo { 
    public static void main(String[] ags) { 
            Properties p = new Properties(); 
            p.put(1, "zhangsan"); 
            p.put(2, "zhangsan"); 
            p.put(3, "wangwu"); 
            Enumeration<String> keys = p.propertyNames(); 
            while (keys.hasMoreElements()) { 
                    String key = (String) keys.nextElement(); 
                    System.out.println(key); 
            }                 
    } 
} 
  建议源码修改样式一: 
class Properties extends Hashtable<Object, Object> { 
    protected Properties defaults; 
 
    public Enumeration<?> propertyNames() { 
            Hashtable h = new Hashtable(); 
                 enumerate(h); 
                 return h.keys(); 
    } 
 
    private synchronized void enumerate(Hashtable h) { 
            if (defaults != null) { 
                    defaults.enumerate(h); 
            } 
            for (Enumeration e = keys(); e.hasMoreElements();) { 
                       //这里不要强转, 用Object来接受, 那么使用Properties对象使用put方法添加元素 
                    //不论添加什么元素, 使用枚举器遍历都不会报错. 
                    Object key =  e.nextElement(); 
                    h.put(key, get(key)); 
            } 
    } 
} 
 
源码修改样式二: 
class Properties extends Hashtable<Object, Object> { 
    protected Properties defaults; 
 
    //这里把枚举的通配符改成String, 那么用户在使用Properties的put方法来添加键值对时,又想用propertyNames 
    //方法来获取枚举器遍历,那么用户就不会添加其它类型的键, 只会添加String类型的 
    //其实仅仅更改这里作用不大, 
    public Enumeration<String> propertyNames() { 
            Hashtable h = new Hashtable(); 
                 enumerate(h); 
                 return h.keys(); 
    } 
 
    private synchronized void enumerate(Hashtable h) { 
            if (defaults != null) { 
                    defaults.enumerate(h); 
            } 
            for (Enumeration e = keys(); e.hasMoreElements();) { 
                     //这里依然用强转 
                  String key =  (String)e.nextElement(); 
                   h.put(key, get(key)); 
            } 
    } 
} 
 
个人认为, 应该是Sun已经放弃了修改这个问题, 因为在JDK1.2后,添加了专门供Properties类添加键值对的方法, 且方法做了限制, 参数类型只能是String类型, 所以, 我们使用时是根本就不用Hashtable中的方法来对Properties类进行各种操作了, 那么Sun公司也就懒得修改这个错误了, 这里也可以总结一下, 虽然要知道Properties是    Hashtable<Object, Object>的子类, 但是在使用它时, 我们应该把它当作一个独立的类来使用; 
 
这个是我的个人总结, 其中有些是自己分析的, 有些问过别人, 总之就是我的个人理解及一些他人答案综合起来的, 如果有看到这个贴的, 我哪里理解错误的还望指出; 
  |