【JavaSE】集合框架2[泛型、Set接口]

①泛型

  • Java的泛型是JDK1.5中引入的一个新特性,它的本质是参数化类型,把类型作为参数传递
  • 常见使用形式: 泛型类 , 泛型接口 , 泛型方法
  • 语法: <T,E,K,V,…> T称为类型占位符,表示一种引用类型
  • 好处:
    提高代码的重用性
    防止类型转换异常,提高代码的安全性

- 泛型类

public class TestGenericClass {
    public static void main(String[] args) {
        /*
            注意:
            1.泛型只能是引用类型
            2.不同泛型类型对象之间不能相互复制
         */

        //使用泛型类创建对象
        GenericClass<String> genericClass1 = new GenericClass<>();

        genericClass1.t = "iFinder";
        genericClass1.show("hello !");   //hello !
        String str = genericClass1.getT();
        System.out.println(str);   //iFinder

        GenericClass<Integer> genericClass2 = new GenericClass<>();
        genericClass2.t = 1592900;
        genericClass2.show(100);   //100
        Integer integer = genericClass2.getT();
        System.out.println(integer);   //1592900
    }
}

/**
 * 泛型类
 * 在类名的后边加<T,E,V,......>
 * T是类型占位符,表示一种引用类型,如果添加多个需要用","隔开
 */
class GenericClass<T> {
    //使用泛型T
    //1.创建变量
    T t;

    //2.作为方法的参数
    public void show(T t){
        //T t1 = new T();  可以创建变量,但是不能实例化.因为不能保证T具有构造器
        System.out.println(t);
    }

    //3.使用泛型作为方法的返回值
    public T getT(){
        return t;
    }
}

- 泛型接口

/**
 * 泛型接口
 * 语法:接口名<T>
 * 注意:不能创建泛型的静态常量
 */
public interface GenericInterface<T> {
    String name = "iFinder";
    //T t;接口中不能创建泛型常量

    //T作为方法的返回值类型,作为传入的参数类型
    T server(T t);
}

/**
 * 泛型接口的实现类
 * 确定与不确定实现类的参数类型,会在重写抽象方法的时候造成不同
 */
class TestGenericInterface1 implements GenericInterface<String>{
    @Override
    public String server(String s) {
        System.out.println(s);
        return null;
    }
}

class TestGenericInterface2<T> implements GenericInterface<T>{
    @Override
    public T server(T t) {
        return null;
    }
}

public class TestGeneric {
    public static void main(String[] args) {
        TestGenericInterface1 tgi1 = new TestGenericInterface1();
        tgi1.server("iFinder");
        TestGenericInterface2<Integer> tgi2 = new TestGenericInterface2<>();
        tgi2.server(100);
    }
}

- 泛型方法

/**
 * 泛型方法
 * 语法:<T>方法返回值类型
 */
class GenericMethod {
    //泛型方法
    public <T>void show(T t){
        System.out.println("泛型方法" + t);
    }
}

public class TestGeneric {
    public static void main(String[] args) {
        //调用泛型方法
        GenericMethod gm = new GenericMethod();
        gm.show("I'm iFinder !");   //T的类型由传入的数据决定
    }
}

- 泛型的好处

提高代码重用性:

  • 避免的相同方法不同参数时造成的多次重载,提升代码利用率

防止类型转换异常,提高代码安全性

- 泛型集合

概念: 参数化的类型 , 类型安全的集合 , 强制集合的元素类型必须保持一致
特点:

  • 编译时即可检查,而非运行时抛出异常
  • 访问时不必由Object向所需类型转换
  • 不同泛型之间引用不能相互赋值,泛型不存在多态

集合ArrayList <>, LinkedList<>在创建时,如果不传入对应的泛型类型,则Java会默认为传入的是Object类型,便可以存储任何类型.

import java.util.ArrayList;
import java.util.Iterator;

public class GenericCollection {
    public static void main(String[] args) {
        //只能添加泛型类型规定的元素
        ArrayList<String> list1 = new ArrayList<>();
        list1.add("iFinder");
        list1.add("Nancy");

        ArrayList<Integer> list2 = new ArrayList<>();
        list2.add(100);
        list2.add(200);

        Iterator<String> it = list1.iterator();
        while(it.hasNext()){
            //使用迭代器遍历元素时不用进行类型转换
            String str =  it.next();
            System.out.println(str);
        }
    }
}

②Set集合

- Set子接口

特点:无序,无下标,元素不可以重复
方法:全部继承自Collection中的方法

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

/**
 * 测试set接口的使用
 * 特点:无序,无下标,不能重复
 */
