安阳后营300一次贵不贵,seo外链软件,wordpress怎么添加主页,私自使用他人图片做网站宣传本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题#xff0c;包括对象创建#xff0c;并发#xff0c;序列化#xff0c;反射等。 它将指导您完成Java掌握的过程#xff01; 在这里查看 #xff01; 目录 1.简… 本文是我们名为“ 高级Java ”的学院课程的一部分。 本课程旨在帮助您最有效地使用Java。 它讨论了高级主题包括对象创建并发序列化反射等。 它将指导您完成Java掌握的过程 在这里查看 目录 1.简介 2.接口 3.标记接口 4.功能接口默认方法和静态方法 5.抽象类 6.不可变的类 7.匿名类 8.可见度 9.继承 10.多重继承 11.继承与组成 12.封装 13.期末课程和方法 14.接下来 15.下载源代码 1.简介 不管您使用哪种编程语言这里Java也不例外遵循良好的设计原则是编写简洁可理解可测试的代码并提供长期有效且易于维护的解决方案的关键因素。 在本教程的这一部分中我们将讨论Java语言提供的基础构建块并介绍一些设计原则以帮助您做出更好的设计决策。 更确切地说我们将讨论与默认的方法 接口和接口 Java 8的新功能 抽象和final 类不可变类继承组成和重温了一下可见性 或可访问的规则我们有部分短暂触及教程1 如何创建和销毁对象 。 2.接口 在面向对象的编程中接口的概念构成了契约驱动或基于契约开发的基础。 简而言之接口定义方法的集合契约并且声称支持该特定接口的每个类都必须提供这些方法的实现一个非常简单但功能强大的想法。 许多编程语言确实具有一种形式或另一种形式的接口但是Java特别为此提供了语言支持。 让我们看一下Java中的简单接口定义。 package com.javacodegeeks.advanced.design;public interface SimpleInterface {void performAction();
} 在上面的代码片段中我们命名为SimpleInterface的接口SimpleInterface声明了一个名为performAction方法。 接口相对于类的主要区别在于接口概述了联系方式声明方法但未提供其实现。 但是Java中的接口可能比这更复杂它们可以包括嵌套的接口类枚举注释该枚举和注释将在本教程的第5部分中详细介绍如何以及何时使用Enums和Annotations 和常量。 。 例如 package com.javacodegeeks.advanced.design;public interface InterfaceWithDefinitions {String CONSTANT CONSTANT;enum InnerEnum {E1, E2;}class InnerClass {}interface InnerInterface {void performInnerAction();}void performAction();
} 在这个更复杂的示例中存在一些关于嵌套构造和方法声明的接口隐式施加的约束而Java编译器则强制执行这些约束。 首先即使没有明确说明该接口中的每个声明都是公共的 并且只能是public 有关可见性和可访问性规则的更多详细信息请参阅Visibility部分。 因此以下方法声明是等效的 public void performAction();
void performAction(); 值得一提的是接口中的每个方法都隐式声明为抽象 甚至这些方法声明也是等效的 public abstract void performAction();
public void performAction();
void performAction(); 至于常量字段声明除了是public 它们是隐式static和final因此以下声明也等效 String CONSTANT CONSTANT;
public static final String CONSTANT CONSTANT; 最后除了public之外嵌套类接口或枚举还隐式声明为static 。 例如这些类声明也等效 class InnerClass {
}static class InnerClass {
} 您将选择哪种样式是个人喜好但是了解这些简单的界面质量可以使您避免不必要的键入。 3.标记接口 标记接口是一种特殊的接口没有定义任何方法或其他嵌套结构。 在本教程的第2部分中 我们已经看到了标记接口的一个示例该接口使用所有对象共有的方法 即Cloneable接口。 这是在Java库中定义的方式 public interface Cloneable {
} 标记接口本身并不是契约而是某种有用的技术用于“附加”或“绑定”类的某些特定特征。 例如对于Cloneable 该类被标记为可用于克隆但是它应该或可以做的方式不是接口的一部分。 标记接口的另一个非常著名且广泛使用的示例是Serializable public interface Serializable {
} 此接口将类标记为可用于序列化和反序列化并且再次它未指定可以或应该完成的方式。 标记器接口虽然不能满足作为合同的接口的主要目的但在面向对象的设计中仍占有一席之地。 4.功能接口默认方法和静态方法 随着Java 8的发布 接口获得了非常有趣的新功能静态方法默认方法和lambda功能性接口的自动转换。 在接口一节中我们强调了以下事实Java中的接口只能声明方法而不能提供其实现。 使用默认方法不再是事实接口可以使用default关键字标记方法并为其提供实现。 例如 package com.javacodegeeks.advanced.design;public interface InterfaceWithDefaultMethods {void performAction();default void performDefaulAction() {// Implementation here}
} 作为实例级别默认方法可以被每个接口实现者覆盖但是从现在开始接口还可以包括static方法例如 package com.javacodegeeks.advanced.design;public interface InterfaceWithDefaultMethods {static void createAction() {// Implementation here}
} 可能有人说在接口中提供实现会破坏基于契约的开发的全部目的但是将这些功能引入Java语言有很多原因无论它们多么有用或令人困惑它们都可以为您提供帮助采用。 功能接口是另外一个故事并且事实证明它们是该语言的非常有用的附加组件。 基本上功能接口是仅声明了一个抽象方法的接口。 Java标准库中的Runnable接口就是这个概念的一个很好的例子 FunctionalInterface
public interface Runnable {void run();
} Java编译器以不同的方式对待功能接口并且能够将lambda函数转换为有意义的功能接口实现。 让我们看一下以下函数定义 public void runMe( final Runnable r ) {r.run();
} 要在Java 7及以下版本中调用此函数应提供Runnable接口的实现例如使用Anonymous类 但是在Java 8中使用lambda语法传递run()方法实现就足够了 runMe( () - System.out.println( Run! ) ); 此外 FunctionalInterface批注批注将在本教程的第5部分“ 如何以及何时使用Enums和Annotations”中详细介绍 提示编译器验证接口仅包含一种抽象方法以便对接口中引入的任何更改未来将不会打破这一假设。 5.抽象类 Java语言支持的另一个有趣的概念是抽象类的概念。 抽象类在某种程度上类似于Java 7中的接口并且与Java 8中具有默认方法的接口非常接近。与常规类相比抽象类无法实例化但可以被子类化请参阅继承一节以获取更多详细信息。 更重要的是抽象类可能包含抽象方法没有实现的特殊方法就像接口一样。 例如 package com.javacodegeeks.advanced.design;public abstract class SimpleAbstractClass {public void performAction() {// Implementation here}public abstract void performAnotherAction();
} 在此示例中类SimpleAbstractClass被声明为abstract并且还具有一个abstract方法声明。 当实现细节的大部分甚至一部分可以被许多子类共享时抽象类非常有用。 但是它们仍然敞开了大门并允许通过抽象方法自定义每个子类的固有行为。 值得一提的是与只能包含public声明的接口相反抽象类可以使用可访问性规则的全部功能来控制抽象方法的可见性有关更多详细信息请参见“ 可见性和继承 ”部分。 6.不可变的类 不可变性在当今的软件开发中变得越来越重要。 多核系统的兴起引起了很多与数据共享和并发相关的担忧在第9部分 并发最佳实践中 我们将详细讨论那些主题。 但是肯定会出现一件事可变状态的减少甚至不存在导致更好的可伸缩性和系统的简化推理。 不幸的是Java语言没有为类不变性提供强大的支持。 但是结合使用多种技术可以设计不可变的类。 首先该类的所有字段都应该是final 。 这是一个好的开始但不能单独保证不变性。 package com.javacodegeeks.advanced.design;import java.util.Collection;public class ImmutableClass {private final long id;private final String[] arrayOfStrings;private final Collection String collectionOfString;
} 其次遵循适当的初始化如果字段是对集合或数组的引用请不要直接从构造函数参数中分配这些字段而应创建副本。 这将确保集合或数组的状态不会从外部更改。 public ImmutableClass( final long id, final String[] arrayOfStrings,final Collection String collectionOfString) {this.id id;this.arrayOfStrings Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );this.collectionOfString new ArrayList( collectionOfString );
} 最后提供适当的访问器获取器。 对于集合不可变视图应使用Collections.unmodifiableXxx包装器公开。 public CollectionString getCollectionOfString() {return Collections.unmodifiableCollection( collectionOfString );
} 对于数组确保真正的不变性的唯一方法是提供副本而不是返回对数组的引用。 从实际的角度来看这可能是不可接受的因为它在很大程度上取决于数组的大小并可能给垃圾收集器带来很大压力。 public String[] getArrayOfStrings() {return Arrays.copyOf( arrayOfStrings, arrayOfStrings.length );
} 即使是这个很小的例子也提供了一个很好的主意即不变性还不是Java中的一等公民。 如果一个不可变的类具有引用另一个类实例的字段那么事情就会变得非常复杂。 这些类也应该是不可变的但是没有简单的方法可以强制执行。 有很多很棒的Java源代码分析器例如FindBugs和PMD 它们可以通过检查代码并指出常见的Java编程缺陷来提供很多帮助。 这些工具是任何Java开发人员的好朋友。 7.匿名类 在Java 8之前的时代匿名类是提供就地类定义和即时实例化的唯一方法。 匿名类的目的是减少样板并提供简洁明了的方式将类表示为表达式。 让我们看一下在Java中产生新线程的典型老式方法 package com.javacodegeeks.advanced.design;public class AnonymousClass {public static void main( String[] args ) {new Thread(// Example of creating anonymous class which implements// Runnable interfacenew Runnable() {Overridepublic void run() {// Implementation here}}).start();}
} 在此示例中 Runnable接口的实现作为匿名类就地提供。 尽管匿名类存在一些限制但使用它们的基本缺点是Java强制将其作为语言使用的语法结构非常冗长。 即使是最简单的不执行任何操作的匿名类每次都至少需要编写5行代码。 new Runnable() {Overridepublic void run() {}} 幸运的是有了Java 8lambda和功能接口所有这些样板都将消失最终使Java代码看起来非常简洁。 package com.javacodegeeks.advanced.design;public class AnonymousClass {public static void main( String[] args ) {new Thread( () - { /* Implementation here */ } ).start();}
}8.可见度 在本教程的第1部分“ 如何设计类和接口”中 我们已经讨论了Java可见性和可访问性规则。 在这一部分中我们将再次回到该主题但要涉及子类化。 修饰符 包 子类 其他所有人 上市 无障碍 无障碍 无障碍 受保护的 无障碍 无障碍 无法访问 无修饰符 无障碍 无法访问 无法访问 私人的 无法访问 无法访问 无法访问 表格1 不同的可见性级别允许或不允许这些类查看其他类或接口例如如果它们位于不同的程序包中或彼此嵌套或子类查看和访问其父级的方法构造函数和字段。 在下一节Inheritance中 我们将看到它的作用。 9.继承 继承是面向对象编程的关键概念之一它是建立类关系的基础。 与可见性和可访问性规则结合使用继承可以设计可扩展和可维护的类层次结构。 从概念上讲Java中的继承是通过使用子类和extends关键字以及父类来实现的。 子类继承其父类的所有公共成员和受保护成员。 此外如果子类都驻留在同一包中则它们继承父类的包私有成员。 话虽如此无论您要设计什么保持类公开或对其子类公开的最小方法集都是非常重要的。 例如让我们看一下Parent类及其子类Child以演示不同的可见性级别及其效果 package com.javacodegeeks.advanced.design;public class Parent {// Everyone can see itpublic static final String CONSTANT Constant;// No one can access itprivate String privateField;// Only subclasses can access itprotected String protectedField;// No one can see itprivate class PrivateClass {}// Only visible to subclassesprotected interface ProtectedInterface {}// Everyone can call itpublic void publicAction() {}// Only subclass can call itprotected void protectedAction() {}// No one can call itprivate void privateAction() {}// Only subclasses in the same package can call itvoid packageAction() {}
}package com.javacodegeeks.advanced.design;// Resides in the same package as parent class
public class Child extends Parent implements Parent.ProtectedInterface {Overrideprotected void protectedAction() {// Calls parents method implementationsuper.protectedAction();}Overridevoid packageAction() {// Do nothing, no call to parents method implementation}public void childAction() {this.protectedField value;}
} 继承本身就是一个非常大的主题其中包含许多特定于Java的细微细节。 但是有一些易于遵循的规则可以对保持类层次结构简洁有很大帮助。 在Java中每个子类都可以覆盖其父类的任何继承的方法除非将其声明为final 请参阅Final类和方法部分 。 但是没有特殊的语法或关键字来将方法标记为已重写这可能会引起很多混乱。 这就是引入Override批注的原因每当您打算覆盖继承的方法时请始终使用Override批注进行指示。 Java开发人员在设计中经常面临的另一个难题是构建类层次结构使用具体或抽象类与接口实现。 强烈建议尽可能使用接口而不是类或抽象类。 接口轻巧得多易于测试使用模拟和维护并且使实现更改的副作用最小化。 许多高级编程技术例如在标准Java库中创建类代理都严重依赖于接口。 10.多重继承 与C 和其他一些语言相比Java不支持多重继承在Java中每个类都只有一个直接父级 Object类位于层次结构的顶部正如我们在本教程的第2部分中已经知道的那样 使用通用方法。到所有对象 。 但是该类可以实现多个接口因此堆叠接口是在Java中实现或模仿多重继承的唯一方法。 package com.javacodegeeks.advanced.design;public class MultipleInterfaces implements Runnable, AutoCloseable {Overridepublic void run() {// Some implementation here}Overridepublic void close() throws Exception {// Some implementation here}
} 多个接口的实现实际上是非常强大的但是重用实现的需求通常会导致深层次的类层次结构这是克服Java中缺少多继承支持的一种方法。 public class A implements Runnable {Overridepublic void run() {// Some implementation here}
}// Class B wants to inherit the implementation of run() method from class A.
public class B extends A implements AutoCloseable {Overridepublic void close() throws Exception {// Some implementation here}
}// Class C wants to inherit the implementation of run() method from class A
// and the implementation of close() method from class B.
public class C extends B implements Readable {Overridepublic int read(java.nio.CharBuffer cb) throws IOException {// Some implementation here}
} 依此类推...最近的Java 8版本通过引入默认方法在某种程度上解决了该问题。 由于使用默认方法因此接口实际上已经开始不仅提供合同而且还提供实现。 因此实现这些接口的类也将自动继承这些实现的方法。 例如 package com.javacodegeeks.advanced.design;public interface DefaultMethods extends Runnable, AutoCloseable {Overridedefault void run() {// Some implementation here}Overridedefault void close() throws Exception {// Some implementation here}
}// Class C inherits the implementation of run() and close() methods from the
// DefaultMethods interface.
public class C implements DefaultMethods, Readable {Overridepublic int read(java.nio.CharBuffer cb) throws IOException {// Some implementation here}
} 请注意多重继承是一种强大的工具但同时又是一种危险的工具。 通常将众所周知的“死亡钻石”问题称为多重继承实现的基本缺陷因此敦促开发人员非常仔细地设计类层次结构。 不幸的是具有默认方法的Java 8接口也正成为这些漏洞的受害者。 interface A {default void performAction() {}
}interface B extends A {Overridedefault void performAction() {}
}interface C extends A {Overridedefault void performAction() {}
} 例如以下代码片段无法编译 // E is not compilable unless it overrides performAction() as well
interface E extends B, C {
} 在这一点上可以说Java作为一种语言总是试图逃避面向对象编程的极端情况但是随着语言的发展其中一些情况开始出现。 11.继承与组成 幸运的是继承不是设计类的唯一方法。 许多开发人员认为比继承更好的另一种选择是组合。 这个想法很简单这些类应该由其他类组成而不是建立类层次结构。 让我们看一下这个例子 public class Vehicle {private Engine engine;private Wheels[] wheels;// ...
} Vehicle类由engine和wheels 加上许多其他零件为简单起见而保留。 但是可以说Vehicle类也是一种引擎因此可以使用继承进行设计。 public class Vehicle extends Engine {private Wheels[] wheels;// ...
} 哪个设计决定是正确的 一般准则称为IS-A和HAS-A原则。 IS-A是继承关系子类还满足父类规范以及父类的此类IS-A变体。 因此 HAS-A是组成关系该类拥有或HAS-A 属于它的对象。 在大多数情况下 HAS-A原理比IS-A更好其原因有两个 设计可以更改的方式更加灵活 该模型更加稳定因为更改不会通过类层次结构传播 与继承紧密关联父级及其子类的继承相比该类及其组合之间的关联松散 关于类的推理更加简单因为所有相关性都包含在其中 但是继承有其自己的位置以不同的方式解决了实际的设计问题因此不应忽略。 在设计面向对象的模型时请牢记这两种选择。 12.封装 面向对象编程中的封装概念全是向外界隐藏实现细节如状态内部方法等。 封装的好处是可维护性和易于更改。 内在细节类暴露的越少开发人员对更改其内部实现的控制就越多而不必担心破坏现有代码如果您正在开发许多人使用的库或框架这将是一个真正的问题。 Java中的封装是使用可见性和可访问性规则实现的。 在Java中最好不要使用getter和setter方法如果未将字段声明为final 直接暴露字段这是Java的最佳实践。 例如 package com.javacodegeeks.advanced.design;public class Encapsulation {private final String email;private String address;public Encapsulation( final String email ) {this.email email;}public String getAddress() {return address;}public void setAddress(String address) {this.address address;}public String getEmail() {return email;}
} 此示例类似于Java语言中所谓的JavaBeans 通过遵循一组约定编写的常规Java类其中一种仅允许使用getter和setter方法访问字段。 正如我们在“ 继承”部分中已强调的那样请始终遵循封装原则尝试使类公共契约保持最小。 无论什么都不应该是public 而应该是private 或protected / package private 这取决于您要解决的问题。 从长远来看它将带来回报使您可以自由开发设计而无需引入重大更改或至少将更改减至最少。 13.期末课程和方法 在Java中有一种方法可以防止该类被其他任何类继承应该将其声明为final 。 package com.javacodegeeks.advanced.design;public final class FinalClass {
} 方法声明中使用相同的final关键字可防止所讨论的方法在子类中被覆盖。 package com.javacodegeeks.advanced.design;public class FinalMethod {public final void performAction() {}
} 没有通用的规则来决定类或方法是否应该是final 。 最终类和方法限制了可扩展性并且很难预先考虑该类是否应该被子类化或者方法是否应该被覆盖。 这对于库开发人员尤其重要因为这样的设计决策可能会大大限制库的适用性。 Java标准库提供了一些final类的示例其中最著名的是String类。 在早期阶段已做出决定来主动防止任何开发人员尝试提出自己的“更好的”字符串实现。 14.接下来 在本教程的这一部分中我们研究了Java中的面向对象设计概念。 我们还简要地介绍了基于合同的开发介绍了一些功能概念并了解了该语言如何随着时间演变。 在本教程的下一部分中我们将讨论泛型以及泛型如何改变我们处理类型安全编程的方式。 15.下载源代码 这是关于如何设计类和接口的课程。 您可以在此处下载源代码 advanced-java-part-3 翻译自: https://www.javacodegeeks.com/2015/09/how-to-design-classes-and-interfaces.html