1、解决的问题
类型安全问题。当不使用泛型时,会造成任意类型的数据都可以存储到集合中,当取出元素时,会涉及到造型的问题,比较繁琐。
2、自定义泛型类
package com.hike.javase.generic;
import org.junit.Test;
class person<T>{ //T表示某种类型,T称为泛型的类型参数(是一个形参)
//T类型的真实类型会在创建对象时确定下来,隶属于对象的存在而存在
//在静态方法中不可以使用泛型类中的泛型,因为静态方法隶属于类
private String name;
private T info;
public person(String name, T info) {
this.name = name;
this.info = info;
}
public person() {
}
public String getName() {
return name;
}
public T getInfo() {
return info;
}
public void setName(String name) {
this.name = name;
}
public void setInfo(T info) {
this.info = info;
}
@Override
public String toString() {
return "person{" +
"name='" + name + '\'' +
", info=" + info +
'}';
}
}
public class GenericTest {
@Test
public void test(){
//使用泛型后,类型就安全了
person<Integer> p1 = new person<Integer>("张三", 20);
//获取到的属性也清晰了
Integer info1 = p1.getInfo();
person<Boolean> p2 = new person<Boolean>("李四", true);
Boolean info2 = p2.getInfo();
person p3 = new person("王五", 5.36);
Object info3 = p3.getInfo();
}
}
3、泛型和继承的关系
class B1 extends A{} //子类中没有处理父类的泛型,泛型类型就是Object,不推荐
class B2 extends A<Integer>{} //子类在继承时,把父类的泛型确定下来了,使用起来最简单
class B3 extends A<person>{} //在创建子类对象后,其泛型时固定的
class B4<T> extends A<T>{} //子类在继承时仍然继续使用泛型,用起来最灵活
@Test
public void test1(){
B1 b1 = new B1();
Object t = b1.getT();
B2 b2 = new B2();
Integer t1 = b2.getT();
B3 b3 = new B3();
person t2 = b3.getT();
B4 b4 = new B4();
Object t3 = b4.getT();
String t4 = new B4<String>().getT();
Integer t5 = new B4<Integer>().getT();
}
4、泛型方法
class GenericMethod<T>{
public void test(T t){}
public <E> E get(E e){ //E表示只可以在此方法中使用的某种类型,在返回值之前加<>,并且必须传递参数,否则泛型在方法调用时无法确定下来
return null;
}
//泛型方法中必须传入泛型类型的参数,如果不传泛型永远无法确定
//泛型的类型由实参的类型来确定,所以它是和方法的某次调用相关
public static <E> E get1(E e){ //静态方法也适用
return null;
}
}
@Test
public void test2(){
String s = GenericMethod.get1("acf"); //泛型方法必须通过实参来告诉方法,泛型的具体类型是什么
Boolean b = GenericMethod.get1(false);
Object o = GenericMethod.get1(null); //如果实参是null,将会导致泛型类型无法感知
Integer i = GenericMethod.get1(200);
}
泛型方法的应用
@Test
public void test3(){
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; i++){
list.add((int)(Math.random() * 20));
}
Object[] objects = list.toArray(); //集合 --> 数组
//<T> T[] toArray(T[] a)
Integer[] integers = list.toArray(new Integer[]{}); //参数中必须传递一个数组对象,以便于方法在调用时能够感知到数组的类型
for(Integer integer : integers){
System.out.println(integer);
}
}
5、泛型通配符
通配符<?>
@Test
public void test4(){
List<Integer> list = new ArrayList<>();
for(int i = 0; i < 10; i++){
list.add((int)(Math.random() * 20));
}
List<?> list2 = list; //泛型通配符<?>,list2中可以添加任意位置类型对象
list2.add(null); //只能添加没有类型信息的对象
Object o = list2.get(0);//可以获取,但是类型最模糊
}
主要用途:写通用的方法,使得方法的参数有更好的兼容性,例如不同类型集合的遍历
public void travel(List<?> list){
for(Object object : list){
System.out.println(object);
}
}
@Test
public void test5() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add((int) (Math.random() * 20));
}
travel(list);
List<Double> list1 = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list1.add(Math.random() * 20);
}
travel(list1);
}
通配符<? super Number>
@Test
public void test6(){
//list中可以保存的是Number和其未知父类的对象
List<? super Number> list = null;
//list.add(38); //可以添加元素
list.add(43.2);
Object object = list.get(0); //获取到的元素是最模糊的
}
通配符<? extends Number>
//list中可以保存的是Number和其未知子类的对象
List<? extends Number> list1 = null;
list1.add(3); //不可以存放数据,因为是未知子类,不能确定是哪一个子类
Number number = list1.get(0); //可以获取元素
主要用途:写通用方法,例如通用求和
public double sum(List<? extends Number> list){
double sum = 0;
for(int i = 0; i < list.size(); i++){
sum += list.get(i).doubleValue();
}
return sum;
}
@Test
public void test7() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add((int) (Math.random() * 20));
}
System.out.println(sum(list));
List<Double> list1 = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list1.add(Math.random() * 20);
}
System.out.println(sum(list1));
}
通用求最大值方法
public Comparable max(Collection<? extends Comparable> col){
Iterator<? extends Comparable> iterator = col.iterator();
Comparable max = iterator.next();
while(iterator.hasNext()){
Comparable next = iterator.next();
if(next.compareTo(max) > 0){
max = next;
}
}
return max;
}
@Test
public void test8() {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list.add((int) (Math.random() * 20));
}
System.out.println(max(list));
List<Double> list1 = new ArrayList<>();
for (int i = 0; i < 10; i++) {
list1.add(Math.random() * 20);
}
System.out.println(max(list1));
HashSet<String> set = new HashSet<>();
set.add("jfdk");
set.add("aaa");
set.add("zzz");
System.out.println(max(set));
}