java魔功心法-范型篇

前言:
https://www.cnblogs.com/LoveBB/p/17277662.html

什么是范型

JDK 1.5开始引入Java泛型(generics)这个特性,该特性提供了编译时类型安全检测机制,允许程序员在编译时检测到非法的类型。停,业余的客套话就不多说了,这些术语,讲了N遍,不管你看不看得懂,我的目的就是就要把你教懂,所以,这里不是重点。


泛型的作用

泛型有四个作用:类型安全、自动转换、性能提升、可复用性。即在编译的时候检查类型安全,将所有的强制转换都自动和隐式进行,同时提高代码的可复用性。实在不想说,但是不说又不行,生怕你们把路走偏了。


泛型的使用

  • 我们写代码,基本上就是:类、接口、方法。

泛型类

  • 先来来个3简单的类,平时的类动则几十上百行,现在我们化繁为简,就是为了让我们更清楚类的结构。
正经类
public class Student {    } 
public class Teacher {    } 
public class Room {    } 

有些人心里忍不住要喷了,这谁不会呀。嘿嘿,别着急,这想说的就是我们修炼的名门正派功法,这是很标准的"正派"写法。接下来,我将使用魔教功法进行魔改。


范型类结构
public class 类名 <泛型类型1,...> { // todo } 

范型类
  • 一个范型

简简单单

public class Student<T> {    } 
  • 两个范型

我好像在骂人,但是你没有证据吧

public class Student<S,B> { } 
  • 三个范型

这里注意,范型里面的 S, B, Q 都是自定义的,一般用大写字母表示,个数不限

public class Student<S, B, Q> { } 
  • N 个范型

嘿嘿,个数不限,那就来个不限的吧

public class Student<S, B, Q, V, N, F, D, A, U, I, O, P, L, H, J, K, G> { } 

  • 关于字母

有人说,字母就26个啊,你写重复的话,那不是一样了嘛。对,你是对的,但是魔教功法就在于,他不讲道理,谁说一定要使用大写字母了,下面来个逼死强迫症写法,什么叫无限火力,放飞自我。

public class Student<Sq, VIP, diss, QR, LKl, WOrd, Hao, Da, VPP, Ji, Ni, Tai, Mei, N, WoCao, D, CPDD, U, I, Love, Dog, OPHJKG, JiuK, HangZhou, WO, LAi, CoffEr, VCS> {    } 

怎么样,好好的一个类,经过魔教功法的改造,是不是看起来很不一样了。


  • 一般规定

虽然我们可以乱写,但是魔教功法还是有一套自己的体系,一般关于大写字母的定义如下

T:任意类型 type E:集合中元素的类型 element K:key-value形式 key V: key-value形式 value N: Number(数值类型) ?: 表示不确定的java类型 

对比
  • 为了加深记忆,我们前后再对比一下内容
// 改造前 public class Student {    }  // 改造后 public class Student<T> {    } 
实例化
  • 范型类应该怎么样实例化呢,请看下面正派写法
// 正经写法 Student student = new Student(); // 范型写法 Student<T> student = new Student<>();  // 案例1 Student<String> student = new Student<>(); // 案例2 Student<Integer> student = new Student<>(); // 案例3 Student<Teacher> student = new Student<>(); // 案例4:前面都没意思,来试试套娃吧,哈哈,走火入魔了没有,魔功就是魔功,这里要自己动手,才清晰明了 Student<Student<Student<Student<Student<String, Student<String, Long>>, Boolean>, Integer>, String>, Student<String, Integer>> student = new Student<>(); // 案例5:那个最长的,我实在懒得写了,后面全部用String代替了,这一套写下来,能不能唬住人。     Student<             String,             BigDecimal,             Integer,             Boolean,             Long,             Double,             Room,             Teacher,             String,             String,             String,             String,             String,             String,             String,             String,             String             > student = new Student<>(); 

咱就是说,用了魔教功法之后,我们 new 出来的对象,想传什么就传什么。有多少个范型参数,就传多少个对象进去。总之就一句话,很强,运用好了,绝对是秒天秒地秒空气。crud 之内,已然无敌。


泛型接口

看过范型类了,那接下来就是接口。有一说一,范型接口的使用率比范型类高出很多很多

正经接口
public interface Student {   // todo } 

范型接口结构
public interface 接口名<T> {   // todo } 
范型接口
  • 两个参数
public interface Student<T> {     // todo } 
  • 两个参数
public interface Student<S, B> {     // todo } 
  • 三个参数

停,就到这里吧,再写下去就不礼貌了,容易走火入魔。参数是和类一样的,可以N个,英文字母不限大小。


对比
// 改造前 public interface Student {     // todo }  // 改造后 public interface Student<T> {     // todo } 

