sincerit java基础之泛型

本文深入探讨Java泛型的概念,解释其如何解决类型安全问题,避免强制类型转换带来的ClassCastException异常。通过实例说明泛型在集合、接口、类及方法中的应用,并介绍通配符的使用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先引入一个例子讨论
https://www.cnblogs.com/lwbqqyumidi/p/3837629.html

public class Test {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("qqyumidi");
        list.add("corn");
        list.add(100);   // 整型类
        for (int i = 0; i < list.size(); i++) {
            String name = (String) list.get(i); // 1
            System.out.println("name:" + name);
        }
    }
}

定义了一个List类型的集合,先向其中加入了两个字符串类型的值,随后加入一个Integer类型的值。这是完全允许的,因为此时list默认的类型为Object类型(集合不记录对象的类型都变成了object类型)。编译阶段正常,而运行时会出现“java.lang.ClassCastException”异常。
在出现这个异常的原因是什么呢? 第三个是整数类型但进行了强制类型转换,发生异常

在如上的编码过程中,我们发现主要存在两个问题:
1.当我们将一个对象放入集合中,集合不会记住此对象的类型,当再次从集合中取出此对象时,改对象的编译类型变成了Object类型,但其运行时类型任然为其本身类型。不使用泛型则要强制转换一下类型

2.因此,//1处取出集合元素时需要人为的强制类型转化到具体的目标类型,且很容易出现“java.lang.ClassCastException”异常。

那么有没有什么办法可以使集合能够记住集合内元素各类型,那就可以输出的时候不强制转换类型?
还记得学c++的时候,它有一个模板类T
template
class test {

}
模板函数
template
int compare(const T& left, const T& right) {
if (left < right) {
return -1;
}
if (right < left) {
return 1;
}
return 0;
}
compare(1, 2); //使用模板函数
只要写一个模板,再传递一个参数类型就可以实现很多种不同类型的方法
java就借鉴了这种模板的方法,搞出了一个泛型

泛型的意思是:参数化类型,即把类型当成一个参数,是可以传递的
当定义一个集合的时候传递一个类型的参数,那就相当于这个集合已经确定只能放这个类型的元素了
比如 ArrayList persons = new ArrayList();

除了可以泛型集合以外还可以泛型接口、泛型类和泛型方法

定义一个泛型接口
public interface Generator<T> {
  public T Test();
}
实现泛型接口
public class NumGenerator implements Generator<Integer> {
   public Integer Test() {
        .....
    }
   public static void main(String[] args) {
      NumGenerator num = new NumGenerator();
      .....;
   }
}

指定自定义的类型
public class NumGenerator implements Generator<Person> {
   public Person Test() {
        .....
    }
   public static void main(String[] args) {
      NumGenerator num = new NumGenerator();
      .....;
   }
}
定义一个泛型类--两个参数类型
class Person<K, V> {
  private K age;
  private V name;
  public K getAge() {
     return age;
  }
  public V setValue(V value) {
     name = value;
  }

public static void main(String[] args) {
      Person<String, String> person  = new Person<String, String>();
      .....;
   }

}
引用其他人写的,觉得不错:
定义泛型方法时,必须在返回值前边加一个<T>,来声明这是一个泛型方法,持有一个泛型T,然后才可以用泛型T作为方法的返回值。
  Class<T>的作用就是指明泛型的具体类型,而Class<T>类型的变量c,可以用来创建泛型类的对象。
  为什么要用变量c来创建对象呢?既然是泛型方法,就代表着我们不知道具体的类型是什么,也不知道构造方法如何,
  因此没有办法去new一个对象,但可以利用变量c的newInstance方法去创建对象,也就是利用反射创建对象。
  泛型方法要求的参数是Class<T>类型,而Class.forName()方法的返回值也是Class<T>,因此可以用Class.forName()作为参数。
  其中,forName()方法中的参数是何种类型,返回的Class<T>就是何种类型。在本例中,forName()方法中传入的是User类的完整路径,
  因此返回的是Class<User>类型的对象,因此调用泛型方法时,变量c的类型就是Class<User>,因此泛型方法中的泛型T就被指明为User,
  因此变量obj的类型为User。
  当然,泛型方法不是仅仅可以有一个参数Class<T>,可以根据需要添加其他参数。
为什么要使用泛型方法呢?因为泛型类要在实例化的时候就指明类型,
如果想换一种类型,不得不重新new一次,可能不够灵活;而泛型方法可以在调用的时候指明类型,更加灵活。

public <T> void func(List<T> list, T t) {
    list.add(t);
}

通配符?

现在引出一个问题?
如果有一个Fruit基类,其子类是Apple, Orange

public void print(ArrayList<Fruit> list) {
  for (Fruit e : list) {
     System.out.println(e);
 }
ArrayList<Apple> list = new ArrayList<Apple>;
list.add(new Apple());
list.add(new Orange());
}
当调用print()函数时会出错
Apple是Fruit的子类,为什么会出错呢
原因是虽然Apple是Fruit的子类
但ArrayList<Apple>却不是ArrayList<Fruit>的子类
实际上他们是没什么关系的,不能转型

那要怎么办呢
这样就可以了
public void print(ArrayList<? extends Fruit> list) {
  for (Fruit e : list) {
     System.out.println(e);
 }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值