java基础之泛型

 

一.泛型知识

目录
• 定义
• 意义(即为什么要使用泛型)
• 作用及特点
• 原理
• 额外说明: List<String>能否转为List<Object>?
作用:
1. 使编译器可在编译期间对类型进行检查以提高类型安全,减少运行时由于对象类型不匹配引发的异常;
2. 运行时所有的转换都是强制、隐式的,大大提高了代码的重用率。 如对集合类取数据时,不需对存储的数据 进行强制类型转换。
原理:
基于 类型擦除。即 使用泛型时加上的类型参数,会在编译器在编译时去掉所以,在生成的 Java 字节码中,不包含泛型中的类型信息。这里需要特别说明是:
• Java中的泛型是在编译器层次实现,编译器在编译时尽可能的发现可能出错的地方,但仍无法避免在运行时刻出现类型转换异常的情况;
• 在代码中定义的List<object> 、List<String>等类型,在编译后都会变成List
• JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的
同时需要特别注意的是:
• 在无泛型的情况下,通常是使用Object类型来进行多种类型数据的操作,此时操作最多的是针对该Object进行数据的强制转换
• 而这种转换是基于开发者对该数据类型明确的情况下进行(如将Object型转换为String型);若类型不一致,编译器在编译过程中不会报错,但在运行时会出错
额外说明: List<String>能否转为List<Object>?不能。具体描述如下:
示意图

// 代码1和代码2相同
// 代码1
List<String> strings = new LinkedList<String>( );
List<Integer> ints = new LinkedList<Integer>( );
// 代码2
List strings = new LinkedList( );
List ints = new LinkedList( );

// 转换方式可以是如下:
List ss=strings;
List<Object> objects=ss;
至此,关于Java中的泛型讲解完毕。

定义:可理解为 适配广泛的类型,即参数化类型,可以把类型像方法的参数那样进行传递。
意义(即为什么要使用泛型)? 通过定义一种模板方式结构,从而保证类型安全 & 匹配。
// 以ArrayList示例。泛型T可以是任意类
public class ArrayList<T> {
private T[] array;
//...
}

// 通过泛型的使用,就可创建多种类型的ArrayList
// 1. 可存储String的ArrayList:
ArrayList<String> strList = new ArrayList<String>();
// 相当于
public class ArrayList<String> {
private String[] array;
//...
}
// 2. 可存储Float的ArrayList:

下面ArrayList示例作为说明。
1. 背景
ArrayList的本质:一个可变的Object类型数组
public class ArrayList {
private Object[] array;
// ...
}
2. 问题
在使用ArrayList存储不同类型时,需要强转类型,不然容易出现ClassCastException异常。如存储String类型:
// 获取到ArrayList里的Object类型时,必须强制转型为String // 不然容易出现ClassCastException异常
ArrayList list = new ArrayList();
list.add("carson ho");
String first = (String) list.get(0);
3. 解决方案
使用泛型将ArrayList变成一种模板:ArrayList<T>,就可以创建任意类型的ArrayList。即:
// 泛型T可以是任意类
public class ArrayList<T> {
private T[] array;
//...
}
// 多种类型
// 1. 可存储String的ArrayList:
ArrayList<String> strList = new ArrayList<String>();
// 相当于
public class ArrayList<String> {
private String[] array;
//...
}

 

二. 泛型:
1.自定义泛型类的使用,在声明时需要指定具体的类型,不能为基本类型;
2. 泛型接口/抽象类 的实现(泛型接口,将泛型定义在接口上 )
欲实现包含了泛型的接口或者抽象类有三种方式:
1.不使用泛型,而是默认Object
2.实现接口或父类时,将泛型确定
3.子类继承为泛型类,延迟到实现类时确定泛型
泛型接口(参考代码):
class Dog{
}
interface Inter<T>{
public abstract void show(T t);
}
class ImpClass1 implements Inter{
@Override
public void show(Object t) {
}
}
class ImpClass2 implements Inter<String>{
@Override
public void show(String t) {
}
}
class ImpClass3<T> implements Inter<T>{
@Override
public void show(T t) {
}
}
主函数:
public static void main(String[] args) {
ImpClass1 c1=new ImpClass1();
c1.show("abc");
c1.show(new Dog());
ImpClass2 c2=new ImpClass2();
c2.show("abc");
//c2.show(new Dog());
ImpClass3<Dog> c3=new ImpClass3<Dog>();
c3.show(new Dog());
}


