Generics Types 泛型学习笔记<二>

Generics Types 泛型学习笔记<>

作者:冰云
时间:2004-02-24
联系:icecloud(AT)sina.com
Bloghttp://icecloud.51.net

首先我要特别感谢Schlemiel,他指出了类型协变的问题。其实我以前也看到过gigix翻译的那篇文,但是没看懂也没经大脑。经Schlemiel一提醒,我才意识到,这是泛型的规范。再翻出来看,如醍醐灌顶,真良师益友也。

我写文章的目的,就是为了能够找到更多同好进行交流。没有交流,没有氛围,绝对不会有提高。谢谢Schlemiel,每次读他的文章或评论,都能受到很大的启发。

如果需要深入了解泛型,请阅读程序员杂志20037期,或

http://gigix.cool2u.net/download/Variance_in_Java.pdf

 

ok,继续上次的学习笔记。这篇22页的文章正好读了3天。每天从地铁东四十条到西直门,每次读7页。如果哪位晚上6:30-7:00间看到地铁上有个人拿着本电脑书在读,不妨上来问问是不是俺 ^___^||

另:后面文中每章出现了不少重点,我就按照和文中章节一样的标题。Notes则自己编号。

这次特地把字体变为14px,不知道各位看起来如何啊?会不会太大?

5 泛型方法(函数)

 

根据上一条,既然通配符类型是只读的,那么怎样才能在函数中写入呢?这就引入了泛型函数(Generic Mehtods):

 

 

    <T> static void fromArrayToCollection(T[] a, Collection<T> c) {

       for (T o : a){

           c.add(o); //correct

       }

    }  

    Collection<Object> co = new ArrayList<Object>;

    Collection<String> cs = new ArrayList<String>;

    fromArrayToCollection(new Integer[100], co); //correct

    fromArrayToCollection(new Number[100], cs); // error

 

 

    可以知道,不需要传递世纪参数到泛型方法,编译器会自行推断类型。

那么,什么时候使用泛型方法,什么时候使用通配符类型呢?可以这样理解:

 

Note 5: 可以采用泛型方法来保证读写操作的类型安全。泛型方法相当于原来的多态方法,它的效果是允许执行时选用不同的参数类型,而通配符方法相当于接受Object的方法。

文:This tells us that the type argument is being used for polymorphism; its only effect is to allow a variety of actual argument types to be used at different invocation sites.

考虑下面的方法,

      

       public static <T, S extends T> void copy (

              List <T> dest, List <S> src) ();

       public static <T> void copy (

              List <T> dest, List <? extends T> src) ();

 

 

    哪一个更清楚明了一点?因为S只用了一次,因此可以用通配符类型取代S。这样更简练。通配符类型的另一个好处是,他们可以用在方法外面,作为值域(fields)、本地变量(local variables)或数组的类型。如

 

      

       static List<List<? extends Shape>> history

              = new ArrayList<List<? extends Shape>>();

 

       public void drawAll(List<? extends Shape> shapes){

           history.addLast(shapes);

       }

 

 

说实话,我看到上面的变量定义简直想骂人。这个是定义了一个ListList,也就是history是保存List<? extends Shape>List

 

6 泛型与旧代码

在泛型代码中使用旧代码可能导致类型安全隐患。

 

      

    public interface Inventory {

       void setCats(Collection c);

       Collection getCats();

    }

    Collection<Cat> c = new ArrayList<Cat>();

    c.add(new BlackCat());

    Inventory.setCats(c);

    Collection<Cat> k = Inventory.getCats();

 

 

Note 6: 一般编译器无法知道Collection引用了何种类型,这样的没有带有类型的Collection称为row type。这样的类型表示一些未知类型,相当于Collection<?>

原文:The compiler has no way of knowing what kind of collection the type Collection refers to. It’s called a raw type. It’s more accurate to say that the type Collection denotes a collection of some unknown type like Collection<?>.

 

这种情况下,把Collection<?>赋值给Collection<Cat>是合法的,但是会出现一个unchecked warning,未检查警告。表示编译器无法保证它的正确性。因此使用旧代码时候请注意unchecked warning.

 

Note 7: 泛型编译时会被编译器进行一次称为erasure的过程。可以认为就是将泛型的代码转换为非泛型版本。最终的结果是:JVM不会检查类型安全和完整性,就算出现了unchecked warning也一样。Erasure会删除所有的泛型信息,如将List<String>转换为List,所有的类型变量被替换为最上限的,如Object。并且不管结果代码如何,都会增加类型转换。

原文:Generics are implemented by the Java compilers as a front-end conversion called ensure. It just like a source-to-source translation. As a result, the type safety and integrity of the JVM are never at risk, even in presence of unchecked warnings. Erasure throws out  all type information between angle brackets. For example, List<String> is converted into List. All remaining uses of type variables are replaced by the upper bound type variable (usually Object). And, whenever the resulting code isn’t type-correct, a cast to the appropriate type is inserted.

 

       在旧代码中使用泛型代码。与上面情况类似,会出现unchecked warning.

 

7 Fine Print 美好蓝图?(搞不懂作者的意图)

   

       泛型类被所有的它的子类共享。

 

             

    List<String> l1 = new ArrayList<String>();

    List<Integer> l2 = new ArrayList<Integer>();

    assert(l1.getClass()==l2.getClass()); // return true

 

 

