java泛型-泛型类-泛型接口-泛型方法-可变参数-

泛型

概述

概念:

  • 泛型,是JDK5引入的特性,提供了编译时类型安全监测机制,该机制允许在编译时检测到非法的类型
  • 本质 = 参数化类型,就是所操作的数据类型被指定为一个参数
  • 提到参数 就会想到 定义方法是的形参,然后调用此方法时传递的是实参
  • 参数化类型 = 将类型由原来具体的类型参数化,然后在使用/调用时传入具体的类型
  • 参数化类型的参数 可以用在类、方法和接口中,分别被称为泛型类、泛型方法、泛型接口。

泛型定义格式:

<类型> :
指定一种类型的格式,这里的类型可以看成是形参

<类型1,类型2....>:
指定多种类型的格式,多种类型之间用逗号隔开

将来具体调用时给定的类型可以看成是实参,并且实参的类型只能是引用数据类型

泛型好处:
①把运行时期的问题提前到了编译期间
比如:当list集合原本存储的是String类型,之后存储integer类型的时候,不使用泛型编译阶段不会报错,而运行时会报错;使用泛型之后,报错会提前出现在编译阶段。

②避免了强制类型转换
比如:使用迭代器遍历集合,集合不使用泛型,则迭代器获得对象类型是Object对象,假设原本的对象是String类型,可能就需要进行强制类型转换,将Object类型转换为String类型;集合使用泛型之后,迭代器对象自动返回泛型类型,不需要再进行强制转换。

案例:

// 217-FDemo
public class FDemo {
    public static void main(String[] args) {

        // 创建Collection集合,不适用泛型
        Collection c = new ArrayList();

        // 在创建集合的时候不使用泛型< E >,这样在使用集合.add方法的时候,添加元素默认为Object类型,因为泛型只能是引用数据类型,所有引用数据类型都是Object类型
        c.add("hello"); // 属于String - Object 向上转型
        c.add("java");
        c.add("world");

        // 问题1:没有使用泛型,当集合之前存储String类型,之后又存储Integer类型的时候,编译不会报错,但是运行会报错
//        c.add(100);//ClassCastException

        // 使用迭代器 遍历集合
        Iterator it = c.iterator();
        while(it.hasNext()){
            // 按照默认的Object类型 可以执行
//            Object o = it.next();
            // 但就是想使用String类型的时候,需要强制转化 可以执行
            String s = (String)it.next();
            System.out.println(s);
        }

        System.out.println("-------------");

        // 问题2:如果集合使用泛型,那么迭代器的部分也会使用泛型,这样就避免使用强制类型转换。
        Collection<String> cs = new ArrayList<String>();
        cs.add("just do it");
        cs.add("i can do it");
        Iterator<String> it2 = cs.iterator();
        while(it2.hasNext()){
            String s = it2.next();
            System.out.println(s);
        }
    }
}

泛型类

泛型类的定义格式:

修饰符 class 类名< 类型T >{
	// 成员变量
	private T t;
	// 成员变量的get/set方法
	public T getT(){} 
	public void setT(T t){
		this.t = t;
		}
	// 成员方法使用 泛型方法
	public <T> 返回值类型 方法名(T t){
		System.out.println(t);
		}
}

例子: public class Generic< T >{}
注意:此处的T是任意标识,常见的有T/E/K/V等形式的参数用于表示泛型

案例:

//217-test4
测试类:
public class GenericDemo {
    public static void main(String[] args) {
        Student s = new Student();
        s.setName("汪苏泷");
        System.out.println(s.getName());

        Teacher t = new Teacher();
        t.setAge(45);
//        t.setAge("100"); // 此时接收字符串类型参数会报错。
        System.out.println(t.getAge());

        // 问题:使用setXXX方法只能接收一种类型的参数,不能接收多种类型的参数

        // 上述问题通过定义泛型类解决
        System.out.println("-----------------");
        GenericClass<String> g = new GenericClass<String>();
        g.setT("汪苏泷");
        System.out.println(g.getT());

        GenericClass<Integer> g2 = new GenericClass<Integer>();
        g2.setT(100);
        System.out.println(g2.getT());

        // 实现两个不同对象不同类型参数的输入,采用一个泛型类即可。

    }
}