泛型:
jdk1.5出现的安全机制。
好处:
1,将运行时期的问题ClassCastException转到了编译时期。
2,避免了强制转换的麻烦。
什么时候用?当操作的引用数据类型不确定的时候。就使用<>。将要操作的引用数据类型传入即可.
其实<>就是一个用于接收具体引用数据类型的参数范围。
在程序中,只要用到了带有<>的类或者接口,就要明确传入的具体引用数据类型 。
泛型技术是给编译器使用的技术,用于编译时期。确保了类型的安全。
运行时,会将泛型去掉,生成的class文件中是不带泛型的,这个称为泛型的擦除。
为什么擦除呢?因为为了兼容运行的类加载器。
泛型的补偿:在运行时,通过获取元素的类型进行转换动作。不用使用者在强制转换了。

泛型的通配符:? 未知类型。
泛型的限定:
? extends E: 接收E类型或者E的子类型对象。上限
一般存储对象的时候用。比如 添加元素 addAll.
? super E: 接收E类型或者E的父类型对象。下限。
一般取出对象的时候用。比如比较器。

泛型定义在方法上
public <w> void show(w str){
System.out.println("show:"+str.toString());
}

当方法静态时,不能访问类上定义的泛型,如果静态方法使用泛型,只能将泛型定义在方法上
public static <Y> void Method(Y obj){
System.out.println("method:"+obj);
}

public interface Person <T>{
//泛型不能用于全局变量前
/*public static final 编译时自动添加*/
/*public abstract 编译时自动添加*/
T compare(T t);
}

 

二. 泛型的总结

普通泛型

class Point< T>{  // 此处可以随便写标识符号,T是type的简称  
 private T var ; // var的类型由T指定,即:由外部指定  
 public T getVar(){ // 返回值的类型由外部决定  
  return var ;  
 }  
 public void setVar(T var){ // 设置的类型也由外部决定  
  this.var = var ;  
 }  
};  
public class GenericsDemo06{  
 public static void main(String args[]){  
  Point< String> p = new Point< String>() ; // 里面的var类型为String类型  
  p.setVar("it") ;  // 设置字符串  
  System.out.println(p.getVar().length()) ; // 取得字符串的长度  
 }  
};

class Notepad< K,V>{ // 此处指定了两个泛型类型 private K key ; // 此变量的类型由外部决定 private V value ; // 此变量的类型由外部决定 public K getKey(){ return this.key ; } public V getValue(){ return this.value ; } public void setKey(K key){ this.key = key ; } public void setValue(V value){ this.value = value ; } }; public class GenericsDemo09{ public static void main(String args[]){ Notepad< String,Integer> t = null ; // 定义两个泛型类型的对象 t = new Notepad< String,Integer>() ; // 里面的key为String,value为Integer t.setKey("汤姆") ; // 设置第一个内容 t.setValue(20) ; // 设置第二个内容 System.out.print("姓名;" + t.getKey()) ; // 取得信息 System.out.print(",年龄;" + t.getValue()) ; // 取得信息 } };

通配符

class Info< T>{  
 private T var ;  // 定义泛型变量  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public T getVar(){  
  return this.var ;  
 }  
 public String toString(){ // 直接打印  
  return this.var.toString() ;  
 }  
};  
public class GenericsDemo14{  
 public static void main(String args[]){  
  Info< String> i = new Info< String>() ;  // 使用String为泛型类型  
  i.setVar("it") ;       // 设置内容  
  fun(i) ;  
 }  
 public static void fun(Info< ?> temp){  // 可以接收任意的泛型对象  
  System.out.println("内容:" + temp) ;  
 }  
};

