Java中的泛型

一.泛型的注意事项

1.1泛型的概念

用一对尖括号表示<>:全称泛化类型

1.2泛型的作用

安全省心

1.3自定义泛型类

(1)  ‘<>’  尖括号中尽量写单个字母,尽可能见名知意

  例如:T代表 Type

    K  V  分别代表KeyValue

 E  代表Element

(2) 使用时不能为基本类型,只能是引用类型

(3) 只能用在非静态成员变量上,不能使用在静态变量上

示例代码:

package Day1;

/**

 * 自定义泛型类

 * 1.<> --> 尖括号中尽量写单个字母,尽可能见名知意

 * 例如:T  Type

 *     K V  Key  Value

 *     E   Element

 * 2.使用时不能为基本类型    

 * 3.泛型不能使用在静态属性上

 * @author asus

 *

 */

public class MyStudent<T> {

//注意点:泛型不能使用在静态属性上

private Tscore;

public MyStudent(){

}

/*

 * 注意:静态方法可以用引用类型参数,

 * 但是必须是自声明,不能由这个类来声明

     * 相当于是声明了一个泛型方法

 * */

public static <T1> T1/*void*/ m(T1t){

return null;

}

public MyStudent(T score){

this.score = score;

}

public T getScore() {

return score;

}

public void setScore(T score) {

this.score = score;

}

 

}

 

 

 

(4) 对于静态方法,静态初始化块及静态变量的声明和初始化不能使用泛型的原因:

1.因为泛型是要在对象创建的时候才知道是什么类型的,而对象创建的代码执行先后顺序是static的部分,然后才是构造函数等等。所以在对象初始化之前static的部分已经执行了,如果你在静态部分引用的泛型,那么毫无疑问虚拟机根本不知道是什么东西,因为这个时候类还没有初始化。因此在静态方法、数据域或初始化语句中,为了类而引用泛型类型参数是非法的

2.这个原理是这样的,静态方法中所能引用的属性必须是静态的,而引用参数是无法声明为静态的,因为静态的属性必须在声明时赴值或者实例化,泛型引用变量在声明的时候根本不知道是什么类型,自然不可能实例化,当然也不能放进静态方法了。

 

1.4自定义泛型接口

1. 接口中泛型类型只能使用在公共抽象方法上(包括设置方法的返回类型或者方法的形参类型),不能使用在全局常量中

实例代码:

package Day1;

/**

 * 定义泛型接口

 * 注意:接口中泛型字母只能使用在公共抽象方法上,不能使用在全局常量中

 * @author asus

 *

 */

 

    //接口中的方法默认都是public abstract和常量默认都是public static final

public interface Comparator<T> {

//全局变量

public static final int MAX_VALUE = 1024;

//公共的抽象方法

    T compare(T t);

}

 

 

1.5自定义泛型方法

1. 泛型方法可以在泛型类中,也可以在非泛型类中

2. 非泛型类中定义泛型方法

     其中该方法可以是静态方法,也可以是非静态方法

3. 泛型方法的定义:

     在返回值前面加上<字母>

4. 通过在泛型上加extendssuper关键字来设置泛型的上下限(后面详细介绍)

示例代码:

package Day1;

 

import java.io.Closeable;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileNotFoundException;

import java.io.IOException;

import java.util.List;

 

/**

 * 泛型方法可以在非泛型类中也可以在泛型类型中

 * 非泛型类中定义泛型方法

 *     其中方法可以是静态方法也可以是成员方法

 * 泛型方法定义:

 *       在返回类型前面加上<字母>    

 * @author asus

 *

 */

public class Method {

 

public static <T>void test(T t){

System.out.println(t);

}

public static <Textends List>void test(T t){

System.out.println(t);

t.add("aa");

System.out.println(t);

}

public static <Textends Closeable>void test(T...a){

for(T temp:a){

   try{

if(temp !=null){

temp.close();

}

}catch(IOException e){

 e.printStackTrace();

}

  }

}

public static void main(String[] args)throws Exception {

test("bjsxt is very good");

test(new FileInputStream("a.txt"));

}

 

}

 

 

1.6泛型父类的继承问题

