论坛首页 Java企业应用论坛

关于JAVA 5可变参数

浏览 4949 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (2)
作者 正文
   发表时间:2011-12-15   最后修改:2011-12-15

最近在用Arrays的asList()生成的List时,List元素的个数时而不正确。

 

 

//经多次测试,只要传递的基本类型的数组,生成List的元素个数均为1
char arrc = {'a','b'};
int  arrint = {1,2,4};
Arrays.asList(arrc).size() ;//  结果为1;
Arrays.asList(arrint ).size() ;//结果为1;
 
//传递对象数组,元素个数正确。
String arrstr = {"a","b","java","spring","hadoop","lucene"};
Arrays.asList(arrstr ).size() ;//结果为6;

 

 

跟源码:

 

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

继续跟,Arrays的私有内部类ArrayList  (没搞明白,为什么这里也起名为ArrayList)

 

 

	private final E[] a;

	ArrayList(E[] array) {
            if (array==null)
                throw new NullPointerException();
	    a = array;
	}

	public int size() {
	    return a.length;
	}

 

发现问题出在java5 的可变参数上。于是写了demo,测试。

 

 

public class TestArray {
	PrintStream out = System.out;
	@Test
	public void array() {
		char[] arrc = {'a','b','c','d','e'};
		out.println("传递char数组:");
		print(arrc);
		out.println("直接传递:");
		print('a','b','c','d','e');
		out.println("----------------------------");
		
		int[] arri = {1,2,3,4,5,6,7};
		out.println("传递int数组:");
		print(arri);
		out.println("直接传递:");
		print(1,2,3,4,5,6,7);
		out.println("----------------------------");
		
		Integer[] arrInt = {1,2,3,4,5,6,7};
		out.println("传递Integer数组:");
		print(arrInt);
		out.println("直接传递:");
		print(1,2,3,4,5,6,7);
		out.println("----------------------------");
		
		String[] arrs = {"a","b","c","d","e"};
		out.println("传递String数组:");
		print(arrs);
		out.println("直接传递:");
		print('a','b','c','d','e');
		out.println("----------------------------");
	}
	
	public void print(Object...arr){
		out.print("内容:"+Arrays.toString(arr));
		out.println("\t\t数组长度:"+arr.length+" ");
	}
}

输出结果为:

