自定义泛型结构
泛型类的定义和实例化
- 泛型------>添加限制
/*
Demo01就是一个普通的类
Demo01<E>就是一个泛型类
<>里面就是一个参数类型,但是这个类型是什么呢?这个类型现在是不确定的,相当于一个占位
但是现在确定的是这个类型一定是一个引用数据类型
*/
public class Demo01<E> {
//属性
int age;
String name;
E sex;//E类型的sex-----<E>中类型确定,则E sex类型确定
//方法
public void a(E n){
}
public void b(E[] m){
}
}
class Test{
public static void main(String[] args) {
//在实例化Demo01时--->才会决定E的类型
//Demo01实例化
//1.实例化的时候不指定泛型:默认泛型为Object类型
Demo01 gt1 = new Demo01();//相当于<Object>
gt1.a("abc");//调用a方法
gt1.a(17);
gt1.a(9.8);
gt1.b(new String[]{"a","b","c"});//调用b方法,需要传入Object类型数组
//2.实例化时指定泛型
Demo01<String> gt2 = new Demo01<>();
gt2.sex = "男"; //sex属性变成String类型
gt2.a("abc");//只能传入String类型
gt2.b(new String[]{"a","b","c"});
}
继承情况
1.父类指定泛型
class SubDemo01 extends Demo01<Integer>{//SubDemo01继承Demo01--->其中父类指定了泛型
}
class Test{
public static void main(String[] args) {
//指定父类泛型,那么子类就不需要再指定泛型了,可以直接使用
SubDemo01 sgt = new SubDemo01();
sgt.a(19);//只能传Integer
}
}
2.父类不指定泛型
- 若父类不指定泛型,那么子类也会变成一个泛型类,那这个E的类型可以在创建子类对象的时候确定
class SubDemo01_2<E> extends Demo01<E>{
//SubDemo01_2继承Demo01--->其中父类未指定泛型
}
class Test{
public static void main(String[] args) {
//创建子类对象确定泛型
SubDemo01_2<String> s = new SubDemo01_2<>();
s.a("abc");//只能传入String类型
}
应用场合
- ArrayList实现就是运用泛型类,看懂API
- 泛型接口跟泛型类一样
细节
- 泛型类可以定义多个参数类型
//可以是多个参数类型
public class Demo02<A,B,C> {
A age;
B name;
C sex;
public void a(A m,B n, C x){
}
}
- 泛型类的构造器的写法
public class Demo02<A,B,C> {
public Demo02<A,B,C>(){
//构造器中不许加泛型
}
}
- 不同的泛型的引用类型不可以相互赋值
ArrayList
ArrayList
list1 = list2;
- 泛型如果不指定,那么就会被擦除,泛型对应的类型为Object类型
- 泛型类中的静态方法不能使用类的泛型:
public static int c(A a){
//静态方法是在类加载时存在--->优先于对象存在,但是创建对象时A的类型才被确定,故不能用静态方法
return 10;
}
- 不能直接使用E[]的创建:
public void a(A m,B n, C x){
A[] = new A[10];
}
泛型方法
- 什么是泛型方法
- 这个方法的泛型的参数类型要和当前的类的泛型无关
public class Demo03<E> {
public void a(E e){
//这个不是泛型方法
}
public <T> void b(T t){
//参数类型T 跟泛型类中的E 不同--->泛型方法
}
}
-
泛型方法定义的时候,前面要加上
- 原因:如果不加的话,会把T当作一种数据类型,然而代码中没有T类型那么就会报错
-
调用方法
- T的类型是在调用方法的时候确定的
public static void main(String[] args) {
Demo03<String> tg = new Demo03<>();
tg.b("abc");//T的类型在调用方法时才最终确定,故可以传任意类型
tg.b(19);
tg.b(true);
}
- 泛型方法可否是静态方法
- 可以是静态方法(静态方法优先于对象加载,没有对象是时静态方法随着类一起加载)
- T的确定是随着方法的调用而确定,故可以是静态
public class Demo03<E> {
public /*static*/ void a(E e){
//这个不是泛型方法
//不能是静态方法,E是随着对象确定才确定
}
public static <T> void b(T t){
//参数类型T 跟泛型类中的E 不同--->泛型方法
//T的类型是在调用方法时确定--->可以是静态
}
}
泛型参数存在继承关系情况
public static void main(String[] args) {
Object obj = new Object();
String s = new String();
//String与Object有继承关系。(所有的类都直接或间接继承Object)
obj = s ;//父类引用指向子类对象(多态一种形式)
//两个数组之间存在数组关系吗
Object[] objArr = new Object[10];
String[] strArr = new String[10];
objArr = strArr;//也可以,多态一种形式
//对应泛型之间存在继承关系
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
list1 = list2;//报错,不存在父类子类关系
//为什么?
//ArrayList--->集合里都是Object类型
/*list2中指定泛型String只是一个标签,
本质集合都是Object类型的,
限制只能String类型数据存入,
实质也是将String类型数据放父Object类型的集合中
故list1与list2底层本质是一样的(Object类型数组)
list2指定String泛型只是在编译器,即写代码时进行限制
所有list1与list2没有继承关系,
是并列关系
*/
}
- A和B是子类父类关系,但是G和G不存在继承关系。是并列关系
通配符
1.在没有通配符的时候:
- 下面的a方法,相当于方法的重复定义,报错
/* public void a(List<Object> list){
}
public void a(List<String> list) {//想传String类型--->重载
}
public void a(List<Integer> list) {//想传Integer类型--->重载
}
报错
泛型是对编译时进行的限制--->标签作
故这几个重载参数本质都是Object-->重复定义
--->通配符解决
*/
2.引入通配符:
//这些泛型接口都是并列关系,没有继承关系
List<Object> list1 = new ArrayList<>();
List<String> list2 = new ArrayList<>();
List<Integer> list3 = new ArrayList<>();
//通配符:?
List<?> list = null;
list = list1;
list = list2;
list = list3;
3.使用通配符后改1中的a方法:
public class Demo05 {
/* public void a(List<Object> list){
}
public void a(List<String> list) {//想传String类型--->重载
}
public void a(List<Integer> list) {//想传Integer类型--->重载
}
报错
泛型是对编译时进行的限制--->标签作
故这几个重载参数本质都是Object-->重复定义
--->通配符解决
*/
public void a(List<?> list){
//内部遍历的时候永Object即可,不用?
for (Object a : list) {
System.out.println(a);
}
}
}
class Test3{
public static void main(String[] args) {
Demo05 demo05 = new Demo05();
//其任何子类都可以传进去
demo05.a(new ArrayList<Integer>());
demo05.a(new ArrayList<String>());
demo05.a(new ArrayList<Object>());//Object也属于?的子类
}
}
- 查看API中应用位置
通配符使用细节
- 通配符泛型,在内部操作时,用Object接收,而不用?
- 集合的写入操作
- 集合的读取操作
//1.遍历:内部遍历的时候用Object即可,不用?
for (Object a : list) {
System.out.println(a);
}
//2.数据的写入操作:
//传入list肯定是接到一个具体的集合
//list.add("abc");--->出错,不能随意添加数据,因为在main函数传入数据指定了泛型
list.add(null);//只能填null,但是也没有实际意义
//3.数据的读取操作:
Object s = list.get(0);//读取可以用Object类型接收
泛型受限
public class Person {//Person继承与Object
}
public class Student extends Person{
}
//a,b,c集合中只是泛型存在子类父类关系,但这几个集合直接不存在子类父类关系(并列)
List<Object> a = new ArrayList<>();
List<Person> b = new ArrayList<>();
List<Student> c = new ArrayList<>();
/*
1.开始使用泛型受限:泛型的上限
List<? extends Person>:
就相当于:
List<? extends Person>是List<Person>的父类,是List<Person的子类>的父类
(另注:之前的单独通配符List<?>实际上是List<? extends Object>)
*/
List<? extends Person> list1 = null;
//list1 = a;--->报错 a是Object类型,是Person的父类,超过泛型上限
list1 = b;
list1 = c;
/*
2.开始使用泛型受限:泛型的下限
List<? super Person>:
就相当于:
List<? super Person>是List<Person>的父类。是List<Person的父类>的父类
*/
List<? super Person> list2 = null;
list2 = a;
list2 = b;
//list2 = c;--->报错 c是Student类型,是Person子类,超过泛型下限
标签:String,自定义,Object,List,泛型,new,public
From: https://www.cnblogs.com/Mc9r4dy/p/18367815