受限泛型

class Info< T>{  
 private T var ;  // 定义泛型变量  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public T getVar(){  
  return this.var ;  
 }  
 public String toString(){ // 直接打印  
  return this.var.toString() ;  
 }  
};  
public class GenericsDemo17{  
 public static void main(String args[]){  
  Info< Integer> i1 = new Info< Integer>() ;  // 声明Integer的泛型对象  
  Info< Float> i2 = new Info< Float>() ;   // 声明Float的泛型对象  
  i1.setVar(30) ;         // 设置整数,自动装箱  
  i2.setVar(30.1f) ;        // 设置小数,自动装箱  
  fun(i1) ;  
  fun(i2) ;  
 }  
 public static void fun(Info< ? extends Number> temp){ // 只能接收Number及其Number的子类  
  System.out.print(temp + "、") ;  
 }  
};
class Info< T>{  
 private T var ;  // 定义泛型变量  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public T getVar(){  
  return this.var ;  
 }  
 public String toString(){ // 直接打印  
  return this.var.toString() ;  
 }  
};  
public class GenericsDemo21{  
 public static void main(String args[]){  
  Info< String> i1 = new Info< String>() ;  // 声明String的泛型对象  
  Info< Object> i2 = new Info< Object>() ;  // 声明Object的泛型对象  
  i1.setVar("hello") ;  
  i2.setVar(new Object()) ;  
  fun(i1) ;  
  fun(i2) ;  
 }  
 public static void fun(Info< ? super String> temp){ // 只能接收String或Object类型的泛型  
  System.out.print(temp + "、") ;  
 }  
};

Java泛型无法向上转型

class Info< T>{  
 private T var ;  // 定义泛型变量  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public T getVar(){  
  return this.var ;  
 }  
 public String toString(){ // 直接打印  
  return this.var.toString() ;  
 }  
};  
public class GenericsDemo23{  
 public static void main(String args[]){  
  Info< String> i1 = new Info< String>() ;  // 泛型类型为String  
  Info< Object> i2 = null ;  
  i2 = i1 ;        //这句会出错 incompatible types  
 }  
};

Java泛型接口

interface Info< T>{  // 在接口上定义泛型  
 public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型  
}  
class InfoImpl< T> implements Info< T>{ // 定义泛型接口的子类  
 private T var ;    // 定义属性  
 public InfoImpl(T var){  // 通过构造方法设置属性内容  
  this.setVar(var) ;   
 }  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public T getVar(){  
  return this.var ;  
 }  
};  
public class GenericsDemo24{  
 public static void main(String arsg[]){  
  Info< String> i = null;  // 声明接口对象  
  i = new InfoImpl< String>("汤姆") ; // 通过子类实例化对象  
  System.out.println("内容:" + i.getVar()) ;  
 }  
};
interface Info< T>{  // 在接口上定义泛型  
 public T getVar() ; // 定义抽象方法,抽象方法的返回值就是泛型类型  
}  
class InfoImpl implements Info< String>{ // 定义泛型接口的子类  
 private String var ;    // 定义属性  
 public InfoImpl(String var){  // 通过构造方法设置属性内容  
  this.setVar(var) ;   
 }  
 public void setVar(String var){  
  this.var = var ;  
 }  
 public String getVar(){  
  return this.var ;  
 }  
};  
public class GenericsDemo25{  
 public static void main(String arsg[]){  
  Info i = null;  // 声明接口对象  
  i = new InfoImpl("汤姆") ; // 通过子类实例化对象  
  System.out.println("内容:" + i.getVar()) ;  
 }  
};

Java泛型方法

