Java基础(20)泛型机制、泛型类、泛型方法、泛型接口、泛型通配符、增强for、可变参数

1. 泛型机制

1. 泛型机制概述:是一种将数据类型明确工作,推迟到创建对象或者调用方法是才去明确的一种机制
2. 泛型的好处:可以避免向下转型,也可以提高程序的扩展性
3. 泛型的语法:<类型>,<类型1,类型2…>,类型指的是引用类型
4. 类型的定义:泛型可以定义在类上,接口上,方法上
5. 泛型有效时间:泛型只在编译期有效,在运行期就擦除

2. 创建集合时使用泛型

1. 创建集合时使用引用普通类型作为泛型

import java.util.ArrayList;

public class TestDemo01 {
    public static void main(String[] args) {
        /**
         * 在没有使用泛型时,集合中可以存储多种类型的引用元素
         */
        ArrayList list1 = new ArrayList();
        list1.add(new Integer(111));
        list1.add(222);
        list1.add("java");
        list1.add(3.14);

        /**
         * 在创建集合时,使用泛型
         * 比如说明确了集合中只能存储String类型的数据
         */
        ArrayList<String> list2 = new ArrayList();
//        list2.add(11);   //报错,因为不是String类型
        list2.add("lol");
        list2.add("java");
        String s = list2.get(1);  //避免了向下转型

        /**
         * 明确集合中只能存储Integer类型
         */
        ArrayList<Integer> list3 = new ArrayList();
        list3.add(new Integer(11));
        list3.add(new Integer(22));
        list3.add(new Integer(33));
        Integer integer = list3.get(2);
        System.out.println(integer);

        /**
         * 如果需要存储多种类型的集合,泛型可以是Object
         * 一般来说,一个集合只存储一种类型的数据
         */
        ArrayList<Object> list4 = new ArrayList();
        list4.add("java");
        list4.add(123);
        list4.add(3.14);
        Object o = list4.get(1);
        System.out.println(o);
    }
}

2. 创建集合时使用类类型作为泛型

import java.util.ArrayList;
import java.util.Objects;

public class TestDemo02 {
    public static void main(String[] args) {
        ArrayList<LOL> list = new ArrayList<>();
        list.add(new LOL("EZ",24));
        list.add(new LOL("VN",30));
        list.add(new LOL("MF",27));

        //不用向下转型
        LOL lol = list.get(2);
        System.out.println(lol.getName() + "===" + lol.getAge());   //MF===27
    }
}

class LOL{
   private String name;
   private int age;

    public LOL() {
    }

    public LOL(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "LOL{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        LOL lol = (LOL) o;
        return age == lol.age &&
                Objects.equals(name, lol.name);
    }

    @Override
    public int hashCode() {

        return Objects.hash(name, age);
    }
}

3. 泛型类

1. 泛型类的概述:把泛型定义在类上
2. 泛型类的定义格式:public class 类名<泛型类型1,…>
3. 不使用泛型类和使用泛型类的对比

//不使用泛型类
public class TestDemo01 {
    public static void main(String[] args) {
        MyClass myClass = new MyClass();
        myClass.setObj("aaa");

        MyClass myClass2 = new MyClass();
        myClass2.setObj(111);

        //向下转型
        Object obj = myClass.getObj();
        String str = (String) obj;
        System.out.println(str.length());   //3
    }
}

/**
 * 在没有使用泛型时
 * 在设计一个类的时候,为了提高程序扩展性,经常会把这个数据类型设置为Object
 * 好处是提高了程序扩展性,不好处是还需要向下转型
 */
class MyClass{
    private Object obj;

    public Object getObj(){
        return obj;
    }

    public void setObj(Object obj){
        this.obj = obj;
    }
}

=======================================================================

//使用泛型类
public class TestDemo02 {
    public static void main(String[] args) {
        //先设置为String类型
        NewClass<String> newClass1 = new NewClass<>();
        newClass1.setObj("java");
        String str = newClass1.getObj();
        System.out.println(str.length());   //4

        //设置为Integer类型
        NewClass<Integer> newClass2 = new NewClass<>();
        newClass2.setObj(111);
        Integer integer = newClass2.getObj();
        System.out.println(integer.intValue());   //111
    }
}

/**
 * 设计一个类,使用泛型
 * 可以提高扩展性,也可以避免向下转型
 * T:代表任何数据类型
 */
class NewClass<T>{
    T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

4. 泛型接口

1. 泛型接口的概述:把泛型定义在接口上
2. 泛型接口的定义格式:public interface 接口名<泛型类型>

public class TestDemo03 {
    public static void main(String[] args) {
        //接口上定义了泛型,在创建接口的实现类对象时明确具体类型
        //匿名内部类
        new MyInterface<Double, Integer>() {
            @Override
            public Double test(Integer integer) {
                return null;
            }
        };

        new MyInterface<Integer, String>() {
            @Override
            public Integer test(String s) {
                return null;
            }
        };

        //创建接口的实现类对象
        MyInterfaceImpl myInterface = new MyInterfaceImpl();
        Integer abc = myInterface.test("abc");
    }
}

interface MyInterface<R,P>{
    public abstract R test(P p);
}


//有一个具体的子类在实现接口时,这个接口上有泛型,就可以直接明确接口上的泛型
class MyInterfaceImpl implements MyInterface<Integer,String>{

