多平台统一管理软件接口,如何实现多平台统一管理软件接口
277
2022-10-25
深入理解java泛型Generic
一、背景
泛型技术诞生之前(JDK5以前),创建集合的类型都是Object 类型的元素,存储内容没有限制,编译时正常,运行时容易出现ClassCastException 异常。
public class Test {
public static void main(String[] args) {
ArrayList list = new ArrayList();
list.add("java");
list.add(100);
list.add(true);
for(int i = 0;i Object o = list.get(i); String str = (String)o; System.out.println(str); } } } 输出: java Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String at com.chengyu.junit.Test.main(Test.java:18) 二、泛型概念 JDK5 中引入泛型,从而可以在编译时检测是否存在非法的类型数据结构。 其本质就是参数化类型,可以用于类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。 public static void main(String[] args) { ArrayList strList.add("java"); strList.add("C#"); for(int i = 0;i < strList.size();i++) { String str = strList.get(i); System.out.println(str); } } 三、泛型类 3.1 定义与调用 定义类时设置泛型,该泛型可用于类中的属性或方法中,调用该泛型类时,指定具体类型; // 调用泛型类 public class GenericTest { public static void main(String[] args) { Generic String key = strGen.getKey(); System.out.println(key); } } // 定义泛型类 // @param class Generic private T key; public Generic(T key) { this.key = key; } public T getKey() { return key; } public void setKey(T key) { this.key = key; } @Override public String toString() { return "GenericTest [key=" + key + "]"; } } 3.2 注意 1)调用泛型类时未定义类型,则会按照Object 类型处理; 2)调用时分别指定不同类型,但本质都是Object 类型; 3)泛型不支持基本数据类型; 4)泛型类的成员方法不可以用static 修饰(泛型方法可以)。 3.3 使用 需求:抽奖活动,但抽奖内容没有确定,可能都是现金,也可能都是物品 public class ProductGetterTest { public static void main(String[] args) { // 抽物品 ProductGetter String[] str = {"手机","电视","洗衣机"}; for(int i = 0; i < str.length; i ++ ) { strProductGetter.addProduct(str[i]); } String strProduct = strProductGetter.getProduct(); System.out.println("恭喜您抽中了" + strProduct); System.out.println("============================================="); // 抽现金 ProductGetter Integer[] integer = {1000,2000,3000}; for(int i = 0; i < integer.length; i ++ ) { intProductGetter.addProduct(integer[juZKWi]); } int intProduct = intProductGetter.getProduct(); System.out.println("恭喜您抽中了" + intProduct); } } // 抽奖器 class ProductGetter Random random = new Random(); // 奖品池 ArrayList // 添加奖品 public void addProduct(T t) { list.add(t); } // 抽奖(获取奖品) public T getProduct() { return list.get(random.nextInt(list.size())); } } 3.4 泛型类的继承 3.4.1 子类也是泛型类 子类也是泛型类,则泛型要保持一致。 class ChildFirst 1)指定子类泛型,不指定父类泛型,父类默认为Object 类型 class Parent private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildFirst @Override public Object getValue() { return super.getValue(); } } 2)若父类保留原有泛型,与子类泛型不一致,则会编译出错 class ChildFirst @Override public E getValue() { return super.getValue(); } 3)父类泛型与子类保持一致 具体泛型指定是由子类传递到父类当中,所以继承时父类要与子类泛型保持一致(当然都写成E也可以)。 class Parent private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildFirst @Override public T getValue() { return super.getValue(); } } 4)调用 public class GenericTest { public static void main(String[] args) { ChildFirst childFirst.setValue("chengyu"); System.out.println(childFirst.getValue()); } } 5)补充: 子类可以进行泛型扩展,但子类必须有一个泛型与父类一致 public class GenericTest { public static void main(String[] args) { ChildFirst childFirst.setValue("chengyu"); System.out.println(childFirst.getValue()); } } class Parent private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildFirst @Override public T getValue() { return super.getValue(); } } 3.4.2 子类不是泛型类 子类不是泛型类,父类要明确泛型的数据类型 class ChildSecond extends Parent 1)子类不是泛型类,不指定父类泛型,父类默认为Object 类型 class Parent private E value; public E getValue() { return value; } public void setValue(E value) { this.value = value; } } class ChildSecond extends Parent{ @Override public Object getValue() { return super.getValue(); } } 2)父类要明确泛型的数据类型 class ChildSecond extends Parent @Override public String getValue() { return super.getValue(); } } 3)调用 public class GenericTest { public static void main(String[] args) { ChildSecond childSecond = new ChildSecond(); childSecond.setValue("chengyu2"); System.out.println(childSecond.getValue()); } } 四、泛型接口 4.1 定义 public interface Generator 4.2 使用(与继承特点相同) 4.2.1 实现类不是泛型类 实现类不是泛型类,接口要明确数据类型 class Apple implements Generator @Override public String getKey() { return "Generator interface"; } } 4.2.2 实现类也是泛型类 实现类也是泛型类,实现类和接口的泛型类型要一致 class Apple private T key; @Override public T getKey() { return key; } } 五、泛型方法 5.1 定义 5.1.1 泛型方法 修饰符 } // 泛型方法 public return list.get(random.nextInt(list.size())); } 5.1.2 静态泛型方法 修饰符 } // 泛型方法 public return list.get(random.nextInt(list.size())); } 5.1.3 可变参数的泛型方法 public for(int i = 0; i < e.length;i++){ System.out.println(e[i]); } } // 调用 print(1,2,3,4); 5.2 注意 1)包含泛型列表的方法才是泛型方法,泛型类中使用了泛型的方法并不是泛型方法; 2)泛型列表中声明了泛型类型,才可以在方法中使用泛型类型; 3)泛型方法中的泛型类型独立于泛型类的泛型,与类泛型类型无关; 4)泛型方法可以用static 修饰(泛型类的成员方法不可以)。 5.3 使用 5.3.1 定义泛型方法 // 抽奖器 // @param class ProductGetter Random random = new Random(); // 奖品池 ArrayList // 添加奖品 public void addProduct(T t) { list.add(t); } // 抽奖(获取奖品) public T getProduct() { return list.get(random.nextInt(list.size())); } // 泛型方法 public return list.get(random.nextInt(list.size())); } } 5.3.2 调用泛型方法 public class ProductGetterTest { public static void main(String[] args) { ProductGetter ArrayList strList.add("手机"); strList.add("电视"); strList.add("洗衣机"); String product = intProductGetter.getProduct(strList); System.out.println("恭喜您抽中了" + product); } } 六、类型通配符 6.1 类型通配符介绍 类型通配符一般用【?】代替具体的类型 实参; 6.2 为什么要用类型通配符 泛型类被调用时,需要指定泛型类型,当泛型类的方法被调用时,不能灵活对应多种泛型类型的需求,如下面代码部分所示: public class BoxTest { public static void main(String[] args) { // 3.调用showBox Box box1.setFirst(100); showBox(box1); // 4.再次调用showBox // 出现问题:类型发生变化后会报错 Box box2.setFirst(200); showBox(box2); } // 2. 调用泛型类,此时需要指定泛型类型 public stjuZKWatic void showBox(Box Number first = box.getFirst(); System.out.println(first); } } // 1.定义泛型类 class Box private E first; public E getFirst() { return first; } public void setFirst(E first) { this.first = first; } } 解决上述问题,类型通配符【?】登场 public class BoxTest { public static void main(String[] args) { // 3.调用showBox Box box1.setFirst(100); showBox(box1); // 4.再次调用showBox // 问题得以解决 Box box2.setFirst(200); showBox(box2); } // 2. 调用泛型类,此时需要指定泛型类型 // 【?】类型通配符等成 public static void showBox(Box> box) { Object first = box.getFirst(); System.out.println(first); } } // 1.定义泛型类 class Box private E first; public E getFirst() { return first; } public void setFirst(E first) { this.first = first; } } 6.3 泛型通配符上限 extends 【6.2】代码例中,虽然使用了通配符,但 box.getFirst()返回类型仍然需要定义成Object 类型,并不理想。 public static void showBox(Box> box) { Object first = box.getFirst(); System.out.println(first); } 通配符上限登场: 调用showBox 方法时,传递的泛型类型可以是Number 及其子类(Integer) public static void showBox(Box extends Number> box) { Number first = box.getFirst(); System.out.println(first); } 注意: public static void showBox(Box extends Number> box) { Number first = box.getFirst(); // 此处编译报错:类型不一致 // 虽然定义上限,showBox 被调用时没问题,但在方法内同时定义多种类型,编译器无法识别 Integer second = box.getFirst(); System.out.println(first); } 6.4 泛型通配符下限 super public static void showBox(Box super Integer> box) { Number first = box.getFirst(); System.out.println(first); } 注意: 遍历时要用Object 类型进行遍历; 七、类型擦除 泛型信息只存在于代码编译阶段,进入JVM之前,与泛型相关的信息会被擦除,这个行为称为类型擦除。
Object o = list.get(i);
String str = (String)o;
System.out.println(str);
}
}
}
输出:
java
Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at com.chengyu.junit.Test.main(Test.java:18)
二、泛型概念
JDK5 中引入泛型,从而可以在编译时检测是否存在非法的类型数据结构。
其本质就是参数化类型,可以用于类、接口和方法中,分别被称为泛型类、泛型接口、泛型方法。
public static void main(String[] args) {
ArrayList
strList.add("java");
strList.add("C#");
for(int i = 0;i < strList.size();i++) {
String str = strList.get(i);
System.out.println(str);
}
}
三、泛型类
3.1 定义与调用
定义类时设置泛型,该泛型可用于类中的属性或方法中,调用该泛型类时,指定具体类型;
// 调用泛型类
public class GenericTest {
public static void main(String[] args) {
Generic
String key = strGen.getKey();
System.out.println(key);
}
}
// 定义泛型类
// @param
class Generic
private T key;
public Generic(T key) {
this.key = key;
}
public T getKey() {
return key;
}
public void setKey(T key) {
this.key = key;
}
@Override
public String toString() {
return "GenericTest [key=" + key + "]";
}
}
3.2 注意
1)调用泛型类时未定义类型,则会按照Object 类型处理;
2)调用时分别指定不同类型,但本质都是Object 类型;
3)泛型不支持基本数据类型;
4)泛型类的成员方法不可以用static 修饰(泛型方法可以)。
3.3 使用
需求:抽奖活动,但抽奖内容没有确定,可能都是现金,也可能都是物品
public class ProductGetterTest {
public static void main(String[] args) {
// 抽物品
ProductGetter
String[] str = {"手机","电视","洗衣机"};
for(int i = 0; i < str.length; i ++ ) {
strProductGetter.addProduct(str[i]);
}
String strProduct = strProductGetter.getProduct();
System.out.println("恭喜您抽中了" + strProduct);
System.out.println("=============================================");
// 抽现金
ProductGetter
Integer[] integer = {1000,2000,3000};
for(int i = 0; i < integer.length; i ++ ) {
intProductGetter.addProduct(integer[juZKWi]);
}
int intProduct = intProductGetter.getProduct();
System.out.println("恭喜您抽中了" + intProduct);
}
}
// 抽奖器
class ProductGetter
Random random = new Random();
// 奖品池
ArrayList
// 添加奖品
public void addProduct(T t) {
list.add(t);
}
// 抽奖(获取奖品)
public T getProduct() {
return list.get(random.nextInt(list.size()));
}
}
3.4 泛型类的继承
3.4.1 子类也是泛型类
子类也是泛型类,则泛型要保持一致。
class ChildFirst
1)指定子类泛型,不指定父类泛型,父类默认为Object 类型
class Parent
private E value;
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
class ChildFirst
@Override
public Object getValue() {
return super.getValue();
}
}
2)若父类保留原有泛型,与子类泛型不一致,则会编译出错
class ChildFirst
@Override
public E getValue() {
return super.getValue();
}
3)父类泛型与子类保持一致
具体泛型指定是由子类传递到父类当中,所以继承时父类要与子类泛型保持一致(当然都写成E也可以)。
class Parent
private E value;
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
class ChildFirst
@Override
public T getValue() {
return super.getValue();
}
}
4)调用
public class GenericTest {
public static void main(String[] args) {
ChildFirst
childFirst.setValue("chengyu");
System.out.println(childFirst.getValue());
}
}
5)补充:
子类可以进行泛型扩展,但子类必须有一个泛型与父类一致
public class GenericTest {
public static void main(String[] args) {
ChildFirst
childFirst.setValue("chengyu");
System.out.println(childFirst.getValue());
}
}
class Parent
private E value;
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
class ChildFirst
@Override
public T getValue() {
return super.getValue();
}
}
3.4.2 子类不是泛型类
子类不是泛型类,父类要明确泛型的数据类型
class ChildSecond extends Parent
1)子类不是泛型类,不指定父类泛型,父类默认为Object 类型
class Parent
private E value;
public E getValue() {
return value;
}
public void setValue(E value) {
this.value = value;
}
}
class ChildSecond extends Parent{
@Override
public Object getValue() {
return super.getValue();
}
}
2)父类要明确泛型的数据类型
class ChildSecond extends Parent
@Override
public String getValue() {
return super.getValue();
}
}
3)调用
public class GenericTest {
public static void main(String[] args) {
ChildSecond childSecond = new ChildSecond();
childSecond.setValue("chengyu2");
System.out.println(childSecond.getValue());
}
}
四、泛型接口
4.1 定义
public interface Generator
4.2 使用(与继承特点相同)
4.2.1 实现类不是泛型类
实现类不是泛型类,接口要明确数据类型
class Apple implements Generator
@Override
public String getKey() {
return "Generator interface";
}
}
4.2.2 实现类也是泛型类
实现类也是泛型类,实现类和接口的泛型类型要一致
class Apple
private T key;
@Override
public T getKey() {
return key;
}
}
五、泛型方法
5.1 定义
5.1.1 泛型方法
修饰符
}
// 泛型方法
public
return list.get(random.nextInt(list.size()));
}
5.1.2 静态泛型方法
修饰符
}
// 泛型方法
public
return list.get(random.nextInt(list.size()));
}
5.1.3 可变参数的泛型方法
public
for(int i = 0; i < e.length;i++){
System.out.println(e[i]);
}
}
// 调用
print(1,2,3,4);
5.2 注意
1)包含泛型列表的方法才是泛型方法,泛型类中使用了泛型的方法并不是泛型方法;
2)泛型列表中声明了泛型类型,才可以在方法中使用泛型类型;
3)泛型方法中的泛型类型独立于泛型类的泛型,与类泛型类型无关;
4)泛型方法可以用static 修饰(泛型类的成员方法不可以)。
5.3 使用
5.3.1 定义泛型方法
// 抽奖器
// @param
class ProductGetter
Random random = new Random();
// 奖品池
ArrayList
// 添加奖品
public void addProduct(T t) {
list.add(t);
}
// 抽奖(获取奖品)
public T getProduct() {
return list.get(random.nextInt(list.size()));
}
// 泛型方法
public
return list.get(random.nextInt(list.size()));
}
}
5.3.2 调用泛型方法
public class ProductGetterTest {
public static void main(String[] args) {
ProductGetter
ArrayList
strList.add("手机");
strList.add("电视");
strList.add("洗衣机");
String product = intProductGetter.getProduct(strList);
System.out.println("恭喜您抽中了" + product);
}
}
六、类型通配符
6.1 类型通配符介绍
类型通配符一般用【?】代替具体的类型 实参;
6.2 为什么要用类型通配符
泛型类被调用时,需要指定泛型类型,当泛型类的方法被调用时,不能灵活对应多种泛型类型的需求,如下面代码部分所示:
public class BoxTest {
public static void main(String[] args) {
// 3.调用showBox
Box
box1.setFirst(100);
showBox(box1);
// 4.再次调用showBox
// 出现问题:类型发生变化后会报错
Box
box2.setFirst(200);
showBox(box2);
}
// 2. 调用泛型类,此时需要指定泛型类型
public stjuZKWatic void showBox(Box
Number first = box.getFirst();
System.out.println(first);
}
}
// 1.定义泛型类
class Box
private E first;
public E getFirst() {
return first;
}
public void setFirst(E first) {
this.first = first;
}
}
解决上述问题,类型通配符【?】登场
public class BoxTest {
public static void main(String[] args) {
// 3.调用showBox
Box
box1.setFirst(100);
showBox(box1);
// 4.再次调用showBox
// 问题得以解决
Box
box2.setFirst(200);
showBox(box2);
}
// 2. 调用泛型类,此时需要指定泛型类型
// 【?】类型通配符等成
public static void showBox(Box> box) {
Object first = box.getFirst();
System.out.println(first);
}
}
// 1.定义泛型类
class Box
private E first;
public E getFirst() {
return first;
}
public void setFirst(E first) {
this.first = first;
}
}
6.3 泛型通配符上限 extends
【6.2】代码例中,虽然使用了通配符,但 box.getFirst()返回类型仍然需要定义成Object 类型,并不理想。
public static void showBox(Box> box) {
Object first = box.getFirst();
System.out.println(first);
}
通配符上限登场:
调用showBox 方法时,传递的泛型类型可以是Number 及其子类(Integer)
public static void showBox(Box extends Number> box) {
Number first = box.getFirst();
System.out.println(first);
}
注意:
public static void showBox(Box extends Number> box) {
Number first = box.getFirst();
// 此处编译报错:类型不一致
// 虽然定义上限,showBox 被调用时没问题,但在方法内同时定义多种类型,编译器无法识别
Integer second = box.getFirst();
System.out.println(first);
}
6.4 泛型通配符下限 super
public static void showBox(Box super Integer> box) {
Number first = box.getFirst();
System.out.println(first);
}
注意:
遍历时要用Object 类型进行遍历;
七、类型擦除
泛型信息只存在于代码编译阶段,进入JVM之前,与泛型相关的信息会被擦除,这个行为称为类型擦除。
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
评论列表