【java】25:泛型

本文介绍了Java泛型的概念,包括其在解决类型安全、提高效率、编译时检查等方面的优势,展示了泛型的声明、实例化和使用示例,以及自定义泛型和通配符的运用。
摘要由CSDN通过智能技术生成

传统方法的问题:

1)不能对加入到集合 ArrayList中的数据类型进行约束(不安全)

2)遍历的时候,需要进行类型转换,如果集合中的数据量较大,对效率有影响

泛型引入:

public class Generic02 {
public static void main(String[] args) {
//使用传统的方法来解决===> 使用泛型
//解读
//1. 当我们 ArrayList<Dog> 表示存放到 ArrayList 集合中的元素是 Dog 类型 (细节后面说...)
//2. 如果编译器发现添加的类型,不满足要求,就会报错
//3. 在遍历的时候,可以直接取出 Dog 类型而不是 Object
//4. public class ArrayList<E> {} E 称为泛型,那么 Dog->E
ArrayList<Dog> arrayList = new ArrayList<Dog>();
arrayList.add(new Dog("旺财", 10));
arrayList.add(new Dog("发财", 1));
arrayList.add(new Dog("小黄", 5));
//假如我们的程序员,不小心,添加了一只猫
//arrayList.add(new Cat("招财猫", 8));
System.out.println("===使用泛型====");
for (Dog dog : arrayList) {
System.out.println(dog.getName() + "-" + dog.getAge());
}
}
}
/*
1.请编写程序,在 ArrayList 中,添加 3 个 Dog 对象
2.Dog 对象含有 name 和 age, 并输出 name 和 age (要求使用 getXxx())
3.使用泛型来完成代码
*/
class Dog {
private String name;
private int age;
public Dog(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;
}
}
class Cat { //Cat 类
private String name;
private int age;
public Cat(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;
}
}
泛型的好处:

1)编译时,检查添加元素的类型,提高了安全性

2)减少了类型转换的次数,提高效率[说明]√不使用泛型Dog-加入-> Object-取出-> Dog/放入到ArrayList会先转成Object,在取出时,还需要转换成Dog√使用泛型Dog->Dog->Dog//放入时,和取出时,不需要类型转换,提高效率

3)不再提示编译警告

泛型介绍:
int a = 10;
理解:泛(广泛)型(类型)=> Integer, String,Dog
1)泛型又称参数化类型,是Jdk5.0出现的新特性,解决数据类型的安全性问题
2)在类声明或实例化时只要指定好需要的具体的类型即可。
3)Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生ClassCastException异常。同时,代码更加简洁、健壮
4)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。[有点难,举例GenericO3.java]
public class Generic03 {
public static void main(String[] args) {
//注意,特别强调: E 具体的数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型
Person<String> person = new Person<String>("韩顺平教育");
person.show(); //String
/*
你可以这样理解,上面的 Person 类
class Person {
String s ;//E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E
是什么类型
public Person(String s) {//E 也可以是参数类型
this.s = s;
}
public String f() {//返回类型使用 E
return s;
}
}
*/
Person<Integer> person2 = new Person<Integer>(100);
person2.show();//Integer
/*
class Person {
Integer s ;//E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E
是什么类型
public Person(Integer s) {//E 也可以是参数类型
this.s = s;
}
public Integer f() {//返回类型使用 E
return s;
}
}
*/
}
}
//泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,
// 或者是某个方法的返回值的类型,或者是参数类型
class Person<E> {
E s ;//E 表示 s 的数据类型, 该数据类型在定义 Person 对象的时候指定,即在编译期间,就确定 E 是什么类型
public Person(E s) {//E 也可以是参数类型
this.s = s;
}
public E f() {//返回类型使用 E
return s;
}
public void show() {
System.out.println(s.getClass());//显示 s 的运行类型
}

}
泛型的语法:
1 泛型的声明:

interface接口<T>分和class类<K,V>分//比如:List,ArrayList说明:

1)其中,T,K,V不代表值,而是表示类型。

2)任意字母都可以。常用T表示,是Type的缩写

2 泛型的实例化:

要在类名后面指定类型参数的值(类型)。如:

1)List<String>strList=new ArrayList<String>(); [举例说明]

2) Iterator<Customer> iterator = customers.iterator();

