泛型

1.泛型概述

泛型:是JDK5 中引入的特性,它提供了编译时类型安全检测机制,该机制允许在编译时检测到非法的类型,它的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数
一提到参数, 最熟悉的就是定义方法时由形参,然后调用此方法时传递实参,那么参数化类型怎么理解?
顾名思义, 就是将类型由原来的具体的类型参数化,然后使用/调用时传入具体的类型
这种参数类型可以用在类、方法和接口中,分别称为泛型类,泛型方法,泛型接口
泛型是一种参数的类型,可以将类或者具体的类型参数化,在使用过程中可以传入具体的类型

java形参和实参复习:
1.形参:用来接收调用该方法时传递的参数。
只有在被调用的时候才分配内存空间,一旦调用结束,就释放内存空间。因此仅仅在方法内有效。
public void swap(int a, int b) {
int temp = a;
a = b;
b = temp;
System.out.println(“a:” + a + “ b:” + b);
}
这里边的a,b就是形参,temp是一个局部变量,方法结束,在栈空间中就会被销毁
2.实参:传递给被调用方法的值,预先创建并赋予确定值。
1 调用上面的
2 swap(1,2);
3 其中1和2就是实际的参数值,就叫实参

泛型定义格式:

  1. 1. <类型>: 指定一种类型的格式。这里的类型可以看成是形参
  2. 1. <类型1,类型2>: 指定多种类型的格式,多种类型之间用逗号隔开。这里的类型可以看成是形参
  3. 1. 将来具体调用时给定的参数可以看成是实参,并且实参的类型只能是引用数据类型

泛型的好处:

  1. 1. 把运行时期的问题提前到了编译期间
  2. 1. 避免了强制类型转换