public class SetTest1 {
    public static void main(String[] args) {
        //创建集合
        Set<String> set =new HashSet<>();

        //1.添加数据
        set.add("iPhone");
        set.add("HuaWei");
        set.add("XiaoMi");
        set.add("MeiZu");
        System.out.println("元素个数:" + set.size());   //元素个数:4
        System.out.println(set.toString());    //[iPhone, MeiZu, XiaoMi, HuaWei]

        //2.删除数据
        //set.remove("XiaoMi");
        //set.clear();

        //3.遍历
        //3.1 增强for
        for (String s : set) {
            System.out.println(s);
        }

        //3.2使用迭代器
        Iterator<String> it = set.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        
        //4.判断 .contains() .isEmpty()
        
    }
}

- Set的实现类

-HashSet:
基于HashCode计算元素的存放位置
当存入元素的Hash码相同时,会调用equals确认,如果结果为true,则拒绝后者的存入

-TreeSet:
基于排列顺序实现,元素不可重复
实现了SortedSet接口,对集合元素自动排序
元素对象的类型必须实现Comparable接口,指定排序规则
通过CompareTo()方法确定元素是否重复

- HashSet的使用

  • HashSet的存储过程:
  • 1.根据hashcode()计算保存的位置,如果此位置为空,直接保存.否则执行下一步
  • 2.再执行equals()方法,如果返回值为true,则认为重复不能存储.否则形成链表
import java.util.HashSet;
import java.util.Iterator;

/**
 * HashSet集合的使用
 * 存储结构:Hash表(数组+链表+红黑树[JDK1.8之后])
 */
public class HashSetTest {
    public static void main(String[] args) {
        //新建集合
        HashSet<String> hashSet = new HashSet<>();

        //1.添加元素
        hashSet.add("Nancy");
        hashSet.add("iFinder");
        hashSet.add("BobBy");
        hashSet.add("JacyCa");

        System.out.println("元素个数:" + hashSet.size());   //元素个数:4
        System.out.println(hashSet);   //[iFinder, JacyCa, Nancy, BobBy] 输出顺序与添加顺序是不同的

        //2.删除元素  .remove()  .clear()
        
        //3.遍历
        //3.1 增强for
        //3.2迭代器
        Iterator<String> it = hashSet.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        
        //4.判断  .contains()  .isEmpty()
    }
}

import java.util.HashSet;
import java.util.Iterator;

/**
 * HashSet 的使用
 * 存储结构:哈希表(数组+链表+红黑树)
 * 存储过程:
 * 1.根据hashcode()计算保存的位置,如果此位置为空,直接保存.否则执行下一步
 * 2.再执行equals()方法,如果返回值为true,则认为重复不能存储.否则形成链表
 */

public class HashSetTest2 {
    public static void main(String[] args) {
        //创建集合
        HashSet<Person> hashSet = new HashSet<>();

        //1.添加数据
        Person p1 = new Person("iFinder",19);
        Person p2 = new Person("Nancy",18);
        Person p3 = new Person("BobJoy",34);
        Person p4 = new Person("JackChan",23);

        hashSet.add(p1);
        hashSet.add(p2);
        hashSet.add(p3);
        hashSet.add(p4);
        hashSet.add(p1);  //添加是不会报错,但是已经不会在集合中添加重复的元素了
        hashSet.add(new Person("Nancy",18));  //添加属性相同的对象,成功!   重写方法后,添加失败
        //如果要实现属性相同就不能添加,需要重写hashcode() equals()方法

        System.out.println(hashSet.toString());   //[Person(name→Nancy, age→18), Person(name→JackChan, age→23), Person(name→iFinder, age→19), Person(name→Nancy, age→18), Person(name→BobJoy, age→34)]

        //2.删除数据 .remove()  .clear()
        //hashSet.remove(new Person("iFinder",19));  重写方法后是能够通过这样的形式删除数据的

        //3.遍历
        //3.1 增强for
        //3.2迭代器
        Iterator<Person> it = hashSet.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }
        
        //4.判断  .contains()  .isEmpty()
        //hashSet.contains(new Person("Nancy",18));  重写方法后判断为真
    }
}

class Person {
    String name;
    int age;

    public Person() {
    }

    public Person(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 "Person(name→" + name + ", age→" + age + ")";
    }

    @Override
    public int hashCode() {
        int n1 = this.name.hashCode();
        int n2 = age;

        return n1+n2;
    }

    @Override
    public boolean equals(Object obj) {
        if(this == obj){
            return true;
        }
        if(obj == null){
            return false;
        }
        if(obj instanceof Person){
            Person pobj = (Person) obj;
            if(this.name.equals(pobj.name) && this.age == pobj.age){
                return true;
            }
        }
        return false;
    }
}

快速重写hashcode()和equals()方法的快捷键 Alt+Insert →equals()and hashcode()

重写hashcode()方法的说明

public static int hashCode(Object a[]) {
//为什么是31?
//①31是一个质数,这样会减少散列的冲突
//②31能够提高执行效率,31*i=(i<<5)-i
        if (a == null)
            return 0;

        int result = 1;

        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }

- TreeSet的使用

import java.util.Iterator;
import java.util.TreeSet;

/**
 * TreeSet 的使用
 * 存储结构:红黑树
 */
