zoukankan      html  css  js  c++  java
  • 由一个问题看JAVA面向对象思想(一)

    今天在用java写一个程序的时候,遇到了一个小问题。写出来,一起分享。 

    由于写的是一个简单的一段代码,并不打算长期使用,所以我用set的过滤能力,对一个较大的数组进行过滤,去掉重复的项,可是遇到了问题。

    出问题部分的主要代码:

    int n=cin.nextInt();
    int a[]=new int[n];
    for(int i=0;i<n;i++){ 
    a[i]=cin.nextInt();
    } Set set = new HashSet(Arrays.asList(a)); Iterator it=set.iterator(); while(it.hasNext()){ System.out.println(it.next()); }

    假设输入的为一段长度的数字:10 2 49 89 123 2 19 10 89

    当这样写的时候,总是出现输出:[I@1270b73 这显然是对象地址。。。

    下断点得到set集合的各种属性:

    查看器table映射情况:

    大家可以看到,作为初值15个位置,只映射了一个位置,本应映射更多位置的。

    其将数组当成一个对象,直接映射了:

     由此,我记得以前使用String[]数组的时候就没有出现这种情况,因此使用String[]将原程序改了,立刻就得到了相关的7个映射位置,实现了所需要的功能,当然中间多了些转换,然后回过头来看看这里到底发生了什么。

    为什么会出现这种情况?

    首先,想到的是String本身就被当做对象对待,而int被当做基本类型对待,这两个是有区别的。因此问题可能出现在这里。

    那么对于int来讲,他的包装类为Integer,更改一下,试一下。

    当将int a[]=new int[n];改为Integer a[]=new Integer[n];就好了:

    int n=cin.nextInt();
    Integer a[]=new Integer[n];
    for(int i=0;i<n;i++){ 
    a[i]=cin.nextInt();
    } 
    Set set = new HashSet(Arrays.asList(a));
    Iterator it=set.iterator();
    while(it.hasNext()){
     System.out.println(it.next());
    }
    

    再次下断点,查看相关属性:

     查阅文档:

    Arrays.asList()的文档:  

    asList

    public static <T> List<T> asList(T... a)
    Returns a fixed-size list backed by the specified array. (Changes to the returned list "write through" to the array.) This method acts as bridge between array-based and collection-based APIs, in combination with Collection.toArray. The returned list is serializable and implements RandomAccess.

    This method also provides a convenient way to create a fixed-size list initialized to contain several elements:

         List stooges = Arrays.asList("Larry", "Moe", "Curly"); 
    Parameters:
    a - the array by which the list will be backed.
    Returns:
    a list view of the specified array.
    See Also:
    Collection.toArray()

    并没有得到什么实质性有用的信息,只是了解了这个方法的一些特性。

    通过在工作空间中追源码得到:

    public static <T> List<T> asList(T... a) {
    return new ArrayList<T>(a);
    }

    我们看到这里定义了泛型,也就是说传进来的东西的对象类型被隐性接受。

     继续找ArrayList<T>(a)

        private static class ArrayList<E> extends AbstractList<E>
    	implements RandomAccess, java.io.Serializable
        {
            private static final long serialVersionUID = -2764017481108945198L;
    	private final E[] a;
    
    	ArrayList(E[] array) {
                if (array==null)
                    throw new NullPointerException();
    	    a = array;
    	}
    

    在此之前,我没认真看过这类的代码,泛型在这里起了作用,当你传入int[] a=new int[n];没注意都,int就进去了  

     

         由上,我们得知,数组的基础类型(int/Integer)通过我们调用asList方法的时候,已经进入到ArrayList之中,并返回给我们调用的左部。

         又基于Set set = new HashSet(Arrays.asList(a));我使用的是HashSet,那么HashSet在映射的时候,需要一个对象的hashcode,那么如果这个传入的类型不能够提供hashcode会怎么样呢?

    实验:

        在int a[]=new int[n];为数组下,我们都知道a[i]不能够调用.hashCode()方法,因为没有包装,没有这个方法。

        在Integer a[]=new Integer[n];为数组下,我们可以轻松调用.hashCode()方法,因为其为包装类,有该方法。

    那么我们就可以思考,为什么会出现那种情况了,因为java根据泛型接收的外部参数的类型,然后查看这个外部参数是否有.hashCode()方法,如果有则调用,用于映射(在内部机制中,我认为这里使用的接口,查看其是否实现了这类接口),如果没有这个方法(就像这个int基础类型),则追溯其传入参数的更大范围的对象(在这里是数组对象),这里将数组当成一个对象映射到桶中(如下图)。

         学校运动会放假,明天去华山旅游,所以这篇日志不能够接着写下去,赶紧睡觉,但是具体的意思已经表达出来了,下一篇文章会接着这个问题从实现方面思考,来对java面向对象带来的方便和麻烦作一个自己的思考总结。

    论证期间的一些思考和证明:

    int c=3;

    对于c这个基础类型是没有任何方法可以调用的,因为其不是对象。

    可是对于int a[]=new int[n];  Integer b[]=new Integer[n];

    a.clone();是可以执行的,而且查看列表,与b数组的方法是一样的。

    这是数组作为一种“容器”,所具有的方法和相关性质。

    所以可以认为int数组形式下,数组时被看做对象来处理的,而对象都有了方法。但是这两个不同类型数组的基类是不一致的。

    进一步探究》》

    对于不同的类型的数组:

    	  int n=cin.nextInt();
    	  int  a[]=new int [n];
    	  Integer b[]=new Integer[n];
    	    for(int i=0;i<n;i++){         
                 a[i]=cin.nextInt();
    	    }
    	    Set set = new HashSet(Arrays.asList(a));
    	    
            System.out.println("int型数组的类的名字:"+a.getClass().getName());
            System.out.println("Integer型数组的类的名字:"+b.getClass().getName());
    

        得到结果为:

    int型数组的类的名字:[I
    Integer型数组的类的名字:[Ljava.lang.Integer;

     这样可以看出这两个数组的基类是不同的,这样做似乎多余。但严格证明了这点。

    对于同样是基类的char进行一步测试:

     char c[]=new char[n];

    System.out.println("char型数组的类的名字:"+c.getClass().getName());

    方法同上,结果为:

    char型数组的类的名字:[C

    又出来一个[C

    可是即使一个类也好,传进去按照泛型,不至于说所有的方法都失效了啊。而且只要是基础类型进去后,length都变成了1。也就是说当成了单个对象进去了。

    动用调试:

    发现,在使用int[] a=new int[n];时候,查看set的hashmap的值只有单个不为null(hashmap初始为15,只映射了1个位置),

    同样测试Integer数组的时候,发现,set的hashmap的值全部被映射。

    得出结论:

    对于这两个被传进来的数组,由于类型不同,被用作不同的处理方式,int数组的整个数组被当做一个对象,进行映射,而Integer数组的每一个值均被当做一个对象用来映射。

    对于int值他们被当做了整体。

  • 相关阅读:
    七款HTML在线编辑器[下载]
    三层开发框架
    vs2005快捷键
    Javascript的IE和Firefox兼容性汇编
    序列化
    [Web2.0]web2.0中的tag及其技术实现
    结合FlyTreeView 无限级别的分类
    sql server中分布式查询随笔(链接服务器(sp_addlinkedserver)和远程登录映射(sp_addlinkedsrvlogin)使用小总结)
    FlyTreeView4.3.2.82 破解方法 (NineRays.Web.UI.WebControls.FlyTreeView)
    asp.net 获取cpu序列号 硬盘ID 网卡硬地址
  • 原文地址:https://www.cnblogs.com/zdcaolei/p/2433572.html
Copyright © 2011-2022 走看看