  • 实例化

众所周知,接口只能用实现接口的方式来实例化,java8之后还能用函数式编程,这里就不展开来讲了

// 正经实现 public class GoodStudent implements Student{      }  // 范型实现 public class GoodStudent<T> implements Student<T>{      }  // 这里不用 T 可不可以呢,答案是可以的,只要子类和父类的范型一样就行 public class GoodStudent<B> implements Student<B>{  }  // 实战1 public class GoodStudent<String> implements Student<String>{  }  // 实战2 public class GoodStudent<Integer> implements Student<Integer>{  }  // 实战N,别忘记了我们还能套娃,还能无限火力N,这里就不演示了 

  • 那子类和父类的范型不一样呢,那就编译器报错呗

java魔功心法-范型篇


使用方式

那说了那么多,这个范型有什么用呢,答案是:接口、类声明中定义的类型形参则可以在整个接口、类中使用。

可以作为参数类型,入参,返回值使用

  • 范型使用
public class GoodStudent<T> implements Student<T>{     // 范型作为参数类型     private T personality; 		// 范型接口1,作为入参     public void evaluation(T t){              }   	// 范型接口2,作为入参和返回值     public T evaluation2(T t){         return t;     } } 
  • 案例参考(比较容易看懂)
// 实例化后很简单的,一看就懂,这就是我们正常的写法 public class GoodStudent<String> implements Student<String>{     // 范型参数     private String personality;      public void evaluation(String t){      }      public String evaluation2(String t){         return t;     }      }  // 案例2 public class GoodStudent<Integer> implements Student<Integer>{     // 范型参数     private Integer personality;      public void evaluation(Integer t){      }      public Integer evaluation2(Integer t){         return t;     }      }  
  • 实例化
    public static void main(String[] args) { 				// String 类型         GoodStudent<String> goodStudent = new GoodStudent<>();         String personality = "";         goodStudent.evaluation(personality);         String result = goodStudent.evaluation2(personality);        	// Integer 类型         GoodStudent<Integer> goodStudent = new GoodStudent<>();         Integer personality = "";         goodStudent.evaluation(personality);         Integer result = goodStudent.evaluation2(personality);             		// 套娃类型,我就套一层,不然容易走火入魔         GoodStudent<GoodStudent<String>> goodStudent = new GoodStudent<>();         GoodStudent<String> personality = new GoodStudent<>();         // 内层         String resultString = personality.evaluation2("");          goodStudent.evaluation(personality);         // 外层         GoodStudent<String>  result = goodStudent.evaluation2(personality);     } 

泛型方法

  • 介绍范型方法之前,我们先看看普通方法,我们经常写的方法就是这样
正经方法
// 无返回值,无入参 public void test(){      } // 无返回值,有入参 public void test(String s){      } // 有返回值,无入参 public String test(){     return ""; } // 有返回值,有入参 public String test(String s){     return s; } 

范型方法结构
// 范型方法就是加上一个范型声明 public <泛型类型> 返回类型 方法名(泛型类型 变量名) {    // todo } 

范型演示(注意和之前正常的对比)
// 无返回值,无入参(无意义) public <T> void test(){      } // 无返回值,有入参(不常用) public <T> void test(T s){      } // 有返回值,无入参(不太常用) public <T> T test(){     retrn null; } // 有返回值,有入参(经常用) public <T> T test(T s){     return s; } 

案例
  • 正经案例
public class GoodStudent implements Student {     // 无返回值,无入参     public void test() {      }      // 无返回值,有入参     public void test2(String s) {      }      // 有返回值,无入参     public String test3() {         return "";     }      // 有返回值,有入参     public String test4(String s) {         return s;     }  } 
  • 正经调用
public static void main(String[] args) {     GoodStudent goodStudent = new GoodStudent();     goodStudent.test();     String s = "";     goodStudent.test2(s);     String s1 = goodStudent.test3();     String s2 = goodStudent.test4(s); } 
  • 范型案例
public class GoodStudent implements Student {     // 无返回值,无入参(无意义)     public <T> void test(){      }     // 无返回值,有入参(不常用)     public <T> void test2(T s){      }     // 有返回值,无入参(不太常用)     public <T> T test3(){         return null;     }     // 有返回值,有入参(经常用)     public <T> T test4(T s){         return s;     } } 
  • 范型调用
public static void main(String[] args) {   	 // String 范型      GoodStudent goodStudent = new GoodStudent();      goodStudent.test();      String s = "";      goodStudent.test2(s);      String s1 = goodStudent.test3();      String s2 = goodStudent.test4(s);         // Integer 范型      GoodStudent goodStudent = new GoodStudent();      goodStudent.test();      Integer s = "";      goodStudent.test2(s);      Integer s1 = goodStudent.test3();      Integer s2 = goodStudent.test4(s);         // Student<String> 范型      GoodStudent goodStudent = new GoodStudent<>();      goodStudent.test();      Student<String> s = new GoodStudent<>();      goodStudent.test2(s);      Student<String> s1 = goodStudent.test3();      Student<String> s2 = goodStudent.test4(s);    } 

范型方法是传什么参数,就是什么返回值


泛型通配符(上下界)

你以为这就完了?下面才是绝杀。

Java泛型的通配符是用于解决泛型之间引用传递问题的特殊语法, 主要有以下三类:

  • 无边界的通配符,使用精确的参数类型
  • 关键字声明了类型的上界,表示参数化的类型可能是所指定的类型,或者是此类型的子类
  • 关键字声明了类型的下界,表示参数化的类型可能是指定的类型,或者是此类型的父类

无边界更多是服务于上界和下界的

// 表示类型参数可以是任何类型 public class B<?> { }   // 上界:表示类型参数必须是A或者是A的子类 public class B<T extends A> { }   // 下界:表示类型参数必须是A或者是A的超类型 public class B<T supers A> { } 
正常类
public class GoodStudent implements Student{     // String参数     private String personality; 		// String 作为入参     public void evaluation(String t){              }   	// String作为入参和返回值     public String evaluation2(String t){         return t;     } } 
  • 范型类
public class GoodStudent<T> implements Student<T>{     // 范型参数     private T personality; 		// 范型接口1,作为入参     public void evaluation(T t){              }   	// 范型接口2,作为入参和返回值     public T evaluation2(T t){         return t;     } } 
  • 下界范型
public class GoodStudent<T extends String> implements Student<T> {     // 范型参数     private T personality;     // 范型接口1,作为入参     public void evaluation(T t){      }     // 范型接口2,作为入参和返回值     public T evaluation2(T t){         return t;     } }  

到这里,我已经走火入魔了,后续的后面在写了,从这里我们也能看出,一个“正派”的类,经过”魔教“功法范型的改造之后,已经具备一定的复杂性了。这就是 魔功-范型 带来的威力。

// 改造前 public class GoodStudent implements Student{     // String参数     private String personality; 		// String 作为入参     public void evaluation(String t){              }   	// String作为入参和返回值     public String evaluation2(String t){         return t;     } }  // 改造后 public class GoodStudent<T extends String> implements Student<T> {     // 范型参数     private T personality;     // 范型接口1,作为入参     public void evaluation(T t){      }     // 范型接口2,作为入参和返回值     public T evaluation2(T t){         return t;     } }  

发表评论

相关文章

当前内容话题