public class TreeSetTest1 {
    public static void main(String[] args) {
        //创建集合
        TreeSet<String> treeSet = new TreeSet<>();

        //1.添加元素  .add()
        treeSet.add("xyz");
        treeSet.add("abc");
        treeSet.add("iFinder");
        treeSet.add("Nancy");

        System.out.println("元素个数: " + treeSet.size());   //元素个数: 4
        System.out.println(treeSet.toString());  //[Nancy, abc, iFinder, xyz]  在输出的时候就已经默认进行排序了

        //2.删除元素  .remove()  .clear()

        //3.遍历元素
        //3.1 增强for循环
        //3.2迭代器
        Iterator<String> it = treeSet.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }

        //4.判断  .contains()  .isEmpty()
    }
}
import java.util.HashSet;
import java.util.Iterator;
import java.util.TreeSet;

public class TreeSetTest2 {
    public static void main(String[] args) {
        //创建集合
        TreeSet<Person1> treeSet = new TreeSet<>();

        //1.添加数据
        Person1 p1 = new Person1("iFinder",19);
        Person1 p2 = new Person1("Nancy",18);
        Person1 p3 = new Person1("BobJoy",34);
        Person1 p4 = new Person1("JackChan",23);

        //直接添加会报错,需要让Person1类实现Comparable接口
        //当CompareTo()方法的返回值为0,则认为是重复元素
        //Person1 cannot be cast to class java.lang.Comparable
        treeSet.add(p1);
        treeSet.add(p2);
        treeSet.add(p3);
        treeSet.add(p4);

        System.out.println(treeSet.toString());  //[Person(name→BobJoy, age→34), Person(name→JackChan, age→23), Person(name→Nancy, age→18), Person(name→iFinder, age→19)]

        //2.删除  .remove()  .clear()
        //treeSet.remove(new Person1("Nancy",18));  重写compareTo方法后可以实现删除

        //3.遍历
        //3.1 增强for循环
        //3.2迭代器
        Iterator<Person1> it = treeSet.iterator();
        while(it.hasNext()){
            System.out.println(it.next());
        }

        //4.判断  .contains()  .isEmpty()
    }
}

class Person1 implements Comparable<Person1>{
    String name;
    int age;
    public Person1() {}
    public Person1(String name, int age) {...}
    
    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
    @Override
    public String toString() {
        return "Person(name→" + name + ", age→" + age + ")";
    }
    @Override
    public int compareTo(Person1 o) {
        //1.先按姓名进行比较
        int n1 = this.getName().compareTo(o.getName());
        int n2 = this.age - o.getAge();
        return n1 == 0 ? n2 : n1;   //如果姓名一样,返回年龄结果,如果年龄一样,返回姓名结果
    }
}

Comparator接口

import java.util.Comparator;
import java.util.TreeSet;

/**
 * TreeSet集合补充 Comparator接口
 * Comparator:实现定制的比较(比较器)
 * Comparable:可比较的接口
 */
public class ComparatorInterface {
    public static void main(String[] args) {
        //创建集合,并指定一个比较的规则
        TreeSet<Person2> treeSet = new TreeSet<>(new Comparator<Person2>() {
            @Override
            public int compare(Person2 o1, Person2 o2) {
                int n1 = o1.getAge() - o2.getAge();
                int n2 = o1.getName().compareTo(o2.getName());
                return n1 == 0 ? n2 : n1;
            }
        });

        Person2 p1 = new Person2("iFinder",23);
        Person2 p2 = new Person2("Nancy",18);
        Person2 p3 = new Person2("Jacky",25);

        //因为已经指定了比较的规则所以添加时不会报错
        treeSet.add(p1);
        treeSet.add(p2);
        treeSet.add(p3);
        System.out.println(treeSet.toString());

    }
}

class Person2 {
    String name;
    int age;
    public Person2() {  }
    public Person2(String name, int age) {...}

    public String getName() {...}
    public void setName(String name) {...}
    public int getAge() {...}
    public void setAge(int age) {...}
    @Override
    public String toString() {...}
}

- TreeSet案例

需求:使用TreeSet集合使字符串按长度排序

import java.util.Comparator;
import java.util.TreeSet;

/**
 * 需求:使用TreeSet集合使字符串按长度排序
 */
public class TreeSetTest3 {
    public static void main(String[] args) {
        
        //创建集合并指定比较规则
        TreeSet<String> str = new TreeSet<>(new Comparator<String>() {
            @Override
            public int compare(String o1, String o2) {
                int n1 = o1.length() - o2.length();
                int n2 = o1.compareTo(o2);

                return n1 == 0 ? n2 : n1;   //优先比较长度,长度相同比较字典表
            }
        });
        
        //添加数据
        str.add("Huawei mate40");
        str.add("iPhone 11");
        str.add("Xiaomi 11S");
        str.add("MeiZu 11pro");
        str.add("NuBia N30");
        
        //输出
        String s = str.toString();
        System.out.println(s);
    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值