public class GenericDemo {
// 需求: Collection集合存储字符串并遍历
public static void main(_String[] args) {
// 创建集合对象
// Collection c = new ArrayList();
// 使用泛型可避免类型转换异常的隐形错误发生
Collection
<_String_> c = new ArrayList<>()_;

  1. // 添加元素,没有指定集合中类型的时候,默认引用类未object类型,因为所有类型都指向object类<br /> // 指定的object类,输入字符串或者整数都属于是向上转型,因为object是所有类的父类<br /> c.add_(_"hello"_)_;<br /> c.add_(_"world"_)_;<br /> c.add_(_"java"_)_;<br />// c.add(11); 使用泛型后,字符串类型提示整数类型报错
  2. // 使用Iterator遍历集合<br /> // Iterator it = c.iterator();<br /> // 使用带泛型的迭代器遍历,泛型和集合指定的类型是对应的<br /> Iterator_<_String_> _it = c.iterator_()_;<br /> while _(_it.hasNext_()){<br /> _/* 生成的类型不是String类型,是Object类型,因为添加object类型<br /> Object o = it.next();<br /> 将object父类向下转型称为String类<br /> 如果添加整形类将报错 ClassCastException 类型转换异常<br /> String s = (String) it.next();<br /> System.out.println(s); */<br /> String s = it.next_()_;<br /> System._out_.println_(_s_)_; _} } }_

2. 泛型类

泛型类的定义格式:
格式:修饰符 class 类名<类型>{ }
格式:public class Generic{ }
Tips: 类名中的表示是随便任意表示,常见的如T\E\K\V等形式的参数常用于表示泛型
// 定义一个教师类,里面有String类型的成员变量
public class Teacher {
_private int age;
public int getAge
() { return age; }
public void setAge(int age) { this.age = age; } }
————————————-
// 定义一个学生类,里面有String类型的成员变量
public class Student
{
private String name;
public String getName
() { return name; }
public void setName(String name) { this.name = name; } }
——————————————————————
// 创建一个T类型的成员变量,表示可以未任意变量
public class Generic
<_T_>{
private T t;
public T getT
() { return t; }
public void setT(T t) { this.t = t; } }
—————————————————
public class GenericDemo {
public static void main(String[] args) {
// 创建学生类,但是只能设置单一String类型变量
Student s = new Student
();
s.setName
(“李畅”);
System._out
.println(_s.getName());
// 创建教师类,但是只能设置单一int类型变量
Teacher t = new Teacher
();
t.setAge
(13);
System._out
.println(_t.getAge());
System._out
.println(“———————“);
// 创建泛型类,自定义String类型
Generic<_String> gs = new Generic<>();
gs.setT
(“赵明”);
System._out
.println(_gs.getT());
// 创建泛型类,自定义Integer类型
Generic
<_Integer_> gi = new Generic<>();
gi.setT
(23);
System._out
.println(_gi.getT());
System._out
.println(“———————“);
// 创建泛型类,自定义Boolean类型
Generic<_Boolean> gb = new Generic<>();
gb.setT
(true);
System._out
.println(_gb.getT());
// 创建泛型类,指定多个类型,不可行
// Generic generic = new Generic<>();
} }_

3. 泛型方法

泛型方法的定义格式
格式:修饰符<类型> 方法的返回值类型 方法名(类型 变量名){ }
实例:public void show(T t){ }
void :表示空类型(任意类型)
/ public class Generic {
// 该类中含有三个相同名,但是参数类型不同的方法— > 方法重载
public void show(String s){ System.out.println(s); }
public void show(Integer i){ System.out.println(i); }
public void show(Boolean b){ System.out.println(b); } }
/
/ 使用泛型类改进类中的方法
public class Generic{
public void show(T t){ System.out.println(t); } }
/
// 在main方法中调用本类方法,static方法需要加泛型
public static<_T> void play(T t){ System._out.println(_t); }
// 创建一个类,其中带有泛型方法
public class Generic
{ public<_T_> void show(T t){ System._out.println(_t); } }
————————————————-
public class GenericDemo
{
public static void main(String[] args) {
/ Generic g = new Generic();
g.show(“李畅”);
g.show(23);
g.show(true);
Generic g = new Generic<>();
g.show(“李畅”);
Generic g1 = new Generic<>();
g1.show(23);
Generic g2 = new Generic<>();
g2.show(true);
/
// 调用泛型犯法,参数可以传递何类型
Generic g = new Generic
();
g.show
(“李畅”); // String
g.show
(11); // Integer
g.show
(true); // Boolean
g.show
(12.45); // Float } }_

4. 泛型接口

泛型接口的定义格式
格式:修饰符 interface 接口名<类型> { }
实例:public interface Generic{ }
// 泛型类接口
public interface Generic<_T> {
// 接口类的方法不能有方法体, 默认public abstract修饰
void show
(T t); }
———————————————————————-
// 定义一个接口的实现类GenericImpl 实现泛型接口类Generic
public class GenericImpl
<_T_> implements Generic<_T_>{
// 因为Generic接口类是抽象类, 所以实现类必须要重写Generic接口中的show()方法
@Override
public void show
(T t) { System._out.println(_t); } }
———————————————————————————-
/public class GenericDemo {
public static void main(String[] args) {
Generic generic = new GenericImpl<>();
generic.show(“李畅”);
generic.show(11);
}
}/
public class GenericDemo {
public static void main(String[] args) {
// 使用接口类的方法必须定义Generic接口类才能调用接口里面的方法
// 因为Generic借口类是抽象类无法直接实例,所以使用多态实例该接口类的实现类
Generic
<_String_> gs = new GenericImpl<>();
gs.show
(“李畅”);
Generic
<_Integer_> gi = new GenericImpl<>();
gi.show
(23); } }_

5. 类型通配符

为了表示各种类型List的父类, 可以使用类型通配符

  1. 1. **类型通配符<?>**
  2. 1. **List<?>: 表示元素类型未知的List , 它的元素可以匹配任何的类型**
  3. 1. **这种带通配符的List仅表示它是各种类型List的父类, 并不能把元素添加到其中**

该功能主要是用于限制泛型的类型<?>

如果说我们不希望List<?>是任何泛型List的父类
只希望它代表某一类泛型List的父类, 可以使用类型通配符的上限

  1. 1. 类型通配符上限:<? extends类型>
  2. 1. List<? extends Number>: 它表示的类型是Number或者其子类型
  3. 设置该类型的上限类型,就表示该类型只能是Number或者Number的子类型,不能超过Number类型<br />

除了可以使用类型通配符的上限,同样我们也可以指定类型通配符的下限

  1. 1. 类型通配符下限:<? super 类型>
  2. 1. List<? super Number>: 它表示的类型是Number或者其父类型

设置该类型的下限类型,就表示该类型只能是Number或者Number的父类型,不能低于Number类型
public class GenericDemo {
public static void main(String[] args) {
// 类型通配符: <?>
List
<_?_> l = new ArrayList<_Object_>();
List
<_?_> l1 = new ArrayList<_String_>();
List
<_?_> l2 = new ArrayList<_Integer_>();
// 类型通配符上限:<? extends类型>
/ 报错因为上限设置为Number,但是Object 是Number的父类,子类Integer是可以的
List<? extends Number> l3 = new ArrayList();/
List<_? extends Number_> l3 = new ArrayList<_Number_>();
List
<_? extends Number_> l4 = new ArrayList<_Integer_>();
// 类型通配符下限:<? super 类型
/ 报错因为下限设置为Number,子类Integer是不可以的,但是Object是Number的父类可以
List<? super Number> l3 = new ArrayList();
/
List
<_? super Number_> l5 = new ArrayList<_Object_>(); } }_

6. 可变参数

可变参数又称为参数个数可变, 用作方法的形参出现, 那么方法参数个数就是可变的了
格式: 修饰符 返回值类型 方法名(参数类型… 变量名){}
范例: public void sum(int…a){}

可变参数的注意事项:

  1. 1. 这里的可变参数 a 其实是一个数组
  2. 1. 如果一个方法有多个参数,包含可变参数,可变参数要放在最后

范例: public void sum(int b ,int…a){}
public class ArgsDemo {
_public static void main
(String[] args) {
System._out.println(sum(_10,20));
System._out
.println(sum(_10,20,30));
System._out
.println(sum(_10,20,30,40));
System._out
.println(sum(_10,20,30,40,20,50)); }
/ 因为main方法是static的,所以里面只能直接调用static类型的方法和属性。
非static类型的属性和变量只能通过所属类的对象来调用。
/
public static int sum
(int…a) {
// System.out.println(i); [I@1b6d3586 []表示i是一个数组,将元素封装在数组中
int sum = 0;
for
(int i: a){
sum += i; }
return sum; }
/ 如果方法中含有多个参数,定义的可变参数a应该放在固定参数b后面
因为可变参数已经将所有元素封装在数组中,所有固定参数没有参数将会报错
public static int sum(int b,int…a) { return 0; }
/
/ public static int sum(int a, int b, int c) { return a + b + c; }
public static int sum(int a, int b, int c, int d) { return a + b + c + d; }
/
}_

7. 可变参数的使用

  1. 1. Arrays工具类中有一个静态方法:
  2. public static <T> List<T> asList(T...a): 返回由指定数支持的固定大小的列表<br />返回的集合不能做增删操作,可以做修改操作
  3. 2. List接口中有一个静态方法:
  4. public static<E> List<E> of(E...elements): 返回包含任意数量的不可变列表<br />返回的集合不能做增删改操作
  5. 3. Set接口中有一个静态方法:
  6. public static<E> Set<E> of(E...elements): 返回一个包含任意数量元素的不可变集合<br /> 在给元素的时候, 不能给重复的元素<br /> 返回的集合不能做增删操作,没有修改的方法<br />代码演示:<br />/* Arrays工具类中有一个静态方法:<br /> public static <T> List<T> asList(T...a): 返回由指定数支持的固定大小的列表*/<br /> List_<_String_> _list = Arrays._asList(_"hello", "world", "java"_)_;<br /> // list.add("javaee"); UnsupportedOperationException 不支持该操作<br /> // list.remove("java"); UnsupportedOperationException 不支持该操作<br /> // list的add()以及remove()方法是改变集合的大小,但是set()方法不改变所以可以执行<br /> list.set_(_1,"javaee"_)_; // [hello, javaee, java]<br /> System._out_.println_(_list_)_;

/ List接口中有一个静态方法:
public static List of(E…elements): 返回包含任意数量的不可变列表
/
List<_String> list = List.of(“hello”, “world”, “java”);
list.add
(“javaee”); UnsupportedOperationException 不支持该操作
list.remove
(“java”); UnsupportedOperationException 不支持该操作
list.set
(1,”javaee”)_; UnsupportedOperationException 不支持该操作
// 所以List.of() 方法对于元素中的操作不能增删改

/ Set接口中有一个静态方法:
public static Set of(E…elements): 返回一个包含任意数量元素的不可变集合
/
Set<_String> set = Set.of(“hello”, “world”, “java”,”world”); 报错因为Set集合不能有重复元素
set.add
(“javaee”); UnsupportedOperationException 不支持该操作
set.remove
(“java”)_; UnsupportedOperationException 不支持该操作