泛型类:
public class GenericClass < T > {
    private T t;

    public T getT() {
        return t;
    }

    public void setT(T t) {
        this.t = t;
    }
}

泛型方法

泛型方法定义格式:

修饰符 < 类型 > 返回值类型 方法名(类型 变量名){}
例子:public < T > void show(T t){}

解决问题
当一个类中的方法需要输出多种参数类型变量的时候,
解决方式有两种:
①泛型类: 也就是说通过泛型类 去设置方法的参数类型,当方法需要多个参数的时候,就对应需要创建多个对象,造成内存资源的浪费;
②泛型方法:在定义方法的时候再指定泛型,不需要创建多个对象。

案例:

// 217-test5-GenericDemo
测试类:
public class GenericDemo {
    public static void main(String[] args) {

        GenericClass g = new GenericClass();
        g.show("string");
        g.show(10);
        g.show(true);

        // 问题1:如果在类中 创建多个show方法,实现不同类型参数的 show方法重载,这样会造成对象调用方法受限制,只能使用类中定义的方法。
        // 解决方式:使用泛型类
/*        System.out.println("---------------");

        GenericClass<String> g2 = new GenericClass<String>();
        g2.show("string");
        GenericClass<Integer> g3 = new GenericClass<Integer>();
        g3.show(100);*/

        // 问题2:采用泛型类的方式,会在定义对象的时候明确泛型,这样也重复定义了对象。
        System.out.println("------------");
        GenericClass g2 = new GenericClass();
        g2.show("string");
        g2.show(125);
        g2.show(true);
    }
}

类:

/*public class GenericClass {
    // 定义show方法,实现三种类型数据的输出
    public void show(String s){
        System.out.println(s);
    }
    public void show(boolean b){
        System.out.println(b);
    }
    public void show(int i){
        System.out.println(i);
    }
}*/

// 问题1 : 使用泛型类
//public class GenericClass<T>{
//    public void show(T t){
//        System.out.println(t);
//    }
//}

// 问题2 使用泛型方法
public class GenericClass{
    public <T> void show(T t){
        System.out.println(t);
    }
}

泛型接口

定义格式:

修饰符 interface 接口名< 类型 >{}
例子:public interface Generic<T>{}
接口中的方法:
	修饰符 返回值类型 方法名(T t);


泛型接口不能直接实例化,需要借助接口的实现类
泛型接口实现类定义:
	修饰符 class 类名<T> implements 接口名<T>{}
	还需要重写接口中的方法。
		 @Override
	    修饰符 返回值类型 方法名(T t) {}

案例:

// 218-test1
// 定义泛型接口,
// 实例化对象不同直接通过接口进行,所以要定义接口的实现类。根据List接口相关定义
public interface Generic<T> {
    void show(T t);
}

public class GenericImpl<T> implements Generic<T> {
    @Override
    public void show(T t) {
        System.out.println(t);
    }
}

public class GenericDemo {
    public static void main(String[] args) {

        Generic<String> g = new GenericImpl<String>();
        g.show("汪苏泷");

        Generic<Integer> g2 = new GenericImpl<Integer>();
        g2.show(33);
    }
}

类型通配符

  • 为了表示各种泛型List的父类,可以使用类型通配符
类型通配符:<?>

List<?>:表示元素类型未知的List,
它的元素可以匹配任何的类型
这种带通配符的List仅表示它是各种泛型List的父类,并不能把元素添加到其中
  • 类型通配符的上限
    想将List<?>从表示任何泛型List的父类,变成,只表示某一类泛型List的父类,可以使用类型通配符的上限
