一、泛型的引入
直接举例:
package generic;
import java.util.ArrayList;
public class Generic_01 {
public static void main(String[] args) {
//使用传统的方式解决
ArrayList arrayList = new ArrayList();
arrayList.add(new People("sxp",20));
arrayList.add(new People("wy",18));
arrayList.add(new People("scy",21));
//如果不小心添加一个Dog类在ArrayList中就会出现问题
// arrayList.add(new Dog("小黄",2));
for (Object obj:arrayList){
People O=(People) obj;
System.out.println(O.getName()+" - "+O.getAge());
}
}
}
class People{
private String name;
private int age;
public People(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
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 int getAge() {
return age;
}
}
输出结果:
sxp - 20
wy - 18
scy - 21
注意
上面方法中存在2个问题:
1、不能对加入到集合ArrayList
中的数据类型进行约束(不安全)
2、遍历的时候,需要进行类型的转换,如果集合中的数据量较大,对效率有影响
例如:
package generic;
import java.util.ArrayList;
public class generic_02 {
public static void main(String[] args) {
//使用泛型
ArrayList<People1> arrayList = new ArrayList<People1>();
arrayList.add(new People1("sxp",20));
arrayList.add(new People1("wy",18));
arrayList.add(new People1("scy",21));
//1、当我们ArrayList<People1>表示存放到ArrayList集合中的元素是People1类型
//2、如果编译器发现添加的类型,不满足要求就会报错
//3、在遍历的时候可以直接取出People1类型而不是Object
for (People1 p:arrayList){
System.out.println(p.getName()+" - "+p.getAge());
}
}
}
class People1{
private String name;
private int age;
public People1(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
class Dog1{
private String name;
private int age;
public Dog1(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
输出结果:
sxp - 20
wy - 18
scy - 21
总结
1、不使用泛型:某类型数据直接添加入集合中,取得时候先要转换成Object,再向下转型成该类型类型
2、使用泛型:放入时和取出不需要进行类型转换,提高了效率
二、泛型介绍
1、泛型又称参数化类型,是JDK5.0出现的新特性,解决数据类型的安全性问题
2、在类声明或实例化时只要指定好需要的具体的类型即可
3、Java泛型可以保证如果程序在编译时没有发出警告,运行时就不会产ClassCastException
异常,同时,代码更加简洁、健壮
4、泛型作用:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值类型,或者时参数类型。
例如:
package generic;
public class Generic_03 {
public static void main(String[] args) {
Cat<String> stringCat = new Cat<String>("小黄");
stringCat.f1();
Cat<Integer> stringCat1 = new Cat<Integer>(5);
stringCat1.f1();
}
}
//E表示s的数据类型,该数据类型在定义Cat对象的时候指定
//即在编译期间,就确定E的类型
class Cat<E>{
E s;
public Cat(E s) {
this.s = s;
}
public E f(){
return s;
}
public void f1(){
System.out.println(s.getClass());
}
}
输出结果:
class java.lang.String
class java.lang.Integer
三、泛型的语法
1、泛型的声明
interface 接口< T >{}
和class类< K,V >{}
- 其中,T、K、V不代表值,而是表示类型
- 意字母都可以,常用T表示,是Type的缩写
2、泛型的实例化
要在类名后面指定类型参数的值(类型)如:
ArrayList< String >str=new ArrayList< String >();
Iterator< man > iterator=man.iterator();
例如:
package generic;
import java.util.*;
public class Generic_04 {
@SuppressWarnings({"all"})
public static void main(String[] args) {
HashSet<Student> students = new HashSet<Student>();
students.add(new Student("sls",10));
students.add(new Student("scy",17));
students.add(new Student("wy",19));
for ( Student stu:students){
System.out.print(stu.getName()+" _ "+stu.getAge()+" ");
}
System.out.println();
//迭代器
HashMap<String,Student> student1 = new HashMap<String,Student>();
student1.put("no1",new Student("sls",10));
student1.put("no2",new Student("scy",17));
student1.put("no3",new Student("wy",19));
Set<Map.Entry<String, Student>> entries = student1.entrySet();
Iterator<Map.Entry<String, Student>> iterator = entries.iterator();
while (iterator.hasNext()) {
Map.Entry<String, Student> next = iterator.next();
System.out.print(next.getKey()+" : "+next.getValue().getName()+" _ "+next.getValue().getAge()+" ");
}
System.out.println();
}
}
class Student{
private String name;
private int age;
public Student(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public int getAge() {
return age;
}
}
输出结果:
scy _ 17 sls _ 10 wy _ 19
no2 : scy _ 17 no1 : sls _ 10 no3 : wy _ 19
注意
1、interface List < T >{}
, public class HashSet< E >{}等等中T,E只能是引用类型
List<integer> list1 = new ArrayList<Integer>(); // 正确
List<int> list2=new ArrayList< int >(); //不正确
2、在指定泛型具体类型后,可以传入该类型或者其子类型
3、泛型的使用:
List<integer> list1 = new ArrayList<Integer>();
List<Integer> list2=new ArrayList< >(); //编译器会进行类型推断
4、如果写成List list = new ArrayList();
就是默认泛型其中< E >
E为object类型
例如:
package generic;
public class Generic_05 {
public static void main(String[] args) {
Bee<Animal> animalBee = new Bee<Animal>(new Animal());
animalBee.func();
Bee<Animal> animalBee1 = new Bee<Animal>(new Pig());
animalBee1.func();
}
}
class Animal{}
class Pig extends Animal{}
class Bee<E>{
E e;
public Bee(E e) {
this.e = e;
}
public void func(){
System.out.println(e.getClass());
}
}
输出结果:
class generic.Animal
class generic.Pig
四、自定义泛型
1、自定义泛型类
基本语法
class 类名<T,R...>{
成员
}
注意
1、普通成员可以使用泛型(属性、方法)
2、使用泛型的数组,不能初始化
3、静态方法中不能使用类的泛型(因为静态是和类相关的,在类加载时,对象还没有创建。如果静态方法和属性使用了泛型,JVM就无法完成初始化)
4、泛型类的类型,是在创建对象时确定的(因为创建对象时,需要制定确定类型)
5、如果在创建对象时,没有指定类型,默认为Object
例如:
package generic;
public class Generic_06 {
public static void main(String[] args) {
Monkey<Double,String,Integer> monkey = new Monkey<>("Tom");
monkey.setAge(17.2);
monkey.setHigh("110");
monkey.setWeight(122);
System.out.println(monkey.name);
System.out.println(monkey);
Monkey monkey1 = new Monkey("Jion");
monkey1.setWeight("12122");
System.out.println(monkey1);
}
}
// 自定义泛型
// T,R,M : 泛型的标识符 一般时单个大写字母,可以有多个泛型标识符
class Monkey<T,R,M> {
String name;
T age;
R high;
M weight;
public Monkey(String name) {
this.name = name;
}
public Monkey(String name, T age, R high, M weight) {
this.name = name;
this.age = age;
this.high = high;
this.weight = weight;
}
public void setAge(T age) {
this.age = age;
}
public void setHigh(R high) {
this.high = high;
}
public void setWeight(M weight) {
this.weight = weight;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public T getAge() {
return age;
}
public R getHigh() {
return high;
}
public M getWeight() {
return weight;
}
@Override
public String toString() {
return "Monkey{" +
"name='" + name + '\'' +
", age=" + age +
", high=" + high +
", weight=" + weight +
'}';
}
}
输出结果:
Tom
Monkey{name='Tom', age=17.2, high=110, weight=122}
Monkey{name='Jion', age=null, high=null, weight=12122}
2、自定义泛型接口
基本语法
interface 接口名<T,R...>{
}
注意
1、接口中静态成员也不能使用泛型(这个和泛型类规定一样)
2、泛型接口的类型,在继承接口或者实现接口时确定
3、没有指定类型,默认Object
例如
package generic;
public class Generic_07 {
public static void main(String[] args) {
}
}
interface inter<U,R> {
int n=10;
// U name;不能这样使用
R get(U u);
void func1(R r);
void func2(R r1,R r2 ,U u1);
default R method(U u){
return null;
}
}
interface outer extends inter<String,Double>{
}
//当实现outer接口时,因为outer在继承inter接口时,指定<U,R>为<String,Double>
// 在实现inter接口的方法时,使用<String,Double>替换为<U,R>
class ter implements outer{
@Override
public Double get(String s) {
return null;
}
@Override
public void func1(Double aDouble) {
}
@Override
public void func2(Double r1, Double r2, String u1) {
}
}
class AA implements inter<Integer,Float>{
@Override
public Float get(Integer integer) {
return null;
}
@Override
public void func1(Float aFloat) {
}
@Override
public void func2(Float r1, Float r2, Integer u1) {
}
}
//不推荐
//默认为<Object,Object>
class BB implements inter{
@Override
public Object get(Object o) {
return null;
}
@Override
public void func1(Object o) {
}
@Override
public void func2(Object r1, Object r2, Object u1) {
}
}
自定义泛型方法
基本语法
修饰符<T,R..>返回类型方法名(参数列表){
}
注意
1、泛型方法,可以定义在普通类中,也可以定义在泛型类中
2、当泛型方法被调用时,类型会确定
3、public void eat(E e){}
,修饰符后没有<T,R..>eat
方法不是泛型方法,而使用了类声明的泛型,泛型方法可以使用类声明的泛型,也可以使用自己声明泛型
例如:
package generic;
public class Generic_08 {
public static void main(String[] args) {
Car car = new Car();
car.func1("nihao",788);
Fish<String, Integer> objectObjectFish = new Fish<>();
objectObjectFish.func4("niahb",123.98);
}
}
//泛型方法可以定义在普通类中,也可以定义在泛型类中
class Car{
public void func(){
}
//<T,R>就是泛型标识符,是提供给fly使用的
public <T,R> void func1(T t,R r){
System.out.println(t.getClass());
System.out.println(r.getClass());
}
}
class Fish<T,R>{
public void func(){
}
public <U,M> void eat(U u,M m){
}
//不是泛型方法,,而是func1方法使用了声明的泛型
public void func1(T t){
}
public<K,k> void func4(T t,K k){
System.out.println(t.getClass());
System.out.println(k.getClass());
}
}
输出结果:
class java.lang.String
class java.lang.Integer
class java.lang.String
class java.lang.Double
泛型的继承和通配符
1、泛型不具备继承性
2、<?>
:支持任意泛型类型
3、<? extends A >
:支持A类以及A类的子类,规定了泛型的上限
4、<? super A>
:支持A类以及A类的父亲,不限于直接父类,规定了泛型的下限
例如:
package generic;
import java.util.ArrayList;
import java.util.List;
public class Generic_09{
public static void main(String[] args) {
Object o=new String("xxx");
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<FF1> list3 = new ArrayList<>();
List<FF2> list4 = new ArrayList<>();
List<FF3> list5 = new ArrayList<>();
// 如果是 List<?> c ,可以接受任意的泛型类型
printCollection(list1);
printCollection(list2);
printCollection(list3);
printCollection(list4);
printCollection(list5);
// printCollection1(list1); 报错
// printCollection1(list2); 报错
printCollection1(list3);
printCollection1(list4);
printCollection1(list5);
printCollection2(list1);
// printCollection2(list2); 报错
printCollection2(list3);
// printCollection2(list4); 报错
// printCollection2(list5); 报错
}
public static void printCollection(List<?> c){
for (Object object:c){
System.out.println(object);
}
}
//?extends FF1 :表示上限,可以接受FF1或者FF1子类
public static void printCollection1(List<? extends FF1> c){
for (Object object:c){
System.out.println(object);
}
}
//? super FF1 子类类名FF1: 支持FF1类以及FF1类的父类,不限于直接父类
public static void printCollection2(List<? super FF1> c){
for (Object object:c){
System.out.println(object);
}
}
}
class FF1{
}
class FF2 extends FF1{
}
class FF3 extends FF1{
}