1. 泛型父类的两种子类实现,子类为富二代

1. 保留父类泛型--->子类为泛型

   1).全部保留

   2).部分保留

2. 不保留父类泛型--->子类按需实现

   1).具体类型

   2).没有类型(类似于Object,泛型的擦除)

注意:子类也可以添加自己需要的泛型。

3. 子类重写方法的类型--->随父类而定

4. 子类新增方法的类型--->随子类而定

5. 子类中使用父类的属性--->随父类而定

6. 子类使用自己的属性--->随子类而定

总之:属性及方法--->随位置而定

示例代码:

package day2;

/**

 * 泛型父类

 * 1.保留父类泛型---->子类为泛型子类

 * 2.不保留父类泛型--->子类按需实现

 * @author asus

 * 属性及方法类型--->随位置而定

 * 1.子类重写方法的类型--->随父类而定

 *   子类新增方法的类型--->随子类而定

 * 2.子类中使用父类的属性--->随父类而定

 *   子类中使用自己的属性---->随子类而定

 */

public abstract class Father<T1,T2> {

T1 age;

public abstract void test(T2 name);

}

 

//保留  -->泛型子类

//1)全部保留

class C1<T1,T2,A,B>extends Father<T1,T2>{

 

@Override

public void test(T2 name) {

//this.age --->T1

}

}

//2)部分保留

class C2<T2,A,B>extends Father<Integer,T2>{

 

@Override

public void test(T2 name) {

//this.age---->Integer

}

}

//不保留 -->按需实现

//1)具体类型

class C3<A,B>extends Father<Integer,String>{

 

@Override

public void test(String name) {

//this.age--->Integer

}

}

//2)没有类型 擦除 类似于Object

class C4<A,B>extends Father{

 

@Override

public void test(Object name) {

//this.age---->Object

}

}

1.7泛型接口

泛型接口的用法同泛型父类的用法一样,此处可以参考泛型父类笔记,下面仅提供示例代码

示例代码:

package day2;

/**

 * 泛型接口与泛型类同理

 * @author asus

 *

 */

public interface Comparator<T> {

//接口只包含公共的抽象的方法和全局常量

public static final int MAX_VALUE=100;

public abstract void test(T t);

}

 

//实现

/**

 * 泛型擦除:

 *   定义  :泛型擦除是指在继承、实现、或者使用时没有指定具体的类型

 *   特点  : 一旦擦除之后按Object处理

 *        --依然存在警告,加上Object可以去除,但是有些画蛇添足

 *        --不完全等同于Object,编译不会类型检查

 */

class InterC1<String,T>implements Comparator<T>{

 

@Override

public void test(Object t) {

}

}

class InterC2<A>implements Comparator<Integer>{

 

@Override

public void test(Integer t) {

}

}

class InterC3<T,A>implements Comparator<T>{

 

@Override

public void test(T t) {

}

}

 

1.8泛型的擦除

泛型擦除:

   定义  :泛型擦除是指在继承、实现、或者使用时没有指定具体的类型

   特点  一旦擦除之后按Object处理

        --依然存在警告,加上Object可以去除,但是有些画蛇添足

        --不完全等同于Object,编译不会类型检查

注意:泛型的擦除是在编译时期

示例代码:

package day2;

/**

 * 泛型的擦除:使用时或者实现或者继承 没有指定类型

 * 类似于Object,不等同于Object

 * @author asus

 *

 */

public class MyStuApp {

 

public static void main(String[] args) {

//此处使用了 擦除-->即 没有指定 泛型的具体类型

MyStudent student = new MyStudent();

student.setScore(100);//100-->int--->Integer---->Object

MyStudent<Object> student2 = new MyStudent<Object>();

test(student);

//不等于Object

        //test(student2);

}

public static void test(MyStudent<Integer> stu){

}

 

}

 

1.9泛型的通配符 (?)

1.  ? --> 表示类型不确定,用于声明变量或者形参上

2.  不能用在:创建对象上,创建泛型类上,泛型方法,泛型接口上

示例代码:

package day3;

 

import java.util.ArrayList;

import java.util.List;

 

