毕设做系统与网站答辩,wordpress sdk.js好卡,成都手机网站建设哪,设计网站设计网站仿制药名言最近#xff0c;我正在为Oracle认证专家Java SE 7程序员考试做准备#xff0c;而我恰巧在Java泛型领域遇到了一些看起来很奇怪的构造。 但是#xff0c;我也看到了一些巧妙而优雅的代码。 我发现这些示例值得分享#xff0c;这不仅是因为它们可以使您的设计选择更… 仿制药名言 最近我正在为Oracle认证专家Java SE 7程序员考试做准备而我恰巧在Java泛型领域遇到了一些看起来很奇怪的构造。 但是我也看到了一些巧妙而优雅的代码。 我发现这些示例值得分享这不仅是因为它们可以使您的设计选择更加容易并且使代码更加健壮和可重用而且还因为其中的某些示例在您不习惯泛型时非常棘手。 我决定将这篇文章分为四个章节这些章节几乎反映了我在学习和工作经历中对仿制药的经验。 您了解泛型吗 当我们四处看看时可以发现泛型在Java Universe的许多不同框架中都大量使用。 它们从Web应用程序框架到Java本身的集合。 由于这个话题已经在我之前被很多人解释过了所以我将只列出我认为有价值的资源然后转到有时根本没有提及或解释得不好的东西通常在网上发布的注释或文章中 。 因此如果您不了解核心泛型概念则可以查看以下一些材料 Katherine Sierra和Bert Bates的SCJP Sun认证Java 6考试程序员 对我而言本书的主要目的是为参加Oracle提供的OCP考试做好准备。 课程 Oracle的泛型已更新 资源由Oracle本身提供。 Maurice Naftalin和Philip Wadler的Java泛型和集合 OReilly Media制作的另一本很棒的Java书籍。 泛型不允许做什么 假设您了解泛型并希望了解更多信息那么请转到无法完成的工作。 令人惊讶的是有很多东西无法与泛型一起使用。 在使用泛型时我选择了以下六个避免陷阱的示例。 类型为T静态字段 许多没有经验的程序员常犯的一个常见错误是试图声明静态成员。 在下面的示例中可以看到任何尝试都会导致编译器错误如下所示 Cannot make a static reference to the non-static type T 。 public class StaticMemberT {// causes compiler errorstatic T member;
} 类型为T实例 另一个错误是尝试通过在泛型类型上调用new来实例化任何类型。 这样编译器将导致错误提示 Cannot instantiate the type T public class GenericInstanceT {public GenericInstance() {// causes compiler errornew T();}
} 与原始类型不兼容 使用泛型时最大的限制之一似乎是它们与原始类型不兼容。 的确您不能在声明中直接使用基元但是可以用适当的包装器类型替换基元然后就可以了。 整个情况在以下示例中呈现 public class PrimitivesT {public final ListT list new ArrayList();public static void main(String[] args) {final int i 1;// causes compiler error// final Primitivesint prim new Primitives();final PrimitivesInteger prim new Primitives();prim.list.add(i);}
} 在编译期间 Primitives类的第一个实例化将失败并出现与以下错误类似的错误 Syntax error on token int, Dimensions expected after this token 。 使用包装器类型和少量自动装箱魔术可绕过此限制。 T类型的数组 使用泛型的另一个明显限制是无法实例化泛型类型的数组。 考虑到数组对象的基本特征原因很明显–它们在运行时保留其类型信息。 如果违反了它们的运行时类型完整性则运行时异常ArrayStoreException可以挽救这一天。 public class GenericArrayT {// this one is finepublic T[] notYetInstantiatedArray;// causes compiler errorpublic T[] array new T[5];
} 但是如果尝试直接实例化一个通用数组则将出现如下编译错误 Cannot create a generic array of T 。 通用异常类 有时程序员可能需要传递泛型类型的实例以及引发异常。 这在Java中是不可能的。 下面的示例描述了这种努力。 // causes compiler error
public class GenericExceptionT extends Exception {} 当您尝试创建这样的异常时您将得到如下消息 The generic class GenericExceptionT may not subclass java.lang.Throwable 。 关键字super和extends替代含义 值得一提的最后一个限制特别是对于新手来说是泛型时关键字super和extends的替代含义。 为了生成利用泛型的精心设计的代码了解这一点非常有用。 ? extends T 含义通配符是指扩展类型T和类型T本身的任何类型。 ? super T 含义通配符是指T的任何超类型以及T本身。 一点点的美 关于Java我最喜欢的事情之一是它的强类型。 众所周知泛型是在Java 5中引入的它们被用来使我们更容易使用集合它们不仅在集合中被用于更多领域但这是设计阶段泛型的核心论点之一 。 即使泛型仅提供编译时保护并且不输入字节码但它们提供了相当有效的方式来确保类型安全。 以下示例显示了泛型的一些不错的功能或用例。 泛型适用于类和接口 这可能一点都不令人惊讶但是是的-接口和泛型是兼容的构造。 尽管将泛型与接口结合使用非常普遍但我发现这一事实实际上是非常酷的功能。 这使程序员可以在考虑类型安全和代码重用的情况下创建甚至更高效的代码。 例如考虑以下来自包java.lang接口Comparable示例 public interface ComparableT {public int compareTo(T o);
} 泛型的简单介绍使得有可能从compareTo方法中省略check实例从而使代码更具凝聚力并提高了可读性。 通常泛型有助于使代码更易于阅读和理解并有助于引入类型顺序。 泛型允许优雅使用范围 关于限制通配符有一个很好的例子说明了在库类Collections可以实现的目标。 此类声明方法copy 该方法在以下示例中定义并使用有界通配符来确保列表的复制操作的类型安全。 public static T void copy(List? super T dest, List? extends T src) { ... } 让我们仔细看看。 方法copy被声明为返回void的静态泛型方法。 它接受两个参数-目标和源并且两者都是有界的。 目标必须存储仅属于T或T类型本身的超类型的类型。 另一方面源必定仅由T类型的扩展类型或T类型本身构成。 这两个约束保证了集合和复制操作都保持类型安全。 我们不需要使用数组因为它们通过抛出上述ArrayStoreException异常防止了任何类型安全冲突。 泛型支持多边界 不难想象为什么人们会只使用一种简单的边界条件而不是使用更多的条件。 实际上这样做很容易。 考虑以下示例我需要创建一个接受参数的方法该参数既是Comparable也是数字List 。 开发人员将被迫创建不必要的接口ComparableList以便在通用时间内履行上述合同。 public class BoundsTest {interface ComparableList extends List, Comparable {}class MyList implements ComparableList { ... }public static void doStuff(final ComparableList comparableList) {}public static void main(final String[] args) {BoundsTest.doStuff(new BoundsTest().new MyList());}
} 在执行此任务之后我们可以忽略这些限制。 使用泛型可以使我们创建满足所需合同的具体类但使doStuff方法尽可能开放。 我发现的唯一缺点是语法相当冗长。 但是由于它仍然保持很好的可读性和易于理解性因此我可以忽略此缺陷。 public class BoundsTest {class MyListT implements ListT, ComparableT { ... }public static T, U extends ListT ComparableT void doStuff(final U comparableList) {}public static void main(final String[] args) {BoundsTest.doStuff(new BoundsTest().new MyListString());}
}有点奇怪 我决定为这篇文章的最后一章专门介绍到目前为止我遇到的两种最奇怪的构造或行为。 您极有可能永远不会遇到这样的代码但是我发现提到它很有趣。 因此事不宜迟让我们见识这些奇怪的东西。 尴尬的代码 与任何其他语言构造一样您可能最终会遇到一些看起来很奇怪的代码。 我想知道最奇怪的代码是什么样的以及它是否甚至可以通过编译。 我能想到的最好的是下面的代码。 您可以猜测该代码是否可以编译 public class AwkwardCodeT {public static T T T(T T) {return T;}
} 即使这是一个非常糟糕的编码示例也可以成功编译并且应用程序可以正常运行。 第一行声明泛型类AwkwardCode 第二行声明泛型方法T 方法T是返回T实例的通用方法。 它采用T类型的参数不幸的是称为T 该参数也会在方法主体中返回。 通用方法调用 最后一个示例显示了与泛型结合使用时类型推断的工作原理。 当我看到一段代码不包含方法调用的通用签名却声称要通过编译时我偶然发现了这个问题。 当某人对泛型只有很少的经验时这样的代码可能一见钟情。 您能否解释以下代码的行为 public class GenericMethodInvocation {public static void main(final String[] args) {// 1. returns trueSystem.out.println(Compare.String genericCompare(1, 1));// 2. compilation errorSystem.out.println(Compare.String genericCompare(1, new Long(1)));// 3. returns falseSystem.out.println(Compare.genericCompare(1, new Long(1)));}
}class Compare {public static T boolean genericCompare(final T object1, final T object2) {System.out.println(Inside generic);return object1.equals(object2);}
} 好吧让我们分解一下。 第一次调用genericCompare非常简单。 我表示参数类型将是什么类型的方法并提供该类型的两个对象-此处没有奥秘。 由于Long不是String对genericCompare第二次调用无法编译。 最后对genericCompare第三次调用返回false 。 这很奇怪因为该方法被声明为接受相同类型的两个参数但是最好将其传递给String文字和Long对象。 这是由编译期间执行的类型擦除过程引起的。 由于方法调用未使用泛型的String语法因此编译器无法告诉您要传递两种不同的类型。 始终记住最接近的共享继承类型用于查找匹配的方法声明。 意思是当genericCompare接受object1和object2 它们被genericCompare转换为Object 但由于运行时多态性而被比较为String和Long实例–因此该方法返回false 。 现在让我们修改一下代码。 public class GenericMethodInvocation {public static void main(final String[] args) {// 1. returns trueSystem.out.println(Compare.String genericCompare(1, 1));// 2. compilation errorSystem.out.println(Compare.String genericCompare(1, new Long(1)));// 3. returns falseSystem.out.println(Compare.genericCompare(1, new Long(1)));// compilation errorCompare.? extends Number randomMethod();// runs fineCompare.Number randomMethod();}
}class Compare {public static T boolean genericCompare(final T object1, final T object2) {System.out.println(Inside generic);return object1.equals(object2);}public static boolean genericCompare(final String object1, final Long object2) {System.out.println(Inside non-generic);return object1.equals(object2);}public static void randomMethod() {}
} 此新代码示例通过添加genericCompare方法的非泛型版本并定义一个不执行任何操作并从GenericMethodInvocation类的main方法调用两次的新randomMethod来修改Compare类。 由于我提供了与给定调用匹配的新方法因此该代码使对genericCompare的第二次调用genericCompare可能。 但这引发了一个关于另一个奇怪行为的问题–第二个呼叫是否通用 事实证明–不不是。 但是仍然可以使用泛型的String语法。 为了更清楚地展示此功能我使用此通用语法创建了对randomMethod新调用。 再次由于类型擦除过程而实现了这一点-擦除了这种通用语法。 但是当有界通配符出现在舞台上时这种情况会改变。 编译器以编译器错误的形式向我们发送清晰的消息说 Wildcard is not allowed at this location 这使得无法编译代码。 要编译和运行代码必须注释掉第12行。以这种方式修改代码后它将产生以下输出 Inside generic
true
Inside non-generic
false
Inside non-generic
false翻译自: https://www.javacodegeeks.com/2014/06/beauty-and-strangeness-of-generics.html仿制药名言