List<Integer> ids = new continental gtArrayList<Integer>();最近ja

 上传我的文档
 下载
 收藏
该文档贡献者很忙,什么也没留下。
 下载此文档
正在努力加载中...
Predicate abstraction of Java programs with collections - OOPSLA面向对象程序设计.
下载积分:3800
内容提示:Predicate abstraction of Java programs with collections - OOPSLA面向对象程序设计系统语言及应用研究论文电子版下载
文档格式:PDF|
浏览次数:0|
上传日期: 07:03:54|
文档星级:
全文阅读已结束,如果下载本文需要使用
 3800 积分
下载此文档
该用户还上传了这些文档
Predicate abstraction of Java programs with collec
关注微信公众号今天看啥 热点:
为什么 Java ArrayList.toArray(T[]) 方法的参数类型是 T 而不是 E ?,arraylisttoarray前两天给同事做 code review,感觉自己对 Java 的 Generics 掌握得不够好,便拿出 《Effective Java》1 这本书再看看相关的章节。在 Item 24:Eliminate unchecked warnings 这一节中,作者拿 ArrayList 类中的 public &T& T[] toArray(T[] a) 方法作为例子来说明如何对变量使用 @SuppressWarnings annotation。
ArrayList 是一个 generic class,它是这样声明的:
public class ArrayList&E& extends AbstractList&E&
implements List&E&, RandomAccess, Cloneable, java.io.Serializable
这个类的 toArray(T[] a) 方法是一个 generic method,它是这样声明和实现的:
1: @SuppressWarnings("unchecked")
2: public &T& T[] toArray(T[] a) {
if (a.length & size)
// Make a new array of a's runtime type, but my contents:
return (T[]) Arrays.copyOf(elementData, size, a.getClass());
System.arraycopy(elementData, 0, a, 0, size);
if (a.length & size)
a[size] = null;
这个方法实际上是在 Collection 接口中声明的。因为我们经常通过 ArrayList 使用它,这里就用 ArrayList 作为例子了。
1 为什么声明为不同类型?
我的问题是:为什么这个方法使用类型 T,而不使用 ArrayList 的类型 E ? 也就是说,这个方法为什么不声明成这样:
public E[] toArray(E[] a);
如果类型相同的话,在编译期间就可以发现参数的类型错误。如果类型不同,很容易产生运行时错误。比如下面这段代码:
1: //创建一个类型为 String 的 ArrayList
2: List&String& strList = new ArrayList&String&();
3: strList.add("abc");
4: strList.add("xyz");
5: //将当前的 strList 转换成一个 Number 数组。注意,下面的语句没有任何编译错误。
6: Number[] numArray = strList.toArray(new Number[0]);
运行上面的代码, Line 6 会抛出 java.lang.ArrayStoreException 异常。
如果 toArray 方法使用类型 E 的话,语句2就会产生编译错误。编译错误怎么说也比运行时错误亲切啊。并且,generics 的主要目的就是为了类型安全,把类型转换错误(ClassCastException)消灭在编译期间。这个方法却反其道而行之。难道这是一个大 bug? Java 的 bug 俺碰上过,但这个地方出 bug 我还是不太敢相信。
上网一查,这个问题早已被讨论过多次了2, 3, 4。
2 可以提高灵活性
这样的声明更灵活,可以把当前 list 中的元素转换成一个更一般类型的数组。比如,当前 list 的类型是 Integer,我们可以把它的元素转换成一个 Number 数组。
1: List&Integer& intList = new ArrayList&Integer&();
2: intList.add(1);
3: intList.add(2);
4: Number[] numArray = intList.toArray(new Number[0]);
如果这个方法声明成类型 E,上面的代码就会有编译错误。 看起来,该方法声明成下面这样会更合适:
public &T super E& T[] toArray(T[] a);
不过, &T super E& 这样的语法在 Java 中是不存在的。而且即使存在,对数组也不起作用。也正是因为这个原因,在使用这个方法时,即使 T 是 E 的父类,或 T 跟 E 相同,也不能完全避免 java.lang.ArrayStoreException 异常5, 6, 7 。请看下面两段代码。第一段代码中 T 是 E 的父类,第二段代码中 T 和 E 一样。这两段代码都会抛出异常。
1: List&Integer& intList = new ArrayList&Integer&();
2: intList.add(1);
3: intList.add(2);
5: Float[] floatArray = new Float[2];
6: //Float 是 Number 的子类,所以 Float[] 是 Number[] 的子类
7: Number[] numArray = floatA
8: //下面的语句会抛出 ArrayStoreException 异常
9: numArray = intList.toArray(numArray);
1: List&Number& intList = new ArrayList&Number&();
2: //List 的类型是 Number。但 Number 是抽象类,只能存它的子类的实例
3: intList.add(new Integer(1));
4: intList.add(new Integer(2));
6: Float[] floatArray = new Float[2];
7: //Float 是 Number 的子类,所以 Float[] 是 Number[] 的子类
8: Number[] numArray = floatA
9: //下面的语句会抛出 ArrayStoreException 异常
10: numArray = intList.toArray(numArray);
上面的异常都是由这个事实造成的:如果 A 是 B 的父类,那么 A[] 是 B[] 的父类。Java 中所有的类都继承自 Object,Object[] 是所有数组的父类。
这个帖子8里举了个例子,说明即使这个方法的类型声明成 E 也不能避免 ArrayStoreException 异常。
该方法的文档中也提到了这个异常:
ArrayStoreException if the runtime type of the specified array is not a supertype of the runtime type of every element in this list.
3 可以与 Java 1.5 之前的版本兼容
这个方法在 Java 引入 Generics 之前(JDK1.5 中引入了 Generics)就出现了9。那时它被声明称这样:
public Object[] toArray(Object[] a)
Generics 出现后,许多类和方法就变成 generic 的了。这个方法也随大流声明成这样:
public &T& T[] toArray(T[] a)
这样声明可以与 Java 1.5 之前的版本兼容10。
4 多啰嗦两句
这个方法需要一个数组参数。如果这个数组的 length 大于或等于当前 list 的 size,list 中的元素就会存储到这个数组当中;如果这个数组的 length 小于当前 list 的 size,就会创建一个新的数组,并把当前 list 中的元素存入到这个新创建的数组中。为提高效率,如果可能,传入的数组的 length 要大于或等于 list 的 size,以避免该方法新建数组。
1: List&Integer& intList = new ArrayList&Integer&();
2: intList.add(1);
3: intList.add(2);
4: //传入一个数组,它的长度为 0
5: Number[] numArray1 = intList.toArray(new Number[0]); //语句1
6: //传入一个数组,它的长度与 intList 的长度相等
7: Number[] numArray2 = intList.toArray(new Number[intList.size()]); //语句2
另外,作为参数的数组不能为 null ,否则的话会抛出 NullPointerException 异常。
Emacs 24.5.1 (Org mode 8.2.10)
相关搜索:
相关阅读:
相关频道:
&&&&&&&&&&&&&&&&
Java编程最近更新Post Reply
Bookmark Topic
Saloon Keepers:
Bartenders:
Difference between List&String& list1 = new ArrayList(); and List&String& list2 = new ArrayList&Stri
Naresh Shanmugam
Ranch Hand
(1) List&& list1 = new ArrayList();
(2) List&String& list2 = new ArrayList&String&();
With both of these options it allows us to add only String into the list.
Is there any other difference between those two??
Is it okey if i just use List&String& list1 = new ArrayList();
What is real significance of List&String& list2 = new ArrayList&String&();
than List&String& list1 = new ArrayList();
Garik Ustinov
Ranch Hand
Yes, it is allowed to do it this way in order to achieve backward compatibility with previous
And no, you don't want to code like this.
Consider the following:
List objList = new ArrayList();
objList.add(new Object());
List&String& list = objL
The compiler would be happy to compile this, but guess what you get in List&String&? An object!
By declaring a Collection&String&, you want to be sure that you get only Strings in there, while a raw type collections allow you to add anything. One day after refactoring your new ArrayList() will be returned from a separate method. Maybe the next day someone will add something to it and who knows, maybe this something won't be a String...
SCJP, SCWCD
Naresh Shanmugam
Ranch Hand
With List&String& list1 = new ArrayList();
(1) We cant add anything other than "String"
(2) List&Object& list2 = list1 will lead to COMPILER error
Similarly with List&String& list2 = new ArrayList&String&();
(1) We cant add anything other than "String"
(2) List&Object& list2 = list2 will lead to COMPILER error
Then what is the difference between those two..
List&String& list1 = new ArrayList();
and List&String& list2 = new ArrayList&String&();
Can any one give explanation please
I am confused !!!
Garik please let your view about this...
Ernest Friedman-Hill
author and iconoclast
Posts: 24217
Honestly, there is no real difference, but the only reason the second version is allowed is to make it easier to compile code that uses generics with old code that does not.
It's just better style to include the &String& in both places.
Ram Chhabra
Sorry, but what i understood from the discussion is that, the code:
List&String& list = new ArrayList()
will work fine in JDK 1.4... ???
Manjusha Muraleedas
Ranch Hand
As of my knowledge,
List&String& list1 = new ArrayList();
will throw a compile time "Warning".
if you use the following ... it wont give the warning... List&String& list1 = new ArrayList&String&();
in boh cases compiler restrinct addition of objects other than those of 'String ' wll give a compilation error.
(I don't know whether any other tricky things hided behind this.mixing of generics to legecy code has always been tricky for me)
Naresh Shanmugam
Ranch Hand
Thanks Ernest.. I got the point now..
kishan Jaiswal
List&String& lst=new ArrayList()
difference with
List&String& lst=new ArrayList&String&()
How JVM internally handle this two.
Why generic are called compile time ?
Jesper de Jong
Java Cowboy
Posts: 16043
Hello Kishan, welcome to the Ranch.
ArrayList without the generics is called a raw type. Raw types exist in Java only because of backward compatibility. When a new version of Java comes out, Oracle is always extremely careful to make sure that code written for the previous version still works without changes on the new version.
In Java 5, generics were added to Java. But there was at that point already a lot of code written without generics, and it was very important that this continued to work. So it is still possible to write code without using generics.
not do this, however, when you write new code. It is only necessary for backward compatibility.
kishan Jaiswal wrote:Why generic are called compile time ?
When the Java compiler translates your source code to byte code, it uses the generics in your code to check if you didn't make any mistakes with the types (for example, putting the wrong kind of object in a List&String&). But the generics are not translated into byte code - the byte code that is produced contains no information about the generics that you used.
So, generics are only important at compile time (when the compiler is translating your code) and not at runtime (when the JVM is running your program).
kishan Jaiswal wrote:How JVM internally handle this two.
Therefore, there is no difference between these two at the JVM level - the byte code for both of these two lines is the same.
Note that since Java 7 you can write this:
List&String& lst = new ArrayList&&();
Notice the && on the right side. This is shortcut syntax, so that you don't have to repeat the &String& that you already wrote on the left side. So, this syntax is exactly the same as:
List&String& lst = new ArrayList&String&();
but just with a little shorter syntax.
kishan Jaiswal
List&String& lst =new ArrayList(String);
lst.add("Fruit");
lst.add("Cosmetic");
System.out.println(lst.get(0)); //how jvm know whether he has to get the string or any other type if the generic information get removed in bytecode
Campbell Ritchie
Posts: 56139
kishan Jaiswal wrote:. . . how jvm know whether he has to get the string or any other type if the generic information get removed in bytecode
I moved that question out of the code tags in yuor post as the line would otherwise be .
Now, let&s look at the bytecode, which you can do with javap:-$ javac RawTypeDemo.java
Note: RawTypeDemo.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
$ javap -c RawTypeDemo
Compiled from "RawTypeDemo.java"
class RawTypeDemo {
& RawTypeDemo();
&&&&&& 0: aload_0
&&&&&& 1: invokespecial #1&&&&&&&&&&&&&&&&& // Method java/lang/Object."&init&":()V
&&&&&& 4: return
& public void foo();
&&&&&& 0: new&&&&&&&&&& #2&&&&&&&&&&&&&&&&& // class java/util/ArrayList
&&&&&& 3: dup
&&&&&& 4: invokespecial #3&&&&&&&&&&&&&&&&& // Method java/util/ArrayList."&init&":()V
&&&&&& 7: astore_1
&&&&&& 8: aload_1
&&&&&& 9: ldc&&&&&&&&&& #4&&&&&&&&&&&&&&&&& // String Fruit
&&&&& 11: invokeinterface #5,& 2&&&&&&&&&&& // InterfaceMethod java/util/List.add:(Ljava/lang/O)Z
&&&&& 16: pop
&&&&& 17: aload_1
&&&&& 18: ldc&&&&&&&&&& #6&&&&&&&&&&&&&&&&& // String Cosmetic
&&&&& 20: invokeinterface #5,& 2&&&&&&&&&&& // InterfaceMethod java/util/List.add:(Ljava/lang/O)Z
&&&&& 25: pop
&&&&& 26: getstatic&&&& #7&&&&&&&&&&&&&&&&& // Field java/lang/System.out:Ljava/io/PrintS
&&&&& 29: aload_1
&&&&& 30: iconst_0
&&&&& 31: invokeinterface #8,& 2&&&&&&&&&&& // InterfaceMethod java/util/List.get:(I)Ljava/lang/O
&&&&& 36: checkcast&&&& #9&&&&&&&&&&&&&&&&& // class java/lang/String
&&&&& 39: invokevirtual #10&&&&&&&&&&&&&&&& // Method java/io/PrintStream.println:(Ljava/lang/S)V
&&&&& 42: return
$Note the raw type is shown as unsafe. Note the line starting 36: shows you are implicitly casting the contents to String. That is what happens when you have a List&String&: all its elements are implicitly cast to Strings, and that is how generics is implemented in the background. There is no record in the Class&RawTypeDemo& object of String anywhere, but the bytecode contains lines representing a cast to (String) on the List&s elements. That was using code very similar to what you posted.
Campbell Ritchie
Posts: 56139
import java.util.L
import java.util.ArrayL
class RawTypeDemo
&&& private void foo(String[] args)
&&&&&&& List&String& words = new ArrayList();
&&&&&&& for (String s : args)
&&&&&&&&&&& words.add(s);
&&&&&&& System.out.println(words);
&&&&&&& List numbers =
&&&&&&& numbers.add(Integer.valueOf(123));
&&&&&&& System.out.println(words.get(words.size() - 1));
&&& private RawTypeDemo()
&&&&&&& super();
&&& public static void main(String... args)
&&&&&&& new RawTypeDemo().foo(args);
}Now, you can assign your raw type to a plain simple List reference (line&14) and now you can add any type of Object to it. T you will get lots of compiler warnings especially if you write
javac -Xlint:unchecked RawTypeDemo.java
to get more details. Run this code with
java RawTypeDemo Kishan Jesper Campbell
or similar. I shall leave you to guess what will happen when you run line&16. I shall also leave you to explain why line 13 didn&t produce a printout on one of the occasions when I ran such code.
kishan Jaiswal
I execute the given code that you provide Campbell Ritchie and what I found is line 13 will simply print the words (of String type list) in a sop statement
and I understood that line 16 will definitely& produce an error because integer cant not be cast into the string.
Campbell Ritchie
Posts: 56139
Actually line&13 prints the List using its toString method, and it would be better to say that line&16 causes an exception to be thrown.
The problem with the raw type here is that it can be assigned to the wrong sort of reference and goodbye type‑safety.
Campbell Ritchie
Posts: 56139
The printing to System.out in line&13 and the exception message to System.err in line&16 may be printed by separate threads, and those threads may run at different speeds. If there is a delay in reaching System.out, the exception may be printed and the “main” th&read terminated before the System.out.println call is completed. So on one occasion I only saw the exception message, not the contents of the List.
Granny's Programming Pearls
"inside of every large program is a small program struggling to get out"
Post Reply
Bookmark Topic
Boost this thread!
Similar ThreadsConnecting to %s
Recent Posts
Categories

我要回帖

更多关于 gt 2000 newyork 5 的文章

 

随机推荐