`
darrenzhu
  • 浏览: 806896 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Java泛型

    博客分类:
  • Java
阅读更多
2.1 Introduction
Java's generics implementation was based on a project originally called Pizza, which was done by Martin Odersky and others. Pizza was renamed GJ, then it turned into a JSR and ended up being adopted into the Java language. And this particular generics proposal had as a key design goal that it could run on an unmodified VM [Virtual Machine]. It is, of course, great that you don't have to modify your VM, but it also brings about a whole bunch of odd limitations. The limitations are not necessarily directly apparent, but you very quickly go, "Hmm, that's strange."

When you take an element out of a Collection, you must cast it to the type of element that is stored in the collection. Besides being inconvenient, this is unsafe. The compiler does not check that your cast is the same as the collection's type, so the cast can fail at run time.
Generics provide a way for you to communicate the type of a collection to the compiler, so that it can be checked. Once the compiler knows the element type of the collection, the compiler can check that you have used the collection consistently and can insert the correct casts on values being taken out of the collection.

List<T> pronounced List of T


2.2 Defining Simple generic




2.3 Java Generic Mechanism-Type Erasure
Generics are implemented by type erasure: generic type information is present only at compile time, after which it is erased by the compiler. The main advantage of this approach is that it provides total interoperability between generic code and legacy code that uses non-parameterized types (which are technically known as raw types). The main disadvantages are that parameter type information is not available at run time, and that automatically generated casts may fail when interoperating with ill-behaved legacy code. There is, however, a way to achieve guaranteed run-time type safety for generic collections even when interoperating with ill-behaved legacy code (reference to section Dynamic Type Safety).

Generic type parameter will be erased to its first bound.

e.g. 1
import java.util.ArrayList;

public class TestErasure1 {
public static void main(String[] args) throws InstantiationException,
IllegalAccessException {
Class<?> c1 = new ArrayList().getClass();
Class<?> c2 = new ArrayList<String>().getClass();
Class<?> c3 = new ArrayList<Integer>().getClass();
System.out.println(c1 == c2);
System.out.println(c1 == c3);
}

}
Output: true true
you can declare ArrayList.class, but you can not declare ArrayList<String>.class

e.g. 2
public class SimpleHolder {

    private Object obj;
   
public Object getObj() {
return obj;
}

public void setObj(Object obj) {
this.obj = obj;
}


public static void main(String[] args) {
           SimpleHolder holder=new SimpleHolder();
           holder.setObj("Item");
           String s=(String) holder.getObj();
}

}

public class GenericHolder<T> {
    private T obj;
   
public T getObj() {
return obj;
}

public void setObj(T obj) {
this.obj = obj;
}

public static void main(String[] args) {
GenericHolder<String> holder=new GenericHolder<String>();
holder.setObj("Item");
String s=holder.getObj();
}

}

Use
javap –c SimpleHolder>>SimpleHolder.txt
javap –c GenericHolder>>GenericHolder.txt

They have same generated byte codes, there is no necessary to do type check with set method, compiler will check it for you, but still necessary to do type cast with the returned value from get method. Actually compiler does the same thing for you when you don’t use generic instead of using Object.

Because of erasure, you can not do the following:

class Erasure<T>{
public void T(Object arg){
if(arg instanceof T){}         //error
T t=new T();                   //error
T[] array1=new T[10];          //error
T[] array2=(T[])new Object[10];//Unchecked warning
}
}

You can do this way?
class Building{}
class House extends Building{}

class ClassTypeCapture<T>{
Class<T> kind;
public ClassTypeCapture(Class<T> kind) throws InstantiationException, IllegalAccessException{
this.kind=kind;

}
public T getObject() throws InstantiationException, IllegalAccessException{
T temp=(T) kind.newInstance();
System.out.println("className of returned object:"+temp.getClass().getSimpleName());
return temp;
}
public boolean checkClassType(Object arg){
return kind.isInstance(arg);
}

public static void main(String[] args) throws InstantiationException,
IllegalAccessException {
       System.out.println("\n***********separator********************");
ClassTypeCapture<Building> ctc1=new ClassTypeCapture<Building>(Building.class);
       System.out.println(ctc1.checkClassType(new Building()));
       System.out.println(ctc1.checkClassType(new House()));
      
       ClassTypeCapture<House> ctc2=new
ClassTypeCapture<House>(House.class);
       System.out.println(ctc2.checkClassType(new Building()));
       System.out.println(ctc2.checkClassType(new House()));
      
       House temp=ctc2.getObject();
}
2.4 Subtype and Covariant
Are the following assignments valid?
class Building{}
class House extends Building{}

Building b=new Building();
House h = new House();
b=h;

Building[] arrayB=new Building[10];
House[] arrayH=new House[10];
arrayB=arrayH;

List<Building> lb=new ArrayList<Building>();
List<House> lh=new ArrayList<House>();
lb=lh;

In general, if Foo is a subtype (subclass or subinterface) of Bar, and G is some generic type declaration, it is not the case that G<Foo> is a subtype of G<Bar>.
2.5 Generic methods

2.6 Wildcards
2.6.1 Wildcards with an UpBound: <? Extend T> - get method
The syntax ? extend T denotes an unknown type that is a subtype of T
2.6.2 Wildcards with a LowerBound: <? Super T> - set method
The syntax ? super T denotes an unknown type that is a supertype of T, note T may have many supertypes(interfaces)
2.6.3 Unbounded wildcard: <?>
List<?> vs. List
After the compiler erasure, it seems List<?> and List are all erased to List<Object>, are they equal? no, there are different.
List<?>  is a non raw type which holds object from a special unknown type, the type is a reify type and we just don’t know right now,
List is a raw type list which holds objects from any types,

2.7 Self Bounded Type


2.8 Dynamic Type Safety
Java.util.Collectinos provide a group of static methods to support dynamic type safety:
checkedCollection(), checkedList(), checkedMap(), checkedSet(), checkedSortedMap(), checkedSortedSet()


2.9 Generics in C#, C++ and Java
How C# generics work?
In C# without generics, you are basically able to say class List {...}. In C# with generics, you can say class List<T> {...}, where T is the type parameter. Within List<T> you can use T as if it were a type. When it actually comes time to create a List object, you say List<int> or List<Customer>. You construct new types from that List<T>, and it is truly as if your type arguments get substituted for the type parameter. All of the Ts become ints or Customers, you don't have to downcast, and there is strong type checking everywhere.

In the CLR [Common Language Runtime], when you compile List<T>, or any other generic type, it compiles down to IL [Intermediate Language] and metadata just like any normal type. The IL and metadata contains additional information that knows there's a type parameter, of course, but in principle, a generic type compiles just the way that any other type would compile. At runtime, when your application makes its first reference to List<int>, the system looks to see if anyone already asked for List<int>. If not, it feeds into the JIT the IL and metadata for List<T> and the type argument int. The JITer, in the process of JITing the IL, also substitutes the type parameter.

It's exactly instantiating at runtime. It's producing native code specifically for that type at the point it is needed. And literally when you say List<int>, you will get a List of int. If the code in the generic type uses an array of T, that becomes an array of int.


Comparing C# and Java Generics
Bruce Eckel: How do C# generics compare with Java generics?
Anders Hejlsberg: Java's generics implementation was based on a project originally called Pizza, which was done by Martin Odersky and others. Pizza was renamed GJ, then it turned into a JSR and ended up being adopted into the Java language. And this particular generics proposal had as a key design goal that it could run on an unmodified VM [Virtual Machine]. It is, of course, great that you don't have to modify your VM, but it also brings about a whole bunch of odd limitations. The limitations are not necessarily directly apparent, but you very quickly go, "Hmm, that's strange."
For example, with Java generics, you don't actually get any of the execution efficiency that I talked about, because when you compile a generic class in Java, the compiler takes away the type parameter and substitutes Object everywhere. So the compiled image for List<T> is like a List where you use the type Object everywhere. Of course, if you now try to make a List<int>, you get boxing of all the ints. So there's a bunch of overhead there. Furthermore, to keep the VM happy, the compiler actually has to insert all of the type casts you didn't write. If it's a List of Object and you're trying to treat those Objects as Customers, at some point the Objects must be cast to Customers to keep the verifier happy. And really all they're doing in their implementation is automatically inserting those type casts for you. So you get the syntactic sugar, or some of it at least, but you don't get any of the execution efficiency. So that's issue number one I have with Java's solution.
Issue number two, and I think this is probably an even bigger issue, is that because Java's generics implementation relies on erasure of the type parameter, when you get to runtime, you don't actually have a faithful representation of what you had at compile time. When you apply reflection to a generic List in Java, you can't tell what the List is a List of. It's just a List. Because you've lost the type information, any type of dynamic code-generation scenario, or reflection-based scenario, simply doesn't work. If there's one trend that's pretty clear to me, it's that there's more and more of that. And it just doesn't work, because you've lost the type information. Whereas in our implementation, all of that information is available. You can use reflection to get the System.Type for object List<T>. You cannot actually create an instance of it yet, because you don't know what T is. But then you can use reflection to get the System.Type for int. You can then ask reflection to please put these two together and create a List<int>, and you get another System.Type for List<int>. So representationally, anything you can do at compile time you can also do at runtime.
Comparing C# Generics to C++ Templates
Bruce Eckel: How do C# generics compare with C++ templates?
Anders Hejlsberg: To me the best way to understand the distinction between C# generics and C++ templates is this: C# generics are really just like classes, except they have a type parameter. C++ templates are really just like macros, except they look like classes.
The big difference between C# generics and C++ templates shows up in when the type checking occurs and how the instantiation occurs. First of all, C# does the instantiation at runtime. C++ does it at compile time, or perhaps at link time. But regardless, the instantiation happens in C++ before the program runs. That's difference number one. Difference number two is C# does strong type checking when you compile the generic type. For an unconstrained type parameter, like List<T>, the only methods available on values of type T are those that are found on type Object, because those are the only methods we can generally guarantee will exist. So in C# generics, we guarantee that any operation you do on a type parameter will succeed.
C++ is the opposite. In C++, you can do anything you damn well please on a variable of a type parameter type. But then once you instantiate it, it may not work, and you'll get some cryptic error messages. For example, if you have a type parameter T, and variables x and y of type T, and you say x + y, well you had better have an operator+ defined for + of two Ts, or you'll get some cryptic error message. So in a sense, C++ templates are actually untyped, or loosely typed. Whereas C# generics are strongly typed.
分享到:
评论

相关推荐

    Java泛型的用法及T.class的获取过程解析

    Java泛型的用法及T.class的获取过程解析 Java泛型是Java编程语言中的一种重要特性,它允许开发者在编写代码时指定类型参数,从而提高代码的灵活性和可读性。本文将详细介绍Java泛型的用法 及T.class的获取过程解析...

    Java泛型三篇文章,让你彻底理解泛型(super ,extend等区别)

    Java 泛型详解 Java 泛型是 Java SE 5.0 中引入的一项特征,它允许程序员在编译时检查类型安全,从而减少了 runtime 错误的可能性。泛型的主要优点是可以Reusable Code,让程序员编写更加灵活和可维护的代码。 ...

    Java泛型应用实例

    Java泛型是Java编程语言中的一个强大特性,它允许我们在定义类、接口和方法时指定类型参数,从而实现代码的重用和类型安全。在Java泛型应用实例中,我们可以看到泛型如何帮助我们提高代码的灵活性和效率,减少运行时...

    很好的Java泛型的总结

    Java泛型机制详解 Java泛型是Java语言中的一种机制,用于在编译期检查类型安全。Java泛型的出现解决了Java早期版本中类型安全检查的缺陷。Java泛型的好处是可以在编译期检查类型安全,避免了运行时的...

    java 泛型类的类型识别示例

    综上所述,虽然Java泛型在编译后会进行类型擦除,但通过上述技巧,我们仍然能够在运行时获得关于泛型类实例化类型的一些信息。在实际开发中,这些方法可以帮助我们编写更加灵活和安全的代码。在示例文件`GenericRTTI...

    java泛型技术之发展

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

    SUN公司Java泛型编程文档

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着JDK 5.0的发布被引入。这个特性极大地提高了代码的类型安全性和可读性,减少了在运行时出现ClassCastException的可能性。SUN公司的Java泛型编程文档,包括...

    java 泛型接口示例

    下面我们将详细探讨Java泛型接口的相关知识点。 1. **泛型接口的定义** 泛型接口的定义方式与普通接口类似,只是在接口名之后添加了尖括号`&lt;T&gt;`,其中`T`是一个类型参数,代表某种未知的数据类型。例如: ```java...

    java 泛型方法使用示例

    下面我们将深入探讨Java泛型方法的概念、语法以及使用示例。 **一、泛型方法概念** 泛型方法是一种具有类型参数的方法,这些类型参数可以在方法声明时指定,并在方法体内部使用。与类的泛型类似,它们提供了编译时...

    Java 泛型擦除后的三种补救方法

    Java 泛型是一种强大的工具,它允许我们在编程时指定变量的类型,提供了编译时的类型安全。然而,Java 的泛型在运行时是被擦除的,这意味着在运行时刻,所有的泛型类型信息都会丢失,无法直接用来创建对象或进行类型...

    java泛型的内部原理及更深应用

    Java泛型是Java编程语言中的一个强大特性,它允许在定义类、接口和方法时使用类型参数,从而实现参数化类型。这使得代码更加安全、可读性更强,并且能够减少类型转换的必要。在“java泛型的内部原理及更深应用”这个...

    JAVA泛型加减乘除

    这是一个使用JAVA实现的泛型编程,分为两部分,第一部分创建泛型类,并实例化泛型对象,得出相加结果。 第二部分用户自行输入0--4,选择要进行的加减乘除运算或退出,再输入要进行运算的两个数,并返回运算结果及...

    java泛型学习ppt

    "Java 泛型学习" Java 泛型是 Java 语言的类型系统的一种扩展,以支持创建可以按类型进行参数化的类。泛型的主要目标是提高 Java 程序的类型安全。通过知道使用泛型定义的变量的类型限制,编译器可以在一个高得多的...

    Java泛型使用详细分析.pdf

    Java 泛型使用详细分析 Java 泛型是 Java 语言中的一种类型系统特性,允许开发者在编译期检查类型安全,以避免在运行时出现类型相关的错误。在本文中,我们将详细介绍 Java 泛型的使用方法和实现原理。 一、泛型的...

    Java泛型技术之发展.pdf

    Java泛型是Java编程语言中的一个关键特性,它在2004年随着Java SE 5.0的发布而引入,极大地增强了代码的类型安全性和重用性。本篇文章将深入探讨Java泛型的发展历程、核心概念以及其在实际开发中的应用。 1. **发展...

    Java泛型类型擦除后的补偿

    本文将深入探讨Java泛型类型擦除的概念,并介绍在类型擦除后,为了保持泛型的安全性和便利性,Java设计者所采取的一些补偿机制。 1. **类型擦除**: - 在编译期间,所有的泛型类型信息都会被替换为它们的实际类型...

Global site tag (gtag.js) - Google Analytics