3 泛型使用举例:
举例说明,泛型在HashSet,HashMap的使用情况,看演示GenericExercise.java10min练习:1.创建 3个学生对象
2.放入到HashSet中学生对象,使用.
3.放入到 HashMap中,要求Key 是String name,Value就是学生对象
4.使用两种方式遍历
public class GenericExercise {
public static void main(String[] args) {
//使用泛型方式给 HashSet 放入 3 个学生对象
HashSet<Student> students = new HashSet<Student>();
students.add(new Student("jack", 18));
students.add(new Student("tom", 28));
students.add(new Student("mary", 19));
//遍历
for (Student student : students) {
System.out.println(student);
}
//使用泛型方式给 HashMap 放入 3 个学生对象
//K -> String V->Student
HashMap<String, Student> hm = new HashMap<String, Student>();
/*
public class HashMap<K,V> {}
*/
hm.put("milan", new Student("milan", 38));
hm.put("smith", new Student("smith", 48));

hm.put("hsp", new Student("hsp", 28));
//迭代器 EntrySet
/*
public Set<Map.Entry<K,V>> entrySet() {
Set<Map.Entry<K,V>> es;
return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
}
*/
Set<Map.Entry<String, Student>> entries = hm.entrySet();
/*
public final Iterator<Map.Entry<K,V>> iterator() {
return new EntryIterator();
}
*/
Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
System.out.println("==============================");
while (iterator.hasNext()) {
Map.Entry<String, Student> next = iterator.next();
System.out.println(next.getKey() + "-" + next.getValue());
}
}
}
/**

* 创建 3 个学生对象
* 放入到 HashSet 中学生对象, 使用. * 放入到 HashMap 中,要求 Key 是 String name, Value 就是 学生对象
* 使用两种方式遍历
*/
class Student {
private String name;
private int age;
public Student(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 "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
泛型使用的注意事项和细节:
1. interface List<T>分, public class HashSet<E>.等等
说明:T,E只能是引用类型看看下面语句是否正确?:
List<Integer> list = new ArrayList<Integer> (); //OK
List<int> list2= new ArrayList<int>()://错误
2.在给泛型指定具体类型后,可以传入该类型或者其子类类型
3.泛型使用形式List<Integer> list1 = new ArrayList<Integer> ();List<Integer> list2 = new ArrayList<>();[说明:]
3.如果我们这样写 List list3=new ArrayList();默认给它的泛型是[<E>E就是Object]即
@SuppressWarnings({"all"})
public class GenericDetail {
public static void main(String[] args) {
//1.给泛型指向数据类型是,要求是引用类型,不能是基本数据类型
List<Integer> list = new ArrayList<Integer>(); //OK
//List<int> list2 = new ArrayList<int>();//错误
//2. 说明
//因为 E 指定了 A 类型, 构造器传入了 new A()
//在给泛型指定具体类型后,可以传入该类型或者其子类类型
Pig<A> aPig = new Pig<A>(new A());
aPig.f();
Pig<A> aPig2 = new Pig<A>(new B());
aPig2.f();
//3. 泛型的使用形式
ArrayList<Integer> list1 = new ArrayList<Integer>();
List<Integer> list2 = new ArrayList<Integer>();
//在实际开发中,我们往往简写
//编译器会进行类型推断, 老师推荐使用下面写法
ArrayList<Integer> list3 = new ArrayList<>();
List<Integer> list4 = new ArrayList<>();
ArrayList<Pig> pigs = new ArrayList<>();
//4. 如果是这样写 泛型默认是 Object
ArrayList arrayList = new ArrayList();//等价 ArrayList<Object> arrayList = new ArrayList<Object>();
/*
public boolean add(Object e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
*/
Tiger tiger = new Tiger();
/*
class Tiger {//类
Object e;
public Tiger() {}
public Tiger(Object e) {
this.e = e;
}
}

*/
}
}
class Tiger<E> {//类
E e;
public Tiger() {}
public Tiger(E e) {
this.e = e;
}
}
class A {}
class B extends A {}
class Pig<E> {//
E e;
public Pig(E e) {
this.e = e;
}
public void f() {

System.out.println(e.getClass()); //运行类型
}
}
自定义泛型:
1. 自定义泛型类 :
基本语法:
class类名<T,R...>{//...表示可以有多个泛型成员}
注意细节:
1)普通成员可以使用泛型(属性、方法)
2)使用泛型的数组,不能初始化
3)静态方法中不能使用类的泛型
4)泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型
5)如果在创建对象时,没有指定类型,默认为Object
2 自定义泛型接口:
>基本语法:
interface 接口名<T, R...>{}
>注意细节:
1)接口中,静态成员也不能使用泛型(这个和泛型类规定一样)
2)泛型接口的类型,在继承接口或者实现接口时确定
3)没有指定类型,默认为Object
泛型的继承和通配符:
1.泛型的继承和通配符说明:
1)泛型不具备继承性List<Object> list = new ArrayList<String>O;// 对吗?
2)<?>:支持任意泛型类型
3)<?extends A>:支持A类以及A类的子类,规定了泛型的上限
4)<? super A>:支持A类以及A类的父类,不限于直接父类,规定了泛型的下限

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值