一.泛型深入:
集合的泛型如果用基本数据类型的话要用包装类,如int要用Integer
二.介绍没有泛型的时候,集合如何存储数据:
下拉框的第一个提示的Object e代表可以添加任意类型的数据
javabean类:
package com.itheima.a04mygenerics;
class Student {
private String name;
private int age;
//构造
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
//set/get
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;
}
//
public String toString() {
return "Student{name = " + name + ", age = " + age + "}";
}
}
测试类里:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericsDemo1 {
public static void main(String[] args) {
//1.创建集合的对象
ArrayList list=new ArrayList<>();
//2.添加数据
list.add(123);
list.add("aaa");
list.add(new Student("zhangsan",123));
//3.遍历集合获取里面的每一个元素
Iterator it = list.iterator();
while (it.hasNext()){
Object obj=it.next();//此时没有泛型,所有元素都提升为Object型
System.out.println(obj);
}
/*运行结果为123
aaa
Student{name = zhangsan, age = 123}
*/
}
}
结论:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
import java.util.Iterator;
public class GenericsDemo1 {
public static void main(String[] args) {
/* 结论:
如果没有给集合指定类型,默认所有的数据类型都是Object类型
此时可以往集合添加任意类型的数据
弊端:在获取数据的时候-->无法使用他的特有行为
因此有了泛型,可以在添加数据的时候就把数据类型进行统一。
在获取数据的时候也无需强制转换了
*/
//1.创建集合的对象
ArrayList list=new ArrayList<>();
//2.添加数据
list.add(123);
list.add("aaa");
list.add(new Student("zhangsan",123));
//3.遍历集合获取里面的每一个元素
Iterator it = list.iterator();
while (it.hasNext()){
Object obj=it.next();//此时没有泛型,所有元素都提升为Object型
/* Object型为基(最大父)类,但多态有一个弊端,即
不能访问子类特有的功能
所有obj不能调用整型,字符串型,Student型的特有功能
而且还不能强制转换类型
比如强制转换为Student型,123和"aaa"就不行了
*/
System.out.println(obj);
}
/*运行结果为123
aaa
Student{name = zhangsan, age = 123}
*/
}
}
三.泛型的好处:
四.扩展:
当集合指定泛型后,如添加一个数据并添加成功-->在集合里还是会默认升为Object型-->当出集合会强制转换回来初始类型
代码的体现:
当编写Java文件时,Java文件里真正存在泛型-->当Java文件编写为.class即字节码文件后泛型会消失(泛型的擦除)
五.泛型的细节:
1.泛型中不能写基本数据类型:
因为基本数据类型不能转为Object型-->因此要把基本数据类型转换为包装类才行
2.指定泛型的具体类型后,传递数据时,可以传入该类类型或者其子类类型;
3.如果不写泛型,类型默认是Object。
六.泛型类:
实例:
package com.itheima.a04mygenerics;
import java.util.Arrays;
/*
在编写一个类时,如果不确定类型,那么这个类就可以定义为泛型类
本例中E是用来记录数据类型的,比如E可以是String型,Integer型等
*/
public class MyArrayList<E> { //E代表定义了一个不确定的类型,之后就可以用这个类型
//左侧边框类显示的还是MyArrayList,这个没啥影响
//ArrayList源码底层是Object型的数组,因此定义一个数组
Object[] obj=new Object[10];
//定义一个变量用来记录存了几个元素
//size为全局变量,初始值默认为0
int size;
public MyArrayList() {
}
public MyArrayList(Object[] obj, int size) {
this.obj = obj;
this.size = size;
}
//定义一个方法,用来添加元素
//由于不知道存入的数据的类型,因此把形参定义为和类一样的泛型
//E是不确定的数据类型,该类型在类名后面就已经定义过了;e为变量名(形参的名字)
public boolean add(E e){
//把元素添加到obj数组中
obj[size]=e;//第一次时size为0(因为size为全局变量,第一次默认为0)
size++;
//return true表示添加成功
return true;
}
//定义一个方法,用来获取元素
//返回值类型不是Object型,而是这个不确定的类型E
public E get(int index){
//返回数组obj中index索引上的元素
//不是return obj[index];-->因为此时返回值类型为Object,而返回值类型为E,因此要强制转换类型
return (E) obj[index];
}
//重写顶级父类Object的toString方法,为了打印属性,而不是地址值
public String toString() {
//return Arrays.toString(obj);代表把数组里的元素拼接为字符串并返回
return Arrays.toString(obj);
}
}
实现类1:
package com.itheima.a04mygenerics;
public class GenericsDemo2 {
public static void main(String[] args) {
//注:如果类名后带有泛型,那么创建对象时就必须传递类型
MyArrayList<String> list=new MyArrayList<>();
//此时类MyArrayList<E>里的E就记录的String型
list.add("aaa");
list.add("bbb");
list.add("ccc");
System.out.println(list);
/*运行结果为[aaa, bbb, ccc, null, null, null, null, null, null, null]
类MyArrayList里的数组长度为10,本例只添加了三个元素,剩下的用默认值null
*/
}
}
实现类2:
package com.itheima.a04mygenerics;
public class GenericsDemo2 {
public static void main(String[] args) {
MyArrayList<Integer> list=new MyArrayList<>();
list.add(123);
list.add(456);
list.add(789);
int i = list.get(0);
/* Integer i = list.get(0);和
int i = list.get(0);都行,因为Java中有自动装箱和自动拆箱的功能
*/
System.out.println(i);//运行结果为123
System.out.println(list);//运行结果为[123, 456, 789, null, null, null, null, null, null, null]
}
}
注:本例中一定要指定泛型E的类型,不然就默认为Object型。
七.泛型方法:
1.当方法形参类型不确定时:
解决方案1:使用类名后面定义的泛型-->所有方法都能用
如果所有方法数据类型都不确定,建议用泛型类
解决方案2:在方法申明上定义自己的泛型-->只有本方法能用
如果只是某个方法中出现了不确定的数据类型,建议用泛型方法
2.泛型方法定义格式:
3.实例:
题目:
解:
工具类:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class ListUtil {
//对于工具类最好私有化构造方法,不让外界创建它的对象
public ListUtil(){}
/*形参需要要添加的集合的元素,因此还需要集合*/
//addAll方法-->添加的元素的类型不确定,因此可以定义为泛型方法,也可以定义为泛型类
public static<E> void addAll(ArrayList<E> list,E e1,E e2,E e3,E e4){ //也可写为public static <E>void addAll
//public和static均为修饰符
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
}
}
测试类:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class GenericsDemo3 {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
//指定了泛型为String型,因此list只能操作String型
ListUtil.addAll(list,"aaa","bbb","ccc","ddd");
System.out.println(list);//运行结果为[aaa, bbb, ccc, ddd]
}
}
工具类优化-->可以添加任意个元素:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class ListUtil {
//对于工具类最好私有化构造方法,不让外界创建它的对象
public ListUtil(){}
/*形参需要要添加的集合的元素,因此还需要集合*/
//addAll方法-->添加的元素的类型不确定,因此可以定义为泛型方法,也可以定义为泛型类
public static<E> void addAll(ArrayList<E> list,E e1,E e2,E e3,E e4){ //也可写为public static <E>void addAll
//public和static均为修饰符
list.add(e1);
list.add(e2);
list.add(e3);
list.add(e4);
}
public static<E> void addAll2(ArrayList<E> list,E...e){ //可以添加任意个元素
//E...e(有三个.)-->叫可变参数,底层是数组
for (E element : e) {
list.add(element);
}
}
}
测试类:
package com.itheima.a04mygenerics;
import java.util.ArrayList;
public class GenericsDemo3 {
public static void main(String[] args) {
ArrayList<String> list=new ArrayList<>();
//指定了泛型为String型,因此list只能操作String型
ListUtil.addAll2(list,"aaa","bbb","ccc","ddd","eee","a","b");
System.out.println(list);//运行结果为[aaa, bbb, ccc, ddd, eee, a, b]
}
}
八.泛型接口:
当接口中数据类型不确定时,可以定义为泛型接口。
第一种使用方式:实现类给出具体数据类型(该实现类不是接口)-->实现类确定类型时用
实现类:
package com.itheima.a04mygenerics;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class MyArrayList2 implements List<String> {
//List<String>代表集合中只能存String型数据-->因此重写的add方法只能操作String型
//List中有很多方法需要重写,可以根据报错提示进行快速改正
@Override
public boolean add(String s) {
return false;
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<String> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(T[] a) {
return null;
}
@Override
public boolean remove(Object o) {
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends String> c) {
return false;
}
@Override
public boolean addAll(int index, Collection<? extends String> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public String get(int index) {
return null;
}
@Override
public String set(int index, String element) {
return null;
}
@Override
public void add(int index, String element) {
}
@Override
public String remove(int index) {
return null;
}
@Override
public int indexOf(Object o) {
return 0;
}
@Override
public int lastIndexOf(Object o) {
return 0;
}
@Override
public ListIterator<String> listIterator() {
return null;
}
@Override
public ListIterator<String> listIterator(int index) {
return null;
}
@Override
public List<String> subList(int fromIndex, int toIndex) {
return null;
}
}
测试类:
package com.itheima.a04mygenerics;
public class GenericsDemo4 {
public static void main(String[] args) {
//泛型接口的第一种使用方式:实现类给出具体的类型
//创建对象时不用写泛型,因为接口中后面没指定,而且存储的数据类型也已经固定了
MyArrayList2 list1=new MyArrayList2();
list1.add("abc");
System.out.println(list1);
}
}
第二种使用方式:实现类延续泛型,创建实现类对象后再确定类型-->实现类不确定类型时用
实现类:
package com.itheima.a04mygenerics;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public class MyArrayList3<E> implements List<E>{ //List<E>,不是List<E e>
//泛型类带有泛型接口
//比如add方法,形参类型就是不确定的数据类型
@Override
public boolean add(E e) {
return false;
}
@Override
public int size() {
return 0;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public boolean contains(Object o) {
return false;
}
@Override
public Iterator<E> iterator() {
return null;
}
@Override
public Object[] toArray() {
return new Object[0];
}
@Override
public <T> T[] toArray(T[] a) {
return null;
}
@Override
public boolean remove(Object o) {
return false;
}
@Override
public boolean containsAll(Collection<?> c) {
return false;
}
@Override
public boolean addAll(Collection<? extends E> c) {
return false;
}
@Override
public boolean addAll(int index, Collection<? extends E> c) {
return false;
}
@Override
public boolean removeAll(Collection<?> c) {
return false;
}
@Override
public boolean retainAll(Collection<?> c) {
return false;
}
@Override
public void clear() {
}
@Override
public E get(int index) {
return null;
}
@Override
public E set(int index, E element) {
return null;
}
@Override
public void add(int index, E element) {
}
@Override
public E remove(int index) {
return null;
}
@Override
public int indexOf(Object o) {
return 0;
}
@Override
public int lastIndexOf(Object o) {
return 0;
}
@Override
public ListIterator<E> listIterator() {
return null;
}
@Override
public ListIterator<E> listIterator(int index) {
return null;
}
@Override
public List<E> subList(int fromIndex, int toIndex) {
return null;
}
}
测试类:
package com.itheima.a04mygenerics;
public class GenericsDemo4 {
public static void main(String[] args) {
//泛型接口的第二种使用方式:实现类延续泛型,创建实现类对象后再确定类型
//创建对象时必须要给出数据类型,因为接口中是不确定数据类型
MyArrayList3<String> list=new MyArrayList3<>();
list.add("aaa");
System.out.println(list);
}
}