class Demo{  
 public < T> T fun(T t){   // 可以接收任意类型的数据  
  return t ;     // 直接把参数返回  
 }  
};  
public class GenericsDemo26{  
 public static void main(String args[]){  
  Demo d = new Demo() ; // 实例化Demo对象  
  String str = d.fun("汤姆") ; // 传递字符串  
  int i = d.fun(30) ;  // 传递数字,自动装箱  
  System.out.println(str) ; // 输出内容  
  System.out.println(i) ;  // 输出内容  
 }  
};

通过泛型方法返回泛型类型实例

class Info< T extends Number>{ // 指定上限,只能是数字类型  
 private T var ;  // 此类型由外部决定  
 public T getVar(){  
  return this.var ;   
 }  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public String toString(){  // 覆写Object类中的toString()方法  
  return this.var.toString() ;   
 }  
};  
public class GenericsDemo27{  
 public static void main(String args[]){  
  Info< Integer> i = fun(30) ;  
  System.out.println(i.getVar()) ;  
 }  
 public static < T extends Number> Info< T> fun(T param){//方法中传入或返回的泛型类型由调用方法时所设置的参数类型决定  
  Info< T> temp = new Info< T>() ;  // 根据传入的数据类型实例化Info  
  temp.setVar(param) ;  // 将传递的内容设置到Info对象的var属性之中  
  return temp ; // 返回实例化对象  
 }  
};

使用泛型统一传入的参数类型

class Info< T>{ // 指定上限,只能是数字类型  
 private T var ;  // 此类型由外部决定  
 public T getVar(){  
  return this.var ;   
 }  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public String toString(){  // 覆写Object类中的toString()方法  
  return this.var.toString() ;   
 }  
};  
public class GenericsDemo28{  
 public static void main(String args[]){  
  Info< String> i1 = new Info< String>() ;  
  Info< String> i2 = new Info< String>() ;  
  i1.setVar("HELLO") ;  // 设置内容  
  i2.setVar("汤姆") ;  // 设置内容  
  add(i1,i2) ;  
 }  
 public static < T> void add(Info< T> i1,Info< T> i2){  
  System.out.println(i1.getVar() + " " + i2.getVar()) ;  
 }  
};

Java泛型数组

public class GenericsDemo30{  
 public static void main(String args[]){  
  Integer i[] = fun1(1,2,3,4,5,6) ; // 返回泛型数组  
  fun2(i) ;  
 }  
 public static < T> T[] fun1(T...arg){ // 接收可变参数  
  return arg ;   // 返回泛型数组  
 }  
 public static < T> void fun2(T param[]){ // 输出  
  System.out.print("接收泛型数组:") ;  
  for(T t:param){  
   System.out.print(t + "、") ;  
  }  
 }  
};

Java泛型的嵌套设置

class Info< T,V>{  // 接收两个泛型类型  
 private T var ;  
 private V value ;  
 public Info(T var,V value){  
  this.setVar(var) ;  
  this.setValue(value) ;  
 }  
 public void setVar(T var){  
  this.var = var ;  
 }  
 public void setValue(V value){  
  this.value = value ;  
 }  
 public T getVar(){  
  return this.var ;  
 }  
 public V getValue(){  
  return this.value ;  
 }  
};  
class Demo< S>{  
 private S info ;  
 public Demo(S info){  
  this.setInfo(info) ;  
 }  
 public void setInfo(S info){  
  this.info = info ;  
 }  
 public S getInfo(){  
  return this.info ;  
 }  
};  
public class GenericsDemo31{  
 public static void main(String args[]){  
  Demo< Info< String,Integer>> d = null ;  // 将Info作为Demo的泛型类型  
  Info< String,Integer> i = null ; // Info指定两个泛型类型  
  i = new Info< String,Integer>("汤姆",30) ;  // 实例化Info对象  
  d = newDemo<Info<String,Integer>>(i);// 在Demo类中设置Info类的对象  System.out.println("内容一:"+ d.getInfo().getVar());System.out.println("内容二:"+ d.getInfo().getValue());}};
posted on 2022-03-20 13:27  左手指月  阅读(223)  评论(0编辑  收藏  举报