类型统配符上限:List<? extends 类型>
例子:
List<? extends Number> 表示的类型是Number或者其子类型
理解:?继承自Number,说明?是Number或者是Number的子类型
  • 类型通配符的下限
类型通配符下限:List< ? super 类型>
例子:
List< ? super Number> 表示的类型是Number或者其父类型
理解:? super Number,说明?是Number或者是Number的父类型

案例:

// 218
public class GenericDemo1 {
    public static void main(String[] args) {

        // object ==> Number ==> Integer
        // 类型通配符 List<?>
        List<?> list1 = new ArrayList<Object>();
        List<?> list2 = new ArrayList<Number>();
        List<?> list3 = new ArrayList<Integer>();

        // 类型统配符上限:List<? extends Number>
//        List<? extends Number> list4 = new ArrayList<Object>();
        // 报错:因为上限是Number,object比Number更高一级
        List<? extends Number> list5 = new ArrayList<Number>();
        List<? extends Number> list6 = new ArrayList<Integer>();

        // 类型通配符下限:List<? super Number>
        List<? super Number> list7 = new ArrayList<Object>();
        List<? super Number> list8 = new ArrayList<Number>();
//        List<? super Number> list9 = new ArrayList<Integer>();
        //报错:因为下限是Number,Integer比Number低一级
    }
}

可变参数

可变参数:又称参数个数可变,用作方法的形式参数出现,那么方法参数个数就是可变的。

格式:

修饰符 返回值类型 方法名(数据类型...变量名){}
例子:pubilc static int sum(int...a){}

注意:
1 这里的变量其实是一个数组
2 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

案例:

// 218
public class SumDemo {
    public static void main(String[] args) {
        System.out.println(sum(10, 20));
        System.out.println(sum(10,20,30));
        System.out.println(sum(10,20,30,40));
        System.out.println(sum(10,20,30,40,50));
        System.out.println(sum(10,20,30,40,50,60));
    }
    // 问题:要想是求5个参数的和,那么就需要再定义对应的方法,那么当需要更多参数的时候,同样也需要再定义。这样比较麻烦
    // 解决方式:可变参数
    public static int sum(int...a){
//        System.out.println(a);//输出内容是:I@1b6d3586 表示int类型数组
        int sum = 0;
        for(int i:a){
            sum += i;
        }
        return sum;
    }
//    public static int sum(int a,int b){
//        return a + b;
//    }
//    public static int sum(int a,int b ,int c){
//        return a + b + c;
//    }
//    public static int sum(int a,int b,int c,int d){
//        return a + b + c + d;
//    }
}

可变参数方法

所属类方法名说明方法使用
Arraypublic static < T> List < T > asList(T…a)返回由指定数组支持的固定大小的列表
返回值类型是List< T >
add、remove不可以使用
set可以使用
Listpublic static < T > List < T > of(E…elements)返回包含任意数量元素的不可变列表
返回值类型是List< T >
add、remove、set都不可以使用
Setpublic static < T > Set < E > of(E…elements)返回包含任意数量元素的不可变集合
返回值类型是Set< T>
add、remove不可以使用
没有索引,没有set方法
设置集合元素的时候,不能设置重复元素

案例Array、List、Set

// 218
public class ArrDemo {
    public static void main(String[] args) {

        List<String> lis = Arrays.asList("hello", "java", "world");

//        lis.add("javaee");//UnsupportedOperationException
        // 报错,说明Arrays.asList创建对象不支持 add方法

//        lis.remove("world");//UnsupportedOperationException
        // 报错,说明Arrays.asList创建对象不支持 remove方法

        lis.set(1, "javaee");
        // 修改成功,因为 add和remove方法会改变list集合长度

        System.out.println(lis);
        // 输出信息是:[hello, java, world]

        // 本机装的jdk8 没有安装 jdk9 所以会报错
//        List<String> lis2 = List.of("hello","java","world","java");
        // 这里报错的原因是 jdk低于9版本,因为这个方法是jdk9引入的。
//        Set.of();// 同理也是jdk9添加的
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值