    @Override
    public Integer test(String s) {
        return null;
    }
}

5. 泛型方法

1. 泛型方法的概述:把泛型定义在方法上
2. 泛型方法的定义格式:public<泛型类型> 返回值类型 方法名(泛型类型 变量名)

public class TestDemo01 {
    public static void main(String[] args) {
        LOL lol = new LOL();
        //在调用泛型方法时,再去明确方法上的泛型具体是哪一种类型
        lol.show("java");
        lol.show(111);
        lol.show(3.14);

      /*  String str = lol.show2("java");
        Integer num = lol.show2(123);*/

        Object o1 = lol.show3("go");
    }
}

class LOL<R>{
    public<T> void show(T s){
        System.out.println(s);
    }

    public<T> T show2(T s){
        System.out.println(s);
        return null;  //这里只能返回null,语法不报错,但没有意义
    }

    public<T> R show3(T s){
        System.out.println(s);
        return null;
    }
}

6. 泛型通配符

1. 泛型通配符<?>:任意类型,如果没有明确定义,那么就是Object类型以及任意Java类
2. <? extends E>:向下限定,E及E的子类
3. <?super E>:向上限定,E及E的父类

import java.util.ArrayList;

public class TestDemo01 {
    public static void main(String[] args) {
        //泛型通配符 ?
        ArrayList<?> list1 = new ArrayList<People>();
        ArrayList<?> list2 = new ArrayList<Teacher>();
        ArrayList<?> list3 = new ArrayList<Student>();

        //向下限定
        ArrayList<? extends People> arrayList1 = new ArrayList<People>();
        ArrayList<? extends People> arrayList2 = new ArrayList<Teacher>();
        ArrayList<? extends People> arrayList3 = new ArrayList<Student>();
//        ArrayList<? extends People> arrayList4 = new ArrayList<Object>();  //错误 Object是People的父类

        //向上限定
        ArrayList<? super People> arrayList4 = new ArrayList<Object>();
        ArrayList<? super People> arrayList5 = new ArrayList<People>();
        
        ArrayList<? super Student> arrayList6 = new ArrayList<People>();
        ArrayList<? super Student> arrayList7 = new ArrayList<Student>();
//        ArrayList<? super Student> arrayList8 = new ArrayList<Teacher>();  //错误 Teacher不是Student的子类
    }
}

class People{

}

class Teacher extends People{

}

class Student extends People{

}

7. 增强for循环

1. 增强for循环概述:简化数组和Collection集合的遍历
2. 格式:for(数据类型 变量:数组或Collection集合){
直接使用变量即可,该变量就是元素
}
3. 注意事项:

  • 增强for的目标要先判断是否为null
  • 在遍历途中,不能增删元素,否则会报并发修改异常
//增强for遍历字符串
public class TestDemo01 {
    public static void main(String[] args) {
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add("java");
        arrayList.add("lol");
        arrayList.add("c++");
        arrayList.add("IDEA");

        for (String s : arrayList) {
            System.out.println(s);
        }
        /**
         * java
         * lol
         * c++
         * IDEA
         */
    }
}

=================================================================

//增强for遍历自定义对象
public class TestDemo02 {
    public static void main(String[] args) {
        ArrayList<LOL> list = new ArrayList<>();
        list.add(new LOL("EZ",20));
        list.add(new LOL("VN",23));
        list.add(new LOL("MF",25));

        for (LOL lol : list) {
            System.out.println(lol);
        }

        /**
         * LOL{name='EZ', age=20}
         * LOL{name='VN', age=23}
         * LOL{name='MF', age=25}
         */
    }
}

class LOL{
    private String name;
    private int age;

    public LOL() {
    }

    public LOL(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "LOL{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

8. 可变参数

1. 可变参数的概述:当定义方法是不知道该定义多少个参数时可以用到可变参数
2. 可变参数的定义格式:(数据类型 … 变量名)
3. 注意事项:

  • 这里的变量其实是一个数组
  • 如果一个方法有可变参数,并且有多个参数,那么必须把可变参数放在最后一个
public class TestDemo01 {
    public static void main(String[] args) {
        int num1 = add(1, 2, 3, 4, 5, 6, 7, 8, 9);
        System.out.println(num1);  //45

        int num2 = add(11, 22, 33, 44, 55, 66);
        System.out.println(num2);   //231
    }

    public static int add(int ... i){  //可变参数其实是个数组,把你传过来的多个参数放到数组中
        int sum = 0;
        for (int ele : i) {
            sum += ele;
        }
        return sum;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值