传递char数组:
内容:[[C@defa1a]		数组长度:1 
直接传递:
内容:[a, b, c, d, e]		数组长度:5 
----------------------------
传递int数组:
内容:[[I@f5da06]		数组长度:1 
直接传递:
内容:[1, 2, 3, 4, 5, 6, 7]		数组长度:7 
----------------------------
传递Integer数组:
内容:[1, 2, 3, 4, 5, 6, 7]		数组长度:7 
直接传递:
内容:[1, 2, 3, 4, 5, 6, 7]		数组长度:7 
----------------------------
传递String数组:
内容:[a, b, c, d, e]		数组长度:5 
直接传递:
内容:[a, b, c, d, e]		数组长度:5 
----------------------------

java 5 可变参数,直接传递值与传递数组处理的机制不太相同。

 

如果直接传递数组,基本类型数组将被视为一个对象而不会被解析成数组,如果直接传递参数将能正常解析。因此传递基本类型数组时强烈建议转为其封装类对象的数组  int ->Integer ,long->Long …………。(未对其封装)


   发表时间:2011-12-15   最后修改:2011-12-15
    public static <T> List<T> asList(T... a) {
return new ArrayList<T>(a);
    }

说明T只可能是对象,若不是对象像基本类型可能会存在装箱的操作,看了你的测试我发现,对于基本类型的数组,java似乎不会进行自动装箱操作
1.传递char[] arrc = {'a','b'} Arrays.asList(arrc) 1 估计是把数组作一个对象直接传递过
2.传递 char a ='a',char b='b' Arrays.asList(a,b) 2 装箱后的传递

不知道对不对(可能自己表达能力有限)
0 请登录后投票
   发表时间:2011-12-19  
toArray() 这个函数必须只能传对象,就能看出来了
0 请登录后投票
   发表时间:2011-12-19   最后修改:2011-12-19
这样写就很清楚了吧
public static void main(String[] args) {
int[] intArray = {1,2,3};
List<int[]> myList = Arrays.asList(intArray);
System.out.println(myList.size());
System.out.println(myList.get(0).length);

}

数组被作为一个参数传递到函数中,而不是扩展为变参。楼主说到的对象类型数组确实效果不同,同求解释。

大概明白了:定义:   
public static <T> List<T> asList(T... a) {
	           return new ArrayList<T>(a);
                   }
这个T必须是对象类型。好比我们不能new ArrayList<int> 只能new ArrayList<Integer>
0 请登录后投票
   发表时间:2011-12-20   最后修改:2011-12-20
    public static <T> List<T> asList(T... a) {
	return new ArrayList<T>(a);
    }

如果是基本类型数组,自动装箱将数组包装为对象如 int[] intArray = new int[] { 1, 2}; T... a 就是 [[1, 2]],可以看到 a 的 size 将为 1
如果是对象数组,不需要自动装箱如 Integer[] integerArray = new Integer[] { 1, 2}; T... a 就是 [1, 2],可以看到 a 的 size 将为 2
0 请登录后投票
   发表时间:2011-12-23  
其实只要记住这句话就ok了:
基本类型的一位数组可以被当作Object类型使用(1.5),不能当做Object[]类型使用(1.4);非基本类型的一维数组,既可以当做Object类型使用(1.5)也可以当做Object[]类型使用(1.4)

jdk1.4   public static <T> List<T> asList(Object[] a)
jdk1.5   public static <T> List<T> asList(T... a)
按jdk1.5的语法,整个数组是一个参数,而jdk1.4的语法,数组中额度每个元素对应一个参数。
javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按照jdk1.4的语法进行处理,即把数组打撒成为若干个单独的参数。当jdk1.4不能处理时交由jdk1.5处理。
出现楼主的现象其实就是jdk1.4能够处理的范围。
看下数组与Object的关系:
int[] a1=new int[]{1,2,3};
int[] a2=new int[]{4};
int[][] a3=new int[2][3];
String [] a4=new String[]{"a","b","c"};
1、代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。即他们都能被jdk1.5处理。
//    getSuperclass
//    public Class<? super T> getSuperclass()返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的Class。如果此 Class 表示 Object 类、一个接口、一个基本类型或 void,则返回 null。如果此对象表示一个数组类,则返回表示该 Object 类的 Class 对象。
//    返回:
//    此对象所表示的类的超类。
System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a2.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a3.getClass().getSuperclass().getName());//java.lang.Object
System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object
Object obj1=a1;
Object obj2=a3;
Object obj3=a3;
Object obj4=a4;

2、基本类型的一位数组可以被当作Object类型使用(1.5),不能当做Object[]类型使用(1.4);非基本类型的一维数组,既可以当做Object类型使用(1.5)也可以当做Object[]类型使用(1.4)
//Object[] objs1=a1;//int的不是Object
//Object[] objs2=a2;
Object[] objs3=a3;//int[]是个Object对象
Object[] objs4=a4;//字符串数组里的字符串是Object,即Object数组里的Object
Object[] 与String[]没有父子关系,Object与String有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”};,Object x = “abc”能强制转换成String x = “abc”。


楼主测试代码修改下:
import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;