Note 8: 所有的泛型类拥有相同的runtime类(其实从上面一条可以知道),并且,静态变量和方法也会在类的实例间共享。这就是为何在静态方法、变量或初始化中引用类型参数是非法的。

原文:All instances of generics class have the same run-time class. As consequence, the static variables and methods of a class are also shared among all the instances. That’s why it is illegal to refer to the type parameters of a type declaration in a static method or initializer, or in the declaration or initializer of a static variable.

 

    另一个隐含的事实,是无法判断一个类是否instanceof 其泛型类。或类型转换一个对象到一个泛型类型。

 

             

    Collection<String> cs = new ArrayList<String>;

    if (cs instanceof Collection<String>) {} //非法

    (Collection<String>) cs; // unchecked warning

   

    <T>T badCast(T t, Object o) {return (T)o};// unchecked warning

 

 

Note 9: 类型变量在运行时不存在!这意味着泛型不会占用时间或空间的性能,但不幸的是,你不能可靠的使用类型转换。

原文:type variables don’t exist at run time. This means that they entail no performance overhead in either time nor space. It also means that you can’t reliably use them in casts.

 

数组可能无法成为一个参数类型。除非是一个通配符类型。

 

             

    List<String> [] lsa = new List<String>[10]; // 不允许

                     = new List<?>[10]; // 允许

    Object o = isa;

    Object[] oa = (Object[])o;

    oa[1] = new ArrayList<Integer>();

    String s = lsa[1].get(); //允许的情况下,runtime error

 

 

可以声明类型变量的数组,但是不能初始化(new)建立一个新数组。如new T[100],因为类型变量运行时并不存在。

 

 

词汇表:

参数类型:parameterized type,形如:new ArrayList<?>new ArrayList<String>

类型变量:type variable,形如:<T> T getCollection()…

通配符类型:wildcard type,形如:new ArrayList<?>

有界通配符类型:bounded wildcard type,形如:new ArrayList<? extends Object>

原生类型:raw type,指在泛型代码中使用Collection, ArrayList等旧形式

未检查警告:unchecked warningJava1.5代码安全警告。

 

To be continue ...

      

 

版权声明:

本文由冰云完成,首发于CSDN,作者保留中文版权。

未经许可,不得使用于任何商业用途。

欢迎转载,但请保持文章及版权声明完整。

如需联络请发邮件:icecloud(AT)sina.com

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Java 泛型Generics)可以提供编译时类型安全检查以及运行时更强大的类型转换能力。它可以减少代码的编写量,提高代码的可读性和灵活性。使用泛型可以定义一个通用的方法,当传入不同的参数类型时,可以做出不同的动作,例如可以定义一个操作数组的简单方法,无论传入的是什么类型的参数,都能做出正确的操作。 ### 回答2: Java中的"<T>"是一种泛型的表示方式,它可以用于定义一个方法。使用泛型可以使方法在接受不同类型的参数时具有更好的复用性和扩展性。 泛型方法的定义需要在返回值类型之前加上"<T>",表示该方法可以接受类型为T的参数。例如,可以这样定义一个泛型方法: public <T> void printArray(T[] array) { for (T element : array) { System.out.println(element); } } 在这个示例中,方法名为printArray,它接受一个类型为T的数组作为参数,并遍历打印数组中的每个元素。这里的T可以是任何数据类型,例如Integer、String等。 在实际调用该方法时,需要传入与T对应的具体类型的数组。例如,可以这样调用该方法: Integer[] intArray = {1, 2, 3, 4, 5}; String[] stringArray = {"Hello", "World"}; printArray(intArray); printArray(stringArray); 通过使用泛型方法,可以在不同的场景中复用同一个方法,而不需要针对不同的数据类型编写多个重载的方法。这样可以提高代码的可维护性和重用性。 总之,Java中的"<T>"可以用于定义一个泛型方法,使方法能够接受不同类型的参数,在不同的场景中具有更好的复用性和扩展性。 ### 回答3: 在Java中,"<T>"是泛型的表示方式,用于定义一个可以接收任意类型的方法或者类。通过在方法或者类的声明中使用"<T>",我们可以在使用时指定具体的类型。 下面是一个示例,展示了如何使用"<T>"在Java中定义一个方法: ```java public class GenericMethod { // 使用泛型"<T>"定义一个方法,该方法可以接收任意类型的参数,并返回该参数 public static <T> T printValue(T value) { System.out.println(value); return value; } public static void main(String[] args) { // 调用printValue方法,并指定参数为整数类型 int intValue = GenericMethod.printValue(10); System.out.println("返回的整数值为:" + intValue); // 调用printValue方法,并指定参数为字符串类型 String stringValue = GenericMethod.printValue("Hello World"); System.out.println("返回的字符串值为:" + stringValue); // 调用printValue方法,并指定参数为自定义类型 MyClass myObject = new MyClass(); MyClass returnedObject = GenericMethod.printValue(myObject); System.out.println("返回的对象值为:" + returnedObject); } } // 定义一个自定义类 class MyClass { // 省略其他代码... } ``` 在上述代码中,我们定义了一个名为`printValue`的方法,使用"<T>"表示该方法可以接收任意类型的参数。在`printValue`方法内部,我们使用了`System.out.println`语句打印参数值,并返回了该值。 在`main`方法中,我们调用了`printValue`方法三次,每次传入不同的参数类型(整数、字符串和自定义类型),并打印了返回的值。 总的来说,通过在Java中使用"<T>"定义一个方法,我们可以实现通用的、可以接收任意类型参数的方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值