####引入
关于泛型这篇博客讲的还可以:
http://blog.csdn.net/old_memories/article/details/78079422
还有:
《泛型超详细解读(一):泛型基础》http://blog.csdn.net/jeffleo/article/details/52245870
《 泛型超详细解读(二):super和extend》http://blog.csdn.net/jeffleo/article/details/52250948
《Java中的泛型方法》这篇写的还行https://www.cnblogs.com/iyangyuan/archive/2013/04/09/3011274.html
/**
* Object 可以接受任意类型,因为发生多态
一个学生的成绩有三种情况:整数,小数,字符串。。一开始无法确定,所以只能用Object接收。
* @author Administrator
*/
public class Student {
private Object javase;
private Object oracle;
public Student() {
}
public Student(Object javase, Object oracle) {
super();//父类不止一个构造函数时,显示的调用super才有意义
//子类会默认调用父类的构造函数,这时候显示的调用没什么意义
this.javase = javase;
this.oracle = oracle;
}
public Object getJavase() {
return javase;
}
public void setJavase(Object javase) {
this.javase = javase;
}
public Object getOracle() {
return oracle;
}
public void setOracle(Object oracle) {
this.oracle = oracle;
}
}
/**
* 获取值:
* 1、强制类型转换
* 2、手动类型检查:避免转换错误 java.lang.ClassCastException:这是个运行时异常
* @author Administrator
*/
public class App {
/**
* @param args
*/
public static void main(String[] args) {
Object obj = 80;
//int score =(int)obj; //jdk1.7以后 Object -->integer -->自动拆箱
int score=(Integer)obj; //jdk1.6只能这么写
System.out.println(score);
//(自动装箱,int->integer 再发生多态转成Object)
//存入整数 int -->Integer -->Object
Student stu = new Student(80,90);
//()stu.getJavase(); 可以转,就像上面Object -->integer -->自动拆箱那样
int javaseScore =(Integer)stu.getJavase();
String oracleScore =null ;
if(stu.getOracle() instanceof String){
oracleScore =(String)stu.getOracle();
}
System.out.println("分数为:"+javaseScore+","+oracleScore);
}
}
####举例
注意是:编译的时候检查类型。
也就意味着,运行期间泛型就不起作用了,所以可以用反射来绕过泛型。
1、泛型类:
先看看泛型类:
约定俗称就用图上几个字母。。
/**
* 泛型类:声明时使用泛型
* 字母:
* T Type 表示类型。
K V 分别代表键值中的Key Value。
E 代表Element。
使用时确定类型
注意:
1、泛型只能使用引用类型,不能基本类型。。
2、泛型声明时,字母不能使用在静态属性|静态方法上。。。
* @author Administrator
*
* @param <T>
*/
public class Student<T1,T2> {
private T1 javaScore;
private T2 oracleScore;
//泛型声明时,字母不能使用在 静态属性|静态方法上
//因为是在使用的时候确定的,静态的则是在编译的时候确定
//private static T1 test; -- 这样是不对的
public T1 getJavaScore() {
return javaScore;
}
public void setJavaScore(T1 javaScore) {
this.javaScore = javaScore;
}
public T2 getOracleScore() {
return oracleScore;
}
public void setOracleScore(T2 oracleScore) {
this.oracleScore = oracleScore;
}
/**
* @param args
*/
public static void main(String[] args) {
//使用时指定类型(引用类型) 《只能用integer,不能用int》
Student<String,Integer> stu = new Student<String,Integer> ();
//1、安全:类型检查。因为这个时候set就只能是字符串了,否则编译报错。它帮你类型检查了。。
stu.setJavaScore("优秀");
//2、省心:类型转换。因为,有自动拆箱,和多态。不用你object到integer,再到int了。它一步到位。
int it =stu.getOracleScore(); //integer -->自动拆箱
}
}
再看看泛型接口:
/**
* 接口中 泛型字母只能使用在方法中,不能使用在全局常量中,因为接口的全局常量是static声明的
*/
public interface Comparator<T> {
//T a = 2; //这种就是错误的,因为接口的变量都是static的。
void compare(T t);
}
再看看泛型方法:
import java.io.Closeable;
import java.io.IOException;
/**
* 泛型方法 <> 是在返回类型前面,类型在使用的时候确定
* 只能访问对象的信息,不能修改信息,因为类型没定。。比如不能执行a.setXX()方法
* @author Administrator
*
*/
public class TestMethod {
/**
* @param args
*/
public static void main(String[] args) {
test("a"); //T -->String //类型在使用的时候确定
}
//泛型方法
public static <T> void test(T a){ ---- 修饰符后面,返回值前面。
//不能执行a.setXX()方法 因为a的类型没定
System.out.println(a);
}
// extends <=(相当于继承) 这里表示T只能是Closeable接口的实现类
//... 三个点表示可变参数
//注意,返回值不是T啊,返回值定死了就是void。 泛型表示的是 参数化类型,表示传入的参数的不确定性。。
//但是返回值也可以指定成泛型,<T> T test(T t){}
public static <T extends Closeable> void test(T... a){
for(T temp:a){
try {
if(null!=temp){
//只能访问对象的信息,不能修改信息
//close或者打印都可以,但不能修改
temp.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
深入自定义泛型:
继承泛型:
/**
* 父类为泛型类
* 1、属性
* 2、方法
*
* 要么同时擦除,要么子类大于等于父类的类型,
* 不能子类擦除,父类泛型 --- 记住这个即可
* 1、属性类型。随位置而定
* 父类中,随父类而定
* 子类中,随子类而定
* 2、方法重写:
* 随父类而定
*
*
* @author Administrator
*
* @param <T>
*/
public abstract class Father<T,T1> {
T name;
public abstract void test(T t); //让子类重写
}
/**
* 子类声明时(也就是使用的时候),指定具体类型
* 属性类型为具体类型
* 方法同理
*/
class Child1 extends Father<String,Integer>{
String t2;
@Override
public void test(String t) {
}
}
/**
* 子类为泛型类 ,类型在使用时确定
* @author Administrator
*
*/
class Child2<T1,T,T3> extends Father<T,T1>{
T1 t2;
@Override
public void test(T t) {
}
}
/**
* 子类为泛型类,父类不指定类型 ,泛型的擦除,使用Object替换
*/
class Child3<T1,T2> extends Father{
T1 name2;
@Override
public void test(Object t) {
// TODO Auto-generated method stub
}
}
/**
* 子类与父类同时擦除,使用Object替换
*/
class Child4 extends Father{
String name;
@Override
public void test(Object t) {
}
}
/**
*错误:子类擦除,父类使用泛型。编译就会报错
//总之:子类不能单独擦除,要么同时擦除,要么父类擦除
class Child5 extends Father<T,T1>{
String name;
@Override
public void test(T t) {
}
*/
泛型接口:与继承同理
/**
* 泛型接口:与继承同理
* 重写方法随父类而定
*
* @param <T>
*/
public interface Comparable<T> {
void compare(T t);
}
//声明子类时,指定具体类型
class Comp implements Comparable<Integer>{
@Override
public void compare(Integer t) {
// TODO Auto-generated method stub
}
}
//擦除
class Comp1 implements Comparable{
@Override
public void compare(Object t) {
// TODO Auto-generated method stub
}
}
//父类擦除,子类泛型
class Comp2<T> implements Comparable{
@Override
public void compare(Object t) {
// TODO Auto-generated method stub
}
}
//子类泛型>=父类泛型
class Comp3<T> implements Comparable<T>{
@Override
public void compare(T t) {
// TODO Auto-generated method stub
}
}
//父类泛型,子类擦除 错误
/**
*泛型的擦除
*1、继承|实现声明 不指定类型
*2、使用时 不指定类型
*统一Object 对待
*1、编译器警告 消除使用Object
*2、不完全等同于Object ,编译不会类型检查
* @author Administrator
*
* @param <T>
*/
public class Student<T> {
private T javaScore;
private T oracleScore;
//泛型声明时不能使用 静态属性|静态方法上
//private static T1 test;
public T getJavaScore() {
return javaScore;
}
public void setJavaScore(T javaScore) {
this.javaScore = javaScore;
}
public T getOracleScore() {
return oracleScore;
}
public void setOracleScore(T oracleScore) {
this.oracleScore = oracleScore;
}
/**
* @param args
*/
public static void main(String[] args) {
Student stu1 = new Student();
//消除警告 使用 Object
Student<Object> stu = new Student<Object>();
//stu.setJavaScore("af"); //以Object对待
test(stu1); //stu1 相当于Object 但是不完全等同Object
//擦除,不会类型检查
//test(stu);
test1(stu1);
test1(stu);
}
public static void test(Student<Integer> a){
}
public static void test1(Student<?> a){
}
}
####深入自定义泛型2:
1、泛型没有多态
Fruit.java
public class Fruit {
}
class Apple extends Fruit{
}
/**
* 多态的两种形式
* @author Administrator
*
*/
public class FruitApp {
/**
* @param args
*/
public static void main(String[] args) {
Fruit f =new Apple();
test(new Apple());
}
//形参使用多态
public static void test(Fruit f){
}
//返回类型使用多态
public static Fruit test2(){
return new Apple();
}
}
//泛型类
public class A<T> {
}
/**
* 泛型没有多态
* @author Administrator
*
*/
public class App {
/**
* @param args
*/
public static void main(String[] args) {
//A<Fruit> f = new A<Apple>();
A<Fruit> f =new A<Fruit>();
//test(new A<Apple>());
}
//形参使用多态
public static void test(A<Fruit> f){
}
//返回类型使用多态
public static A<Fruit> test2(){
//return (A<Fruit>)(new A<Apple>());
return null;
}
}
/**
* 通配符
* ?表示类型不定,使用时确定类型
* ?使用:声明类型|声明方法上,不能在声明类或使用时 用
* ? extends : <= 上限 指定类型 子类或自身
* ? super :>=下限 指定类型 为自身或父类
* @author Administrator
*
*/
public class Student<T> {
T score;
public static void main(String[] args) {
Student<?> stu = new Student<String>(); //声明的时候不指定,使用的时候传递类型String
test(new Student<Integer>()); //使用
test2(new Student<Apple>());
//test3(new Student<Apple>()); //泛型没有多态
//test4(new Student<Apple>()); //<
stu = new Student<Fruit>();;
//test4(stu); //使用时确定类型
test4(new Student<Object>());
test4(new Student<Fruit>());
}
public static void test(Student<?> stu){
}
public static void test3(Student<Fruit> stu){
}
// <=
public static void test2(Student<? extends Fruit> stu){
}
//>=
public static void test4(Student<? super Fruit> stu){
}
}
没有泛型数组:
/**
* 没有泛型数组,那容器怎么办,用下面的方法变量保留。JDK源码ArrayList也是这么写的
* 声明可以使用,但是创建失败
* @author Administrator
*
*/
public class Array {
/**
* @param args
*/
public static void main(String[] args) {
Integer[] arr = new Integer[4];
//Student<String>[] arr2 = new Student<String>[10];
Student<?>[] arr2 = new Student[10];
MyArrayList<String> strList =new MyArrayList<String>();
strList.add(0, "a");
String elem =strList.getElem(0);
System.out.println(elem);
}
}
class MyArrayList<E>{
//E[] cap =new E[10]; 没有泛型数组:因为这个时候类型不定,无法在内存中开辟空间
Object[] cap = new Object[10];
public void add(int idx,E e){
cap[idx] =e;
}
@SuppressWarnings("unchecked")
public E[] getAll(){
return (E[]) cap;
}
@SuppressWarnings("unchecked")
public E getElem(int idx){
return (E) cap[idx];
}
}
JDK1.7泛型的改进:
/**
* 1.7中使用泛型,声明一次类型即可
* 在使用|创建时不用指定类型
* @author Administrator
*
*/
public class Test7 {
/**
* @param args
*/
public static void main(String[] args) {
List<String> arrList= new ArrayList<String>();
//List<String> arrList2= new ArrayList<>();
}
}
package com.zte.sdno.services.wandriver.amx;
import com.zte.sdno.model.fc.model.FCIpsecTunnel;
import com.zte.sdno.services.RestService;
import com.zte.sdno.services.RetroifitService;
import com.zte.sdno.services.hmf.HmfService;
import com.zte.sdno.services.wandriver.amx.interfaces.Ipsec;
import com.zte.sdno.utils.enums.FuncName;
import com.zte.sdno.utils.enums.ModuleName;
import com.zte.ums.zenap.hk2.i18n.I18nException;
import org.jvnet.hk2.annotations.Service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import retrofit2.Call;
import retrofit2.Retrofit;
import javax.inject.Inject;
/**.
* IPSEC 隧道接口
*
* @author 10225631
* @Time 2017/8/25 10:21
*/
@Service
public class IpsecService {
private static final Logger LOGGER = LoggerFactory.getLogger(IpsecService.class);
@Inject
private HmfService hmfService;
@Inject
private RestService restService;
@Inject
private RetroifitService retroifitService;
/**.
* 创建 ipsec隧道
* @param controllerId 控制器Id
* @param fcIpsecTunnel dirver 南向接口参数
*/
public void createIpsec(String controllerId, FCIpsecTunnel fcIpsecTunnel) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("create Ipsec begin, input is: " + fcIpsecTunnel);
}
Ipsec ipsec = createService(controllerId, Ipsec.class);
Call<Void> call = ipsec.create(controllerId, fcIpsecTunnel);
restService.callRequest(call, FuncName.CREATE_IPSEC, ModuleName.WAN_DRIVER, controllerId);
}
/**.
* 更新 IPSEC 隧道
* @param controllerId 控制器Id
* @param fcIpsecTunnel dirver 南向接口参数
*/
public void updateIpsec(String controllerId, FCIpsecTunnel fcIpsecTunnel) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("update Ipsec begin, input is: " + fcIpsecTunnel);
}
Ipsec ipsec = createService(controllerId, Ipsec.class);
Call<Void> call = ipsec.update(controllerId, fcIpsecTunnel);
restService.callRequest(call, FuncName.UPDATE_IPSEC, ModuleName.WAN_DRIVER, controllerId);
}
/**.
* 删除 IPSEC 隧道
* @param controllerId 控制器Id
* @param fcIpsecTunnel dirver 南向接口参数
*/
public void deleteIpsec(String controllerId, FCIpsecTunnel fcIpsecTunnel) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("delete Ipsec begin, input is: " + fcIpsecTunnel);
}
Ipsec ipsec = createService(controllerId, Ipsec.class);
Call<Void> call = ipsec.delete(controllerId, fcIpsecTunnel);
restService.callRequest(call, FuncName.DELETE_IPSEC, ModuleName.WAN_DRIVER, controllerId);
}
/**.
* 创建服务类
*/
private <T> T createService(String controllerId, Class<T> clazz) throws I18nException {
Retrofit retrofit = retroifitService.initRetrofit(hmfService.getAdapterUrl(controllerId));
return retrofit.create(clazz);
}
}