多平台统一管理软件接口,如何实现多平台统一管理软件接口
233
2022-10-13
带你入门Java的泛型
目录泛型1、简单泛型(1)元组(2)堆栈2、泛型接口3、泛型方法(1)类型推断(2)通用的Generator(3)Set实用工具实现数学方法4、擦除(1)迁移兼容性(2)擦除的问题5、擦除的补偿(1)由于擦除原因,无法通过instanceof比较类型。如果引入类型标签,就可以转而使用动态的isInstance()。(2)创建类型实例(3)泛型数组6、边界7、通配符(1)List extends Fruit>协变(2)List super Fruit>逆变(3)无界通配符List>(4)捕获转换8、问题(1)任何基本类型都不能作为类型参数(2)实现参数化接口(3)转型和警告(4)重载(5)基类劫持了接口9、自限定10、异常总结
泛型
1、简单泛型
泛型的主要目的之一就是用来指定容器要持有什么类型的对象,而且由编译器来保证类型的正确性。
泛型暂时不指定类型,在使用时决定具体使用什么类型。通过
(1)元组
class TwoTuple{
public final A first;
public final B second;
public TwoTuple(A a,B b){
first = a;
second = b;
}
@Override
public String toString() {
return "{ " + first +
", " + second +
'}';
}
}
(2)堆栈
class LinkedStack
private class Node {
T item;
Node next;
Node() { item = null; next = http://null; }
Node(T item, Node next) {
this.item = item;
this.next = next;
}
boolean end() { return item == null && next == null; }
}
private Node top = new Node();
public void push(T item) { top = new Node(item, top); }
public T pop() {
T result = top.item;
if(!top.end())
top = top.next;
return result;
}
}
(3)RandomList
class RandomList
private ArrayList
private Random rand = new Random(47);
public void add(T item){
storage.add(item);
}
public T select(){
return storage.get(rand.nextInt(storage.size()));
}
}
2、泛型接口
泛型也可以应用于接口,例如生成器,这是一种专门负责创建对象的类。
import net.mindview.util.Generator;
import java.util.Iterator;
class Fibonacci implements Generator
private int count = 0;
public Integer next(){
return fib(count++);
}
private int fib(int n){
if(n<2) return 1;
return fib(n-2) + fib(n-1);
}
}
class IterableFibonacci implements Iterable
private Fibonacci fib = new Fibonacci();
private int n;
public IterableFibonacci(int count){
n = count;
}
@Override
public Iterator
return new Iterator
@Override
public boolean hasNext() {
return n>0;
}
@Override
public Integer next() {
n--;
return fib.next();
}
public void remove() { // Not implemented
throw new UnsupportedOperationException();
}
};
}
}
3、泛型方法
泛型方法使得该方法能够独立于类而产生变化。使用泛型方法的时候,通常不必指明参数类型,因为编译器会为我们找出具体的类型,这称为类型参数推断。
class GenericMethods{
public
System.out.println(x.getClass().getSimpleName());
}
}
(1)类型推断
使用泛型有时候需要向程序中加入更多的代码。如下所示:
Map
new HashMap
在泛型方法中可以通过类型推断来简化一部分工作。如下所示:
class New{
public static
return new HashMap
}
public static void main(String[] args) {
Map
}
}
类型推断只对赋值操作有效,其他时候并不起作用。如果将一个泛型方法的结果作为参数,传递给另一个方法时,另一个方法需要显式的类型说明。如下所示:
public class ExplicitTypeSpecification{
static void f(Map
public static void main(String[] args) {
f(New.
}
}
(2)通用的Generator
import net.mindview.util.Generator;
public class BasicGenerator
private Class
public BasicGenerator(Class
this.type = type;
}
public T next(){
try {
return type.newInstance();
}catch (Exception e){
throw new RuntimeException(e);
}
}
public static
return new BasicGenerator
}
}
(3)Set实用工具实现数学方法
public class Sets{
@SuppressWarnings("unchecked")
protected static
if(s instanceof EnumSet)
return ((EnumSet)s).clone();
return new HashSet
}
//并集
public static
Set
result.addAll(b);
return result;
}
//交集
public static
Set
result.retainAll(b);
return result;
}
//差集
public static
Set
result.removeAll(subset);
return result;
}
//包含除了交集以外的所有元素
public static
return difference(union(a, b), intersection(a, b));
}
}
4、擦除
Java泛型是使用擦除来实现的,这意味着当你在使用泛型时,任何具体的类型信息都被擦除了,你唯一知道的就是你在使用一个对象。因此List
(1)迁移兼容性
泛型类型只有在静态类型检查期间才出现,在此之后,程序中的所有泛型类型都将被擦除,替换为他们的非泛型上界。擦除的核心动机是它使得泛化的客户端可以用非泛化的类库来使用,反之亦然,这经常被称为“迁移兼容性”。
(2)擦除的问题
泛型的QkuLosNIYG所有关于参数的类型信息都丢失了,所以不能用于显式地引用运行时类型的操作之中,例如转型、instanceof操作和new表达式。
5、擦除的补偿
(1)由于擦除原因,无法通过instanceof比较类型。如果引入类型标签,就可以转而使用动态的isInstance()。
public class ClassTypeCapture
Class
public ClassTypeCapture(Class
this.kind = kind;
}
public boolean f(Object arg){
return kind.isInstance(arg);
}
}
(2)创建类型实例
通过工厂对象来创建实例。如果使用类型标签,就可以使用newInstance()来创建这个类型的新对象。
class ClassAsFactory
T x;
public ClassAsFactory(Class
try{
x = kind.newInstance();
}catch(Exception e){
throw new RuntimeException(e);
}
}
}
如果类没有默认的构造器,上面的案例会创建失败。为了解决这个问题,可以通过显示的工厂来实现。
interface FactoryI
T create();
}
class Foo2
private T x;
public
x = factory.create();
}
}
class IntegerFactory implements FactoryI
public Integer create(){
return new Integer(6);
}
}
另一种方式是模板方法设计模式。
abstract class GenericWithCreate
final T element;
GenericWithCreate(){ element = create(); }
abstract T create();
}
class X{}
class Creator extends GenericWithCreate
X create(){ return new X(); }
}
(3)泛型数组
无法通过 T[] array = new T[sz] 来创建泛型数组,一般的解决方法是在需要泛型数组的地方都使用ArrayList。
在创建泛型数组时,有以下三种情况:
①创建时强制转型
public class GenericArray
private T[] array;
@SuppressWarnings("unchecked")
public GenericArray(int sz){
array = (T[])new Object[sz];
}
public T[] rep(){ return array; }
public static void main(String[] args) {
GenericArray
Integer[] ia = gai.rep();//引起ClassCastException
Object[] oa = gai.rep();
}
}
②方法返回时强制转型
class GenericArray2
private Object[] array;
@SuppressWarnings("unchecked")
public GenericArray(int sz){
array = new Object[sz];
}
public T[] rep(){ return (T[])array; }
public static void main(String[] args) {
GenericArray
Integer[] ia = gai.rep();//引起ClassCastException
Object[] oa = gai.rep();
}
}
③使用Array.newInstance()
以上两种方法都无法创建具体类型的数组,无法推翻底层的数组类型,只能是Object[]。通过传入类型标记Class
class GenericArray3
private T[] array;
@SuppressWarnings("unchecked")
public GenericArray(Class
array = (T[]) Array.newInstance(type,sz);
}
public T[] rep(){ return array; }
public static void main(String[] args) {
GenericArray
Integer[] ia = gai.rep();//可以正常运行
Object[] oa = gai.rep();
}
}
6、边界
边界使得你可以在用于泛型的参数类型上设置限制条件,可以按照自己的边界类型来调用方法。
public class Test {
public static void main(String[] args) {
Man m = new Man();
m.hear();
m.smell();
}
}
interface SuperPower{}
interface SuperHearing extends SuperPower{
void hearSubtleNoises();
}
interface SuperSmell extends SuperPower{
void trackBySmell();
}
class SuperHero
POWER power;
SuperHero(POWER power){ this.power = power; }
POWER getPower(){ return power; }
}
class CaineHero
CaineHero(POWER power){ super(power); }
void hear(){ power.hearSubtleNoises(); }
void smell(){ power.trackBySmell(); }
}
class SuperHearSmell implements SuperHearing,SuperSmell{
@Override
public void hearSubtleNoises() {
System.out.println("hearSubtleNoises");
}
@Override
public void trackBySmell() {
System.out.println("trackBySmell");
}
}
class Man extends CaineHero
Man(){ super(new SuperHearSmell()); }
}
7、通配符
(1)List extends Fruit>协变
表示具有任何从Fruit继承的类型的列表。List extends Fruit>可以合法地指向一个List
List extends Fruit> flist =
Arrays.asList(new Apple());
//Compile Error:can't add any type of object
//add()的参数是 extends Fruit>,编译器不知道需要Fruit的哪个
//具体的子类型,因此不接受任何类型的Fruit
//flist.add(new Apple());
//flist.add(new Fruit());
//flist.add(new Object());
flist.add(null);//Legal but uninteresting
Apple a = (Apple)flist.get(0);//No warning
Fruit f = flist.get(0);//No warning
flist.contains(new Apple());//参数是Object
flist.indexOf(new Apple());//参数是Object
(2)List super Fruit>逆变
超类型通配符可以安全地传递一个类型对象到泛型类型中。List super Fruit>意味着向其中添加Fruit或Fruit的子类型是安全的。
List super Fruit> flist = new ArrayList
flist.add(new Apple());
flist.add(new Fruit());
//Error:Incompatible Type
//Fruit f = flist.get(0);
Object f = flist.get(0);//OK,but type information has been lost
(3)无界通配符List>
List实际上表示“持有任何Object类型的原生List”,List>表示“具有某种特定类型的非原生List,只是我们不知道那种类型是什么”,List extends Object>表示“类型是Object的导出类”。
无界通配符的一个重要应用:处理多个泛型参数时,允许一个参数可以是任何类型,同时为其他参数确定某种特定类型。
Map
map = new HashMap
原生Holder与Holder>是大致相同的事物,但存在不同。它们会揭示相同的问题,但是后者将这些问题作为错误而不是警告报告。
static void rawArgs(Holder holder,Object arg){
//holder.set(arg);
//Warning:Unchecked call to set(T) as member
//of the raw type Holder
//holder.set(new Wildcards());//Same Warning
//Can't do this:don't have any 'T'
//T t = holder.get();
//OK,but type infomation has been lost
Object obj = holder.get();
}
//Similar to rawArgs(),but errors instead of warnings
static void unboundedArg(Holder> holder,Object arg){
//holder.set(arg);
//Error:set(capture of ?) in Holder
//cannot be applied to (Object)
//holder.set(new Wildcards());//Same Error
//Can't do this:don't have any 'T'
//T t = holder.get();
//OK,but type infomation has been lost
Object obj = holder.get();
}
(4)捕获转换
未指定的通配符类型被捕获,并被转换为确切类型。在f2()中调用f1(),参数类型在调用f2()的过程中被捕获,因此它可以在对f1()的调用中被使用。不能从f2()中返回T,因为T对于f2()来说是未知的。
static
T t = holder.get();
System.out.println(t.getClass().getSimpleName());
}
static
f1(holder);
}
8、问题
(1)任何基本类型都不能作为类型参数
(2)实现参数化接口
一个类不能实现同一个泛型接口的两种变体。将泛型参数移除掉后,这段代码就可以正常编译了。
interface Payable
class Employee implements Payable
//Compile Error:cannot be inherited with different type arguments
class Hourly extends Employee implements Payable
(3)转型和警告
使用带有泛型类型参数的转型或instanceof不会有任何效果。
由于擦除原因,编译器无法知道这个转型是否安全,并且pop()方法实际上并没有执行任何转型。如果没有@SuppressWarnings注解,编译器将对pop()产生“Unchecked cast”警告。
private int index = 0;
private Object[] storage;
@SuppressWarnings("unchecked")
public T pop(){ return (T)storage[--index]; }
(4)重载
由于擦除的原因,重载方法将产生相同的类型签名,导致程序不能编译。
public class UseList
void f(List
void f(List
}
(5)基类劫持了接口
一旦为Comparable确定了ComparablePet参数,那么其他任何实现类都不能与ComparablePet之外的任何对象比较。在前面的“实现参数化接口”章节里面的第一个例子,就体现了基类劫持接口。
public class ComparablePet
implements Comparable
public int compareTo(ComparablePet arg) {
return 0;
}
}
class Cat extends ComparablePet implements Comparable
// Error: Compahttp://rable cannot be inherited with
// different arguments:
public int compareTo(Cat arg) { return 0; }
} ///:~
class Hamster extends ComparablePet
implements Comparable
public int compareTo(ComparablePet arg) {
return 0;
}
}
9、自限定
class Subtype extends BasicHolder
从使用上来说,Subtype对象本身的类型是Subtype,且Subtype对象继承而来的成员(element)、方法的形参(set方法)、方法的返回值(get方法)也是Subtype了(这就是自限定的重要作用)。这样Subtype对象就只允许和Subtype对象(而不是别的类型的对象)交互了。
class BasicHolder
T element;
void set(T arg) { element = arg; }
T get() { return element; }
void f() {
System.out.println(element.getClass().getSimpleName());
}
}
class Subtype extends BasicHolder
public class CRGWithBasicHolder {
public static void main(String[] args) {
Subtype st1 = new Subtype(), st2 = new Subtype(), st3 = new Subtype();
st1.set(st2);
st2.set(st3);
Subtype st4 = st1.get().get();
st1.f();
}
} /* Output:
Subtype
*/
10、异常
由于擦除原因,将泛型应用于异常是非常受限的。但是,类型参数可能会在一个方法的throws子句中用到,这使得你可以编写随检查型异常的类型而发生变化的泛型代码。
interface
Processor
void process(List
}
class
ProcessRunner
extends ArrayList
List
List
for(Processor
processor.process(resultCollector);
return resultCollector;
}
}
class Failure extends Exception {}
class Processor1 implements
Processor
static int count = 3;
public void process(List
throws Failure1_1, Failure1_2 {
if(count-- > 1)
resultCollector.add("Hep!");
else
resultCollector.add("Ho!");
if(count < 0)
throw new Failure1();
}
}
public class Test {
public static void main(String[] args) {
ProcessRunner
new ProcessRunner
for(int i = 0; i < 3; i++)
runner.add(new Processor1());
try {
System.out.println(runner.processAll());
} catch(Failure e) {
System.out.println(e);
}
}
}
总结
本篇文章就到这里了,希望能给您带来帮助,也希望您能够多多关注我们的更多内容!
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~