集合框架2
①泛型
- 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);
}
}