public class TestArray { 
    PrintStream out = System.out; 
    @Test
    public void array() { 
        char[] arrc = {'a','b','c','d','e'}; 
        out.println("传递char数组:"); 
       // print(arrc); //其实Object[] arr没有处理,他还是真正Object...arr处理的。所以你把print方法参数改为Object[] arr报错
        printtt(arrc);
        printObject(arrc);
        out.println();
        out.println("直接传递:"); 
        printtt('a','b','c','d','e'); 
        out.println("----------------------------"); 
         
        int[] arri = {1,2,3,4,5,6,7}; 
        out.println("传递int数组:"); 
        //print(arri);   //其实Object[] arr没有处理,他还是真正Object...arr处理的。所以你把print方法参数改为Object[] arr报错
        printtt(arri);
        printObject(arri);
        out.println();
        out.println("直接传递:"); 
        printtt(1,2,3,4,5,6,7); 
        out.println("----------------------------"); 
         
        Integer[] arrInt = {1,2,3,4,5,6,7}; 
        out.println("传递Integer数组:"); 
        print(arrInt);   //其实当作Object[] arr处理了
        printtt(arrInt);
        printObject(arrInt);
        out.println();
        out.println("直接传递:"); 
        printtt(1,2,3,4,5,6,7); 
        out.println("----------------------------"); 
         
        String[] arrs = {"a","b","c","d","e"}; 
        out.println("传递String数组:"); 
        print(arrs);   //其实当作Object[] arr处理了
        printtt(arrs);
        printObject(arrs);
        out.println();
        out.println("直接传递:"); 
        printtt('a','b','c','d','e'); 
        out.println("----------------------------"); 
    } 
     
