续上一节Java集合框架,Collection接口,List接口与实现类,依旧是Java集合的内容。
文章目录
4 泛型
- Java泛型是JDK1.5中引入的一个新特性,其本质是参数化类型,把类型作为参数传递。
在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型。
【类似于模板,先不定义类型,在使用时在限定类型。比如同一个泛型方法,可以用于整数和都浮点数运算】 - 这种参数类型可以用在类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
- 语法:
<T,...>
T称为类型占位符,表示一种引用类型。可以写多个参数,逗号隔开<T,K,E>
- 运用泛型的好处:
(1)提高代码的重用性
(2)防止类型转换异常,提高代码的安全性
4.1 泛型类
- 泛型类创建语法:
类名 <T>
- 可以创建变量
T t;
但是不能实例化T t1 = new T();
(有可能构造函数私有等原因) - 泛型只能使用引用类型【可以是Integer,不能是int】
- 不同泛型类型对象之间不能相互赋值。
package study.generic;
//定义泛型类语法:类名<T>
public class MyGenericClass<T> {
//1.使用泛型类创建成员变量
T t;
//T t2 = new T();//编译报错:类型参数'T'不能直接实例化
//2.作为方法形式参数
public void show(T t){
System.out.println("泛型参数:"+t);
}
//3.作为返回值
public T getT(){
return t;
}
}
4.2 泛型接口
- 泛型接口语法:
接口名<T>
- 不能泛型静态常量。
泛型接口:
package study.generic;
public interface MyGenericIn<T> {
// T t;//编译报错:不能从静态上下文引用
String name = "louis";
//接口只有规范,不写方法体
T service(T t);
}
泛型接口的两种实现类:
- 继续使用泛型
package study.generic;
public class InClass1<T> implements MyGenericIn<T> {
@Override//重写快捷键【Alt+Insert】
public T service(T t) {
return t;
}
}
- 在实现类中指定类型
package study.generic;
public class InClasses<String> implements MyGenericIn<String> {
@Override
public String service(String string) {
return string;
}
}
4.3 泛型方法
- 定义在普通类中,泛型方法的语法
修饰符 <T> 返回类型 方法名(T t)
普通类中的泛型方法:
package study.generic;
//普通类
public class GenMethodClass {
//泛型方法
public <T> void show(T t){
System.out.println("泛型方法" + t);
}
public <T> T show2(T t){
System.out.println("泛型方法" + t);
return t;
}
}
4.4 泛型集合
- 概念:参数化类型、类型安全的集合。强制集合元素的类型必须一致,可以避免强制类型转换时出错。
- 特点:
(1)编译时即可检查,而非运行时抛出异常
(2)访问时,不必类型转换(拆箱)
(3)不同泛型之间应用不能相互赋值,泛型不存在多态
普通集合:
泛型集合:
4.5 测试类
package study.generic;
import java.util.ArrayList;
public class mainGenericText {
public static void main(String[] args) {
System.out.println("1.泛型类");
MyGenericClass<String> c1 = new MyGenericClass<String>();
c1.t = "Hello,Java";
c1.show("Hello,World");
System.out.println(c1.getT());
MyGenericClass<Integer> c2 = new MyGenericClass<>();
c2.show(250);
// MyGenericClass<int> c3 = new MyGenericClass<int>();//编译报错:类型参数不能是原始类型
// c2 = c1;//不同类ing不能互相赋值
System.out.println("2.泛型接口的实现类调用");
//需要指名泛型类
InClass1<Integer> c3 = new InClass1<>();
System.out.println(c3.service(30));
//已定义好的接口实现类
InClasses<Object> c4 = new InClasses<>();
System.out.println(c4.service("Hello,Java"));
System.out.println("3.泛型方法");
GenMethodClass c5 = new GenMethodClass();
c5.show("Java");
System.out.println(c5.show2("Halo"));
System.out.println("4.泛型集合");
ArrayList<String> s1 = new ArrayList<>();
s1.add("Chanel");
s1.add("LV");
// s1.add(100);//编译报错
for(String s:s1){
System.out.println(s);
}
}
}
/*
1.泛型类
泛型参数:Hello,World
Hello,Java
泛型参数:250
2.泛型接口的实现类调用
30
Hello,Java
3.泛型方法
泛型方法Java
泛型方法Halo
Halo
4.泛型集合
Chanel
LV
*/
5 Set接口与实现类
- 特点:无序、无下标、元素不可重复
- 方法:全部继承自Collection中的方法。
增、删、遍历、判断完全一致。
构造方法因为实现类不同略有不同Set<String> s1 = new HashSet<>();
。 - 两种实现类:HashSet和TreeSet。
5.1 HashSet类
- 存储结构:哈希表(数组+链表+红黑树)
- 存储过程(怎么判断元素是否重复):
①根据hashCode方法计算保存的位置,如果位置为空,直接保存;
②若不为空,再执行equals方法,如果equals为true,则认为是重复,否则形成链表。
【对于自定义类,需要重写方法】例如Person类(属性名字、年龄)
- 特点
基于HashCode计算元素存放位置:
(1)利用31这个质数,减少散列冲突;
(2)提高执行效率。31*i=(i << 5)-i转为移位操作。
当存入元素的哈希码相同时,会调用equals进行确认,如果结果为true,则拒绝后者存入 - 方法(同Collection)
5.2 TreeSet类
- 存储结构:红黑树(二叉排序平衡)
- 创建集合:
TreeSet<String> treeSet = new TreeSet<>()
- 方法(添加、删除、遍历、判断同Collection)
- 特点:
(1)基于排列顺序实现元素不重复。
(2)实现SortedSet接口,对集合元素自动排序。
(3)元素对象的类型必须实现Comparable接口,指定排序规则。
(4)通过CompareTo方法确定是否为重复元素。
查源码知道,包类型都自动继承Comparable接口,并且Comparable接口里面只有一个方法CompareTo方法。 - TreeSet集合的使用方法(自定义排序规则)
(1)对象类型继承Comparable接口,重写CompareTo方法来制定排序规则。
(2)Comparator比较器实现定制比较.
5.2.1 Comparable接口
int compareTo(T o)
将此对象与指定的对象进行比较,返回一个负整数、零或一个正整数,因为这个对象小于、等于或大于指定的对象。
重写对象方法:
package generic;
public class Person implements Comparable<Person> {
String name;
int age;
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 int compareTo(Person o) {
int n1 = this.getName().compareTo(o.getName());
int n2 = this.getAge()-o.getAge();
return n1==0?n2:n1;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
创建集合并添加对象:
package generic;
import java.util.TreeSet;
public class TreeSetText {
public static void main(String[] args) {
//创建集合
TreeSet<Person> pe = new TreeSet<>();
//创建对象
Person p1 = new Person("Louis", 22);
Person p2 = new Person("LV", 20);
Person p3 = new Person("Chanel", 19);
//添加对象到集合
pe.add(p1);
pe.add(p2);
pe.add(p3);
pe.add(new Person("LV", 20));//因为重写了比较方法才可以判断出重复
System.out.println(pe.toString());
//删除对象
pe.remove(p1);
pe.remove(new Person("LV", 20));//因为重写了比较方法才可以判断出重复存在
System.out.println(pe.toString());
}
}
/*
[Person{name='Chanel', age=19}, Person{name='LV', age=20}, Person{name='Louis', age=22}]
[Person{name='Chanel', age=19}]
*/
5.2.2 Comparator比较器
Comparator实现定制比较(比较器),就可以不再需要实现Comparable接口比较功能。
package generic;
/*
要求:使用Treeset集合实现字符串按照长度进行排序
comparator接口实现定制比较
*/
import java.util.Comparator;
import java.util.TreeSet;
public class Demo01 {
public static void main(String[] args) {
//创建集合并使用comparator接口定制比较
TreeSet<String> ts = 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;//长度相等判断再是否一致
}
});
ts.add("Balenciaga");
ts.add("Chanel");
ts.add("Louis");
ts.add("Burberry");
System.out.println(ts);//[Louis, Chanel, Burberry, Balenciaga]
}
}