今天在用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值他們被當做了整體。