    public void print(Object[] arr){ 
        out.print("内容:"+Arrays.toString(arr));  // public static String toString(Object[] a)
        out.println("\t\t数组长度:"+arr.length+" "); 
    }
    public void printtt(Object...arr){ 
        out.print("内容:"+Arrays.asList(arr)); 
        out.println("\t\t数组长度:"+arr.length+" ");  // public static <T> List<T> asList(T... a)
    }
    //用Array工具类用于完成对数组的反射操作,可以决绝上面所产生的问题
    public static void printObject(Object obj){
        Class cla=obj.getClass();
        if (cla.isArray()) {
           int len=Array.getLength(obj);
           for (int i = 0; i < len; i++) {
              System.out.print(Array.get(obj, i));
           }
         
        } else {
           System.out.println(obj);
        }
     }

0 请登录后投票
   发表时间:2011-12-23   最后修改:2011-12-23

其实只要记住这句话就ok了:

基本类型的一位数组可以被当作Object类型使用(1.5),不能当做Object[]类型使用(1.4);非基本类型的一维数组,既可以当做Object类型使用(1.5)也可以当做Object[]类型使用(1.4

 

jdk1.4   public static <T> List<T> asList(Object[] a)

jdk1.5   public static <T> List<T> asList(T... a)

jdk1.5的语法,整个数组是一个参数,而jdk1.4的语法,数组中额度每个元素对应一个参数。

javac会到底按照哪种语法进行处理呢?jdk1.5肯定要兼容jdk1.4的语法,会按照jdk1.4的语法进行处理,即把数组打撒成为若干个单独的参数。jdk1.4不能处理时交由jdk1.5处理。

出现楼主的现象其实就是jdk1.4能够处理的范围。

看下数组与Object的关系:

int[] a1=new int[]{1,2,3};

int[] a2=new int[]{4};

int[][] a3=new int[2][3];

String [] a4=new String[]{"a","b","c"};

1代表数组的Class实例对象的getSuperClass()方法返回的父类为Object类对应的Class。即他们都能被jdk1.5处理。

//    getSuperclass

//    public Class<? super T> getSuperclass()返回表示此 Class 所表示的实体(类、接口、基本类型或 void)的超类的Class。如果此 Class 表示 Object 类、一个接口、一个基本类型或 void,则返回 null。如果此对象表示一个数组类,则返回表示该 Object 类的 Class 对象。

//    返回:

//    此对象所表示的类的超类。

System.out.println(a1.getClass().getSuperclass().getName());//java.lang.Object

System.out.println(a2.getClass().getSuperclass().getName());//java.lang.Object

System.out.println(a3.getClass().getSuperclass().getName());//java.lang.Object

System.out.println(a4.getClass().getSuperclass().getName());//java.lang.Object

Object obj1=a1;

Object obj2=a3;

Object obj3=a3;

Object obj4=a4;

 

2基本类型的一位数组可以被当作Object类型使用(1.5),不能当做Object[]类型使用(1.4);非基本类型的一维数组,既可以当做Object类型使用(1.5)也可以当做Object[]类型使用(1.4

//Object[] objs1=a1;//int的不是Object

//Object[] objs2=a2;

Object[] objs3=a3;//int[]是个Object对象

Object[] objs4=a4;//字符串数组里的字符串是Object,即Object数组里的Object

Object[] String[]没有父子关系,ObjectString有父子关系,所以new Object[]{“aaa”,”bb”}不能强制转换成new String[]{“aaa”,”bb”};,Object x = “abc”能强制转换成String x = “abc”

 

楼主测试代码修改下:

 

import java.io.PrintStream;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;

import org.junit.Test;

public class TestArray {  
    PrintStream out = System.out;  
    @Test
    public void array() {  
        char[] arrc = {'a','b','c','d','e'};  
        out.println("传递char数组:");  
       // print(arrc); //其实Object[] arr没有处理,他还是真正Object...arr处理的。所以你把print方法参数改为Object[] arr报错
        printtt(arrc);
        printObject(arrc);
        out.println();
        out.println("直接传递:");  
        printtt('a','b','c','d','e');  
        out.println("----------------------------");  
          
        int[] arri = {1,2,3,4,5,6,7};  
        out.println("传递int数组:");  
        //print(arri);   //其实Object[] arr没有处理,他还是真正Object...arr处理的。所以你把print方法参数改为Object[] arr报错
        printtt(arri); 
        printObject(arri);
        out.println();
        out.println("直接传递:");  
        printtt(1,2,3,4,5,6,7);  
        out.println("----------------------------");  
          
        Integer[] arrInt = {1,2,3,4,5,6,7};  
        out.println("传递Integer数组:");  
        print(arrInt);   //其实当作Object[] arr处理了
        printtt(arrInt);
        printObject(arrInt);
        out.println();
        out.println("直接传递:");  
        printtt(1,2,3,4,5,6,7);  
        out.println("----------------------------");  
          
        String[] arrs = {"a","b","c","d","e"};  
        out.println("传递String数组:");  
        print(arrs);   //其实当作Object[] arr处理了
        printtt(arrs);
        printObject(arrs);
        out.println();
        out.println("直接传递:");  
        printtt('a','b','c','d','e');  
        out.println("----------------------------");  
    }  
      
    public void print(Object[] arr){  
        out.print("内容:"+Arrays.toString(arr));  // public static String toString(Object[] a)
        out.println("\t\t数组长度:"+arr.length+" ");  
    } 
    public void printtt(Object...arr){  
        out.print("内容:"+Arrays.asList(arr));  
        out.println("\t\t数组长度:"+arr.length+" ");  // public static <T> List<T> asList(T... a) 
    } 
    //用Array工具类用于完成对数组的反射操作,可以决绝上面所产生的问题
    public static void printObject(Object obj){
        Class cla=obj.getClass();
        if (cla.isArray()) {
           int len=Array.getLength(obj);
           for (int i = 0; i < len; i++) {
              System.out.print(Array.get(obj, i));
           }
          
        } else {
           System.out.println(obj);
        }
     }

}  
  

 

 

0 请登录后投票
   发表时间:2011-12-23  
分析的不错,楼上这个说的也挺好的
0 请登录后投票
   发表时间:2011-12-25  
基本类型的一位数组可以被当作Object类型使用(1.5),不能当做Object[]类型使用(1.4);非基本类型的一维数组,既可以当做Object类型使用(1.5)也可以当做Object[]类型使用(1.4);
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics