In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >
Share
Shulou(Shulou.com)06/01 Report--
This article mainly introduces what the knowledge points of Java generics have, the content is detailed and easy to understand, the operation is simple and fast, and it has a certain reference value. I believe you will gain something after reading this knowledge point of Java generics. Let's take a look.
1. What is generics? Why use generics?
Generics, or "parameterized types". When it comes to parameters, the most familiar thing is to have formal parameters when defining a method, and then pass arguments when you call this method. So how do you understand parameterized types? As the name implies, the type is parameterized by the original specific type, similar to the variable parameters in the method, and the type is also defined as a parameter (which can be called a type parameter). Then pass in the specific type (type argument) when using / calling.
The essence of generics is to parameterize types (the types of specific restrictions on formal parameters are controlled by different types specified by generics without creating new types). In other words, in the use of generics, the data type of the operation is specified as a parameter, which can be used in classes, interfaces, and methods, which are called generic classes, generic interfaces, and generic methods, respectively.
Before there are generics:
Private static void genericTest () {List arrayList = new ArrayList (); arrayList.add ("there are always unruly people trying to harm me"); arrayList.add (7); for (int I = 0; I
< arrayList.size(); i++) { Object item = arrayList.get(i); if (item instanceof String) { String str = (String) item; System.out.println("泛型测试 item = " + str); }else if (item instanceof Integer) { Integer inte = (Integer) item; System.out.println("泛型测试 item = " + inte); } }} 如上代码所示,在没有泛型之前 类型的检查 和 类型的强转 都必须由我们程序员自己负责,一旦我们犯了错,就是一个运行时崩溃等着我们。 有了泛型之后: private static void genericTest2() { List arrayList = new ArrayList(); arrayList.add("总有刁民想害朕"); arrayList.add(7); //..(参数不匹配:int 无法转换为String) ... } 如上代码,编译器在编译时期即可完成 类型检查 工作,并提出错误(其实IDE在代码编辑过程中已经报红了) 二、泛型的特性是什么? 大家都知道,Java的泛型是伪泛型,这是因为Java在编译期间,所有的泛型信息都会被擦掉,正确理解泛型概念的首要前提是理解类型擦除。Java的泛型基本上都是在编译器这个层次上实现的,在生成的字节码中是不包含泛型中的类型信息的,使用泛型的时候加上类型参数,在编译器编译的时候会去掉,这个过程成为类型擦除。 如在代码中定义List和List等类型,在编译后都会变成List,JVM看到的只是List,而由泛型附加的类型信息对JVM是看不到的。Java编译器会在编译时尽可能的发现可能出错的地方,但是仍然无法在运行时刻出现的类型转换异常的情况,类型擦除也是Java的泛型与++模板机制实现方式之间的重要区别。 什么是类型擦除? 类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。 类型擦除可以简单的理解为将泛型java代码转换为普通java代码,只不过编译器更直接点,将泛型java代码直接转换成普通java字节码。 类型擦除的主要过程如下: 1.将所有的泛型参数用其最左边界(最顶级的父类型)类型替换。 2.移除所有的类型参数。 通过两个例子来理解泛型的类型擦除。 例一: public class Test { public static void main(String[] args) { ArrayList list1 = new ArrayList(); list1.add("abc"); ArrayList list2 = new ArrayList(); list2.add(123); System.out.println(list1.getClass() == list2.getClass()); } } 在这个例子中,我们定义了两个ArrayList数组,不过一个是ArrayList泛型类型的,只能存储字符串;一个是ArrayList泛型类型的,只能存储整数,最后,我们通过list1对象和list2对象的getClass()方法获取他们的类的信息,最后发现结果为true。说明泛型类型String和Integer都被擦除掉了,只剩下原始类型。 例二:通过反射添加其它类型元素 public class Test { public static void main(String[] args) throws Exception { ArrayList list = new ArrayList(); list.add(1); //这样调用 add 方法只能存储整形,因为泛型类型的实例为 Integer list.getClass().getMethod("add", Object.class).invoke(list, "asd"); for (int i = 0; i < list.size(); i++) { System.out.println(list.get(i)); } } } 在程序中定义了一个ArrayList泛型类型实例化为Integer对象,如果直接调用add()方法,那么只能存储整数数据,不过当我们利用反射调用add()方法的时候,却可以存储字符串,这说明了Integer泛型实例在编译之后被擦除掉了,只保留了原始类型。 类型擦除后保留的原始类型,那么什么是原始类型呢? 原始类型 就是擦除去了泛型信息,最后在字节码中的类型变量的真正类型,无论何时定义一个泛型,相应的原始类型都会被自动提供,类型变量擦除,并使用其限定类型(无限定的变量用Object)替换。 例三:原始类型Object class Pair { private T value; public T getValue() { return value; } public void setValue(T value) { this.value = value; } } Pair的原始类型为: class Pair { private Object value; public Object getValue() { return value; } public void setValue(Object value) { this.value = value; } } 因为在Pair中,T 是一个无限定的类型变量,所以用Object替换,其结果就是一个普通的类,如同泛型加入Java语言之前的已经实现的样子。在程序中可以包含不同类型的Pair,如Pair或Pair,但是擦除类型后他们的就成为原始的Pair类型了,原始类型都是Object。 从上面的例2中,我们也可以明白ArrayList被擦除类型后,原始类型也变为Object,所以通过反射我们就可以存储字符串了。 如果类型变量有限定,那么原始类型就用第一个边界的类型变量类替换。 比如: Pair这样声明的话: public class Pair {} 那么原始类型就是Comparable。 要区分原始类型和泛型变量的类型。 在调用泛型方法时,可以指定泛型,也可以不指定泛型。 在不指定泛型的情况下,泛型变量的类型为该方法中的几种类型的同一父类的最小级,直到Object 在指定泛型的情况下,该方法的几种类型必须是该泛型的实例的类型或者其子类 public class Test { public static void main(String[] args) { /**不指定泛型的时候*/ int i = Test.add(1, 2); //这两个参数都是Integer,所以T为Integer类型 Number f = Test.add(1, 1.2); //这两个参数一个是Integer,以风格是Float,所以取同一父类的最小级,为Number Object o = Test.add(1, "asd"); //这两个参数一个是Integer,以风格是Float,所以取同一父类的最小级,为Object /**指定泛型的时候*/ int a = Test.add(1, 2); //指定了Integer,所以只能为Integer类型或者其子类 int b = Test.add(1, 2.2); //编译错误,指定了Integer,不能为Float Number c = Test.add(1, 2.2); //指定为Number,所以可以为Integer和Float } //这是一个简单的泛型方法 public static T add(T x,T y){ return y; } } 其实在泛型类中,不指定泛型的时候,也差不多,只不过这个时候的泛型为Object,就比如ArrayList中,如果不指定泛型,那么这个ArrayList可以存储任意的对象。 三、泛型的使用方式 泛型一般有三种使用方式:泛型类、泛型接口、泛型方法。 1.泛型类就是把泛型定义在类上,用户使用该类的时候,才把类型明确下来 这样的话,用户明确了什么类型,该类就代表着什么类型…用户在使用的时候就不用担心强转的问题,运行时转换异常的问题了。 /** * Java泛型 */public class Demo { public static void main(String[] args) { // 定义泛型类 Test 的一个Integer版本 Test intOb = new Test(88); intOb.showType(); int i = intOb.getOb(); System.out.println("value= " + i); System.out.println("----------------------------------"); // 定义泛型类Test的一个String版本 Test strOb = new Test("Hello Gen!"); strOb.showType(); String s = strOb.getOb(); System.out.println("value= " + s); }}/*使用T代表类型,无论何时都没有比这更具体的类型来区分它。如果有多个类型参数,我们可能使用字母表中T的临近的字母,比如S。*/class Test { private T ob; /* 定义泛型成员变量,定义完类型参数后,可以在定义位置之后的方法的任意地方使用类型参数,就像使用普通的类型一样。 注意,父类定义的类型参数不能被子类继承。 */ //构造函数 public Test(T ob) { this.ob = ob; } //getter 方法 public T getOb() { return ob; } //setter 方法 public void setOb(T ob) { this.ob = ob; } public void showType() { System.out.println("T的实际类型是: " + ob.getClass().getName()); }} /* output T的实际类型是: java.lang.Integer value= 88 ---------------------------------- T的实际类型是: java.lang.String value= Hello Gen!*/ 2.泛型接口 public interface Generator { public T method();} 实现泛型接口,不指定类型: class GeneratorImpl implements Generator{ @Override public T method() { return null; }} 实现泛型接口,指定类型: class GeneratorImpl implements Generator{ @Override public String method() { return "hello"; }} 泛型方法:判断一个方法是否是泛型方法关键看方法返回值前面有没有使用 标记的类型,有就是,没有就不是 public class Normal { // 成员泛型方法 public String getString(E e) { return e.toString(); } // 静态泛型方法 public static void printString(V v) { System.out.println(v.toString()); } } // 泛型类中的泛型方法 public class Generics { // 成员泛型方法 public String getString(E e) { return e.toString(); } // 静态泛型方法 public static void printString(V v) { System.out.println(v.toString()); } }四、Java中的泛型通配符 常用的 T,E,K,V,? 本质上这些个都是通配符,没啥区别,只不过是编码时的一种约定俗成的东西。比如上述代码中的 T ,我们可以换成 A-Z 之间的任何一个 字母都可以,并不会影响程序的正常运行,但是如果换成其他的字母代替 T ,在可读性上可能会弱一些。通常情况下,T,E,K,V,? 是这样约定的: ? 表示不确定的 java 类型 T (type) 表示具体的一个java类型 K V (key value) 分别代表java键值中的Key Value E (element) 代表Element ? 无界通配符: 我有一个父类 Animal 和几个子类,如狗、猫等,现在我需要一个动物的列表,我的第一个想法是像这样的: List listAnimals 但是老板的想法确实这样的: List ),表示可以持有任何类型。像 countLegs 方法中,限定了上届,但是不关心具体类型是什么,所以对于传入的 Animal 的所有子类都可以支持,并且不会报错。而 countLegs1 就不行。 上界通配符 < ? extends E>:
Previous: declared with the extends keyword, indicating that the parameterized type may be the specified type or a subclass of this type.
Using extends in type parameters means that the parameters in this generic type must be E or a subclass of E, which has two advantages:
If the type passed in is not E or a subclass of E, you can use the method of E in the compilation of unsuccessful generics, otherwise you have to convert it to E before you can use it.
Lower bound wildcard
< ? super E>:
Lower bound: declared with super, indicating that the parameterized type may be the specified type or the parent of this type until Object
This is the end of this article on "what are the knowledge points of Java generics?" Thank you for reading! I believe you all have a certain understanding of "what are the knowledge points of Java generics". If you want to learn more knowledge, you are welcome to follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.