虽然Java只支持从一个父类继承但它使用接口的方式支持多重继承 接口实现了多态使得我们能够给与对象不同特性以满足不同的需要 你可以使用多态机制让完成相似功能的不同的方法拥有相同的名字但是拥有不同的参数列表 动态/运行时的绑定机制允许一个对象在运行时被强制转化成你所需要的对象类型前提是这个对象实现了必需的接口或者括展了特定的父类 下面我们将讨论通过限制对对象属性和方法的访问来强制实现对多重接口实现和父类拓展的正确使用的目的和实用性 黑箱方法:封装 一个基本的面向对象的概念就是封装将表示一个对象状态的数据与其它对象隔离开来这一点是通过一个通常叫做作用域的概念来实现的作用域指的是编程语言的一种能力这种能力被用来实现一些限制对类或者结构体成员变量的访问的规则大多数面向对象的语言支持作用域机制这些机制通常是通过诸如public protected 和 private之类的特殊关键字来实现的 Java提供了四种不同的作用范围:public package protected 和 private任何类方法或者成员变量都能通过使用public protected 和 private关键字来显式的加以保护任何类方法或者成员变量如果没有使用上面的关键字都将被隐式的给与package的作用范围所有这些就构成了Java中命名空间的概念 命名空间和软件包 一个命名空间可以被看成是在一个给定的上下文中一组相关的名字或是标识符命名空间避免了拥有相同名字或标识符的实体存在于同一个上下文里这里隐含的意思是只要实体是存在于不同的命名空间中那么拥有相同名字或者标识符的实体就能够呆在一块儿Java使用软件包的概念来实现命名空间和作用范围控制 软件包是一个在统一的名字下的类和接口的集合每一个类或者接口都必须存在于用package关键字构成的软件包申明语句定义的命名空间中例如下面的申明语句: package commycompanyappsHelloWorld; 它申明了一个存在于commycompanyapps软件包中的名叫HelloWorld的类或者接口软件包申明总是放在包含了类或者接口定义的文件的顶部 在java开发界目前对软件包的命名有一个建议就是使用公司或组织的域名(以相反的顺序)作为你的软件包的第一部分因为域名是全球唯一的所以使用你的域名来命名你的软件包也能使你软件包的名字全球唯一 如果一个Java类或者接口没有包含一个软件包申明那么它就属于unamed package也就是没有名字的软件包无名的软件包应该只用来测试程序或是代码原型等等 请尽量使用封装机制 在任何程序风格中尤其是在面向对象的编程中将暴露的编程界面背后的实现细节隐藏起来是非常关键的这使得低层的实现方法能够在不影响编程界面现有的客户端的前提下改变而且能使对象完全自主的管理它们自己的状态 分离界面和实现方法的第一步就是隐藏类的内部数据要使一个成员变量或是方法对Java中所有潜在的客户不可见可以将用private关键字将它声明为私有成员变量如下所示: private int customerCount; 要使一个成员变量或是方法除了其本身所属类的子类以外对Java中所有潜在的客户不可见可以使用protected关键字将它声明成保护类型的如下所示: protected int customerCount; 要使一个成员变量或是方法除了其本身所属的类以外对Java中所有潜在的客户不可见不使用任何关键字来声明它如下所示: int customerCount; 要将一个成员变量或是方法暴露给其所属类的所有客户可以用public关键字将它声明为公共的成员变量如下所示: public int customerCount; 访问成员变量 不论一个对象的数据隐藏得多么好客户仍然需要访问一些隐藏的数据这是通过调用函数或方法来实现的在Java中使用特殊的被称做属性访问器的方法来访问隐藏的数据是可能的在Java中属性访问器和通常的函数之间并没有本质的区别将一个通常的方法转变成一个属性访问器唯一要做的事情就是参照一个命名规则来添加方法 读数据的访问器的命名规则就是将方法命名为和数据域一样的名字将首字母大写然后在方法名字的前面添加get或是is写数据访问器的命名规则就是将方法命名为和数据域一样的名字将首字母大写然后在方法名字的前面添加set下面的例子演示了写和读数据的数据访问器方法 这是一个读数据访问器方法: public int getCustomerCount() { return(customerCount); } 这是另一个读数据访问器方法 public int isCustomerActive() { return(customerActive); } 这是一个写数据访问器方法: public void setCustomerCount(int newValue) { customerCount = newValue; } 使用访问器方法允许其它对象访问一个对象的隐藏数据而不直接涉及数据域这就允许拥有隐含数据的对象在改变成员变量以前做正确性检查并控制成员变量是否应该被设置成新的值 现在让我们修改例子程序来使用这些概念如下所示 public class HelloWorld { public static void main(String[] args) { Dog animal = new Dog(); Cat animal = new Cat(); Duck animal = new Duck(); animalsetMood(AnimalCOMFORTED); Systemoutprintln(A comforted dog says +animalgetHello()); animalsetMood(AnimalSCARED); Systemoutprintln(A scared dog says +animalgetHello()); Systemoutprintln(Is a dog carnivorous? +animalisCarnivorous()); Systemoutprintln(Is a dog a mammal? +animalisCarnivorous()); animalsetMood(AnimalCOMFORTED); Systemoutprintln(A comforted cat says +animalgetHello()); animalsetMood(AnimalSCARED); Systemoutprintln(A scared cat says +animalgetHello()); Systemoutprintln(Is a cat carnivorous? +animalisCarnivorous()); Systemoutprintln(Is a cat a mammal? +animalisCarnivorous()); animalsetMood(AnimalCOMFORTED); Systemoutprintln(A comforted duck says +animalgetHello()); animalsetMood(AnimalSCARED); Systemoutprintln(A scared duck says +animalgetHello()); Systemoutprintln(Is a duck carnivorous? +animalisCarnivorous()); Systemoutprintln(Is a duck a mammal? +animalisCarnivorous()); } } abstract class Animal { // The two following fields are declared as public because they need to be // accessed by all clients public static final int SCARED = ; public static final int COMFORTED = ; // The following fields are declared as protected because they need to be // accessed only by descendant classes protected boolean mammal = false; protected boolean carnivorous = false; protected int mood = COMFORTED ; public boolean isMammal() { return(mammal); } public boolean isCarnivorous() { return(carnivorous); } abstract public String getHello(); public void setMood(int newValue) { mood = newValue; } public int getMood() { return(mood); } } interface LandAnimal { public int getNumberOfLegs(); public boolean getTailFlag(); } interface WaterAnimal { public boolean getGillFlag(); public boolean getLaysEggs(); } class Dog extends Animal implements LandAnimal { // The following fields are declared private because they do not need to be // access by any other classes besides this one private int numberOfLegs = ; private boolean tailFlag = true; // Default constructor to make sure our properties are set correctly public Dog() { mammal = true; carnivorous = true; } // methods that override superclasss implementation public String getHello() { switch (mood) { case SCARED: return(Growl); case COMFORTED: return |