本质是参数化类型
可以用在类,接口,方法的创建中
-
类——泛型类.note
public class GenericCla<T,P> {
public T method1(T t){
return t;
}
public P method2(P p){
return p;
}
public <P> P method3(){
return null;
}
}
-
接口——泛型接口.note
// 定义接口
public interface CalGenneric <T>{
T add(T a,T b);
T sub(T a,T b);
T mul(T a,T b);
T div(T a,T b);
}
// 实现接口
public class DoubleCalc<Double> implements CalGenneric<Double>{
@Override
public Double add(Double a, Double b) {
return null;
}
@Override
public Double sub(Double a, Double b) {
return null;
}
@Override
public Double mul(Double a, Double b) {
return null;
}
@Override
public Double div(Double a, Double b) {
return null;
}
}
-
方法——泛型方法.note
public class GenericMethod<K,V> {
/**
* 1、实体方法使用类上定义的泛型
* @param k
* @param v
* @return
*/
public K method1(K k,V v){
return null;
}
public <T> T method02(){ //2、方法上定义泛型
return null;
}
/**
* 静态方法中不能直接使用类上定义的泛型
* 静态方法中可以使用方法上定义的泛型
* @return
*/
// public static V method03(){
// return null;
// }
/**
* class new的时候才加载,所以静态方法中不能直接使用类上定义的泛型
* static 声明优先于类加载,所有需要先声明
*/
public static <P> P method04(){
return null;
}
}
先声明,再使用
泛型通配符
无界通配符 ? |
上界通配符 ? extends Number |
下界通配符 ? supper Inteher |
import java.util.ArrayList;
/**
* 泛型通配符:边界的问题
* 三种边界
* 无界:?<?>
* 上界: <? extends E>
* 下界: <? super E>
*
* 编译检查 保证类型的安全
* 避免强制转换的硬编码
* 增加调用代码的重用性
*/
public class BoderDemo {
/**
* 无界通配符的使用
*/
public void border01(ArrayList<?> arrayList){
for (int i=0;i<arrayList.size();i++){
System.out.println(arrayList.get(0));
}
}
/**
* 上界通配符的使用
* <? extends Object> 无界通配符
*/
public void border02(ArrayList<? extends Number> arrayList){
for (int i=0;i<arrayList.size();i++){
System.out.println(arrayList.get(0));
}
}
/**
* 下界通配符的使用
*/
public void border03(ArrayList<? super Number> arrayList){
for (int i=0;i<arrayList.size();i++){
System.out.println(arrayList.get(0));
}
}
public static void main(String[] args) {
BoderDemo boderDemo = new BoderDemo();
ArrayList<String> strList = new ArrayList<>();
ArrayList<Object> objList = new ArrayList<>();
ArrayList<Number> numberArrayList = new ArrayList<>();
ArrayList<Double> doubleArrayList = new ArrayList<>();
ArrayList<Integer> intArrayList = new ArrayList<>();
//无界
boderDemo.border01(strList);
boderDemo.border01(numberArrayList);
boderDemo.border01(intArrayList);
//上界
boderDemo.border02(numberArrayList);
boderDemo.border02(doubleArrayList);
// boderDemo.border02(strList); //泛型编译检查
//下界
boderDemo.border03(objList);
}
}
作用
编译检查 保证类型的安全 |
避免强制转换的硬编码 |
增加调用代码的重用性 |
编译检查
- 没有进行泛型约束的类
import java.io.File;
public class ArryListNoGeneric {
private Object[] elements= new Object[4];
private int size;
public Object get(int i){
if (size>i) return elements[i];
throw new IndexOutOfBoundsException();
}
public void add(Object c){
elements[size++]=c;
}
public static void main(String[] args) {
ArryListNoGeneric list = new ArryListNoGeneric();
list.add(1);
list.add("a");
list.add(new File("d:/nxjy"));
System.out.println(list.size);
String str = (String) list.get(2);
}
}
- 有泛型约束的类
import java.io.File;
public class ArryListHasGeneric<E> {
private Object[] elements= new Object[4];
private int size;
public Object get(int i){
if (size>i) return elements[i];
throw new IndexOutOfBoundsException();
}
public void add(E c){
elements[size++]=c;
}
public static void main(String[] args) {
ArryListHasGeneric<String> list = new ArryListHasGeneric<String>();
// list.add(1); // 类型检查
list.add("a");
// list.add(new File("d:/nxjy")); // 类型检查
System.out.println(list.size);
String str = (String) list.get(2);
}
}
避免强制转型类型
import java.util.ArrayList;
import java.util.List;
/**
* 1、保证类型安全,编译阶段类型检查
* 2、避免类型转换硬编码
* 3、调用代码重用性
*/
public class ArryListDemo {
public void hasGen(){
List<Integer> list = new ArrayList<>(); //1.7
list.add(123);
list.add(124);
System.out.println("---------------");
System.out.println(list.get(0).compareTo(list.get(1)));
}
public void noGen(){
List list = new ArrayList();
list.add(123);
list.add(124);
System.out.println("---------------");
System.out.println(((Integer) list.get(0)).compareTo((Integer)list.get(1)));
}
}
增加调用代码的重用性
import org.junit.Test;
import static org.junit.Assert.assertTrue;
public class Reuse<T extends Comparable>{
public Integer compaerTo(T t1,T t2){
return t1.compareTo(t2);
}
@Test
public void testComara(){
Reuse<Integer> reuse = new Reuse<>();
System.out.println(reuse.compaerTo(123,234)==0);
/**
* 相当于一个三目运算符,如果结果为false,打印提示语
*/
assertTrue("正常对比",reuse.compaerTo(123,234)==0);
Reuse<String> stringReuse = new Reuse<>();
Integer integer = stringReuse.compaerTo("!23", "234");
System.out.println(integer);
}
}
泛型的类型擦除
泛型只在编译阶段有效,泛型类型在逻辑上可看成是多个不同的类型,但是其实质都是同一个数据类型(Object)。
编译之后编译器会才去泛型化的措施。
- java中的泛型是假泛型
- 编译之后没有泛型
-
import org.junit.Test; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.List; /** * 泛型并不影响数据的基本类型 * 伪泛型,Java编译期间会将泛型擦除 */ public class GenType { @Test public void m01(){ List list = new ArrayList(); List<String> strList = new ArrayList<String>(); System.out.println(list.getClass()); System.out.println(strList.getClass()); System.out.println(list.getClass()==strList.getClass()); //true?false? } @Test public void method02() throws Exception { List<String> list = new ArrayList<>(); list.add("a"); list.add("b"); // list.add(1); //约束类型 System.out.println(list.size()); System.out.println("-------------------------"); /** * 泛型擦除 * 改变定于的泛型,诠释java的泛型是伪泛型,编译之后class会进行泛型的擦除 * 通俗来讲,就是泛型只在编译阶段起作用,生成class文件之后就不起作用 */ Class<? extends List> clazz = list.getClass(); Method m = clazz.getDeclaredMethod("add", Object.class); m.invoke(list,new Object()); System.out.println(list.size()); } }
堆污染
当一个可变泛型参数指向一个无泛型参数时,堆污染就有可能发生
-
案例1
import java.util.Set; import java.util.TreeSet; /** * 当一个可变泛型参数执行一个无泛型参数时,堆污染 */ public class Pollution { public static void main(String[] args) { Set set = new TreeSet(); set.add("addd"); set.add(100); System.out.println(set.size()); } }
- 案例2
import java.util.Set; import java.util.TreeSet; /** * 当一个可变泛型参数执行一个无泛型参数时,堆污染 */ public class Pollution { public static void main(String[] args) { Set<Object> set = new TreeSet(); set.add("addd"); set.add(100); System.out.println(set.size()); } }
- 案例3
import java.util.Set; import java.util.TreeSet; /** * 当一个可变泛型参数执行一个无泛型参数时,堆污染 */ public class Pollution { public static void main(String[] args) { Set set = new TreeSet(); set.add("addd"); varagMethod(set); } private static void varagMethod(Set<Integer> set) { System.out.println(set.size()); } }
- 案例4
import java.util.Set; import java.util.TreeSet; /** * 当一个可变泛型参数执行一个无泛型参数时,堆污染 */ public class Pollution { public static void main(String[] args) { Set set = new TreeSet(); varagMethod(set); } private static void varagMethod(Set<Integer> set) { set.add(new Integer(100)); System.out.println(set.size()); } }
- 案例5
import java.util.Set; import java.util.TreeSet; /** * 当一个可变泛型参数执行一个无泛型参数时,堆污染 */ public class Pollution { public static void main(String[] args) { Set set = new TreeSet(); set.add("addd"); varagMethod(set); } private static void varagMethod(Set<Integer> set) { System.out.println(set.size()); } }
- 案例6
import java.util.Set; import java.util.TreeSet; /** * 当一个可变泛型参数执行一个无泛型参数时,堆污染 */ public class Pollution { public static void main(String[] args) { Set set = new TreeSet(); set.add("addd"); varagMethod(set); } private static void varagMethod(Set<Integer> set) { set.add(new Integer(100)); System.out.println(set.size()); } }
桥接
1.5之后引入泛型后,为了使java的放心方法生成的字节码和1.5之前的字节码相兼容,编译器自动生成的方法叫做桥接
泛型接口
public interface SuperClass<T> {
T m01(T param);
}
类实现泛型接口
public class SubClass implements SuperClass<String>{
@Override
public String m01(String param) {
return param + "---";
}
}
测试
public class BridgeMethosTest {
public static void main(String[] args) {
SuperClass superClass = new SubClass();
System.out.println(superClass.m01("qwer"));
System.out.println(superClass.m01(new Object()));
}
}
javap命令看桥接的实现
javap -p -v SubClass.class
jdk1.5之后自动桥接适配,多加了一个类型为Object的m01方法。