/*

 * ? -->表示类型不确定,用于声明变量或者形参上

 * 不能用在:

 * 1.创建对象上

 * 2.创建泛型类,泛型方法,泛型接口上

 */

public class WildCardsTest {

 

public static void main(String[] args) {

// 声明

List<?> list = new ArrayList<Integer>();

list = new ArrayList<String>();

list = new ArrayList<Object>();

test(list);

 

// 编译错误,不能用在创建对象上

// list = new ArrayList<?>();

 

}

 

// 编译错误,不能用在创建泛型类上

// class Test<?>{}

 

// 编译错误,不能用在泛型方法上

//public static <?> void test2(){}

public static void test(List<?> list) {

 

}

 

}

 

2.0 泛型的上限

使用extends : 泛型的上限  <= 即:子类或者自身

1. 一般用于限制操作

2.不能使用在添加数据上面,一般都是读取操作

   extends还可以和通配符一起使用

3.规则

    List<Fruit> ---> List<? extends Fruit>

    List<Apple> ---> List<? extends Fruit>

    List<? extends Apple> ---> List<? extends Fruit>

不能存放的是List<?>,因为他等同于List<? extends Object>

示例代码:

package day3;

 

import java.util.ArrayList;

import java.util.List;

 

/*

 * extends : 泛型的上限  <= 即:子类或者自身

 * 1.一般用于限制操作

 * 2.不能使用在添加数据上面,一般都是读取操作

 *    extends 还可以和通配符一起使用

 * 3.规则

 *    List<Fruit> ---> List<? extends Fruit>

 *    List<Apple> ---> List<? extends Fruit>

 *    List<? extends Apple> ---> List<? extends Fruit>

 * 不能存放的是:List<?>,因为他等同于List<? extends Object>

 *

 *

 *

 * */

public class ExtenndsTest {

 

public static void main(String[] args) {

//extends 为上限

Test<Fruit> t1 = new Test<Fruit>();

Test<Apple> t2 = new Test<Apple>();

Test<Pear> t3 = new Test<Pear>();

//调用方法

List<? extends Fruit> list1 =new ArrayList<Fruit>();

test(list1);

List<Fruit> list2 = new ArrayList<Fruit>();

test(list2);

List<Apple> list3 = new ArrayList<Apple>();

test(list3);

//? extends Apple

List<? extends Apple> list4 =new ArrayList<Apple>();

test(list4);

//? ---> 为什么错误,因为?可以接收所有类型,等同于? extends Object

/*List<?> list5 = new ArrayList<Apple>();

test(list5);*/

}

public static void test(List<?extends Fruit> list){

}

/*定义一个内部类*/

static class Test<Textends Fruit>{

}

}

 

2.1泛型的下限

使用supper:泛型的  >=即:或者自身

2. 一般用于限制操作

2.能够添加数据在上面,但不能添加父类对象

   Supper还可以和通配符一起使用

3.规则

    List<Fruit> ---> List<?super Fruit>

    List<Apple> ---> List<?super Apple>

    List<? super Fruit> ---> List<?super Apple>

不能存放的是List<? super FujiApple> ---> List<? super Apple>,因为,FujiAppleApple的子类。

2.2泛型的嵌套

1. 总之一句话,由外到内一层一层的展开。

2.3泛型没有多态和数组

参考下面的示例代码

示例代码:

package day3;

 

import java.util.ArrayList;

import java.util.List;

 

/*

 * 1.泛型没有多态

 * 2.泛型没有数组

 *

 * */

public class Polymorphism {

public static void main(String[] args) {

//多态

Fruit f =new Apple();//ok

//泛型没有多态

//List<Fruit> list = new ArrayList<Apple>();//编译出错

List<? extends Fruit>list =new ArrayList<Apple>();//这样是OK

//泛型没有数组

//Fruit<String>[] arr = new Fruit<String>[];//编译出错

}

}

 

2.4 JDK1.7关于泛型的简化

1. Fruit<String> list = new ArrayList<>();这样定义在JDK1.7中是可以的,但是在JDK1.6中必须把后面的也补全,像这样:Fruit<String> list = new ArrayList<String>();

 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值