技术开发 频道

再读Think in Java-高级篇



    问题1:java的访问控制符
    问题2:组件类库和控制“谁能访问类库中组件”
    问题3: java里类的复用
 
    一,隐藏实现

    1.package是类库的单元,当你用import引入一个完整的类库时,这个package就能为你所用了。例如import java.util.*;如果你只想引入某个类,那么你就可以明确的指出,如 import java.util.ArrayList;之所以用import,是因为它提供了一种管理名字空间(name space)的机制.当你把package放到.java文件的开头,你要表达的意思就是:这个编译单元的public类的名字在package name 下面的。任何想使用这个类的人都必须使用它的全名,或者用import 关键词把package引进来。注意:java里约定用全小写表示包的名字。

    为了创建少有的package名字,java的做法是:将所有属于同一个包的.class文件放到同一个目录下面。另外java还约定了package名字的第一部分应该是类的创建者的internate域名的反写。这个技巧的第二部分是将package的名字映射到本地机器内部。

    2.Java的访问控制符
    public,protected,private是java的访问控制符,应该放在类的每个成员的定义部分的前面。不管这个成员是数据还是方法,在java里每样东西都有一个访问控制符。下面我们就说说java里的访问权限:
    (1) 默认的访问权限, 通常又称为package权限。所有同属于这个package的类都能访问这个成员,同时这个类也就有了这个package里的其他类的访问权限,但是对于那些不属于同一个package的类,这个成员就是private的了。
    (2) public :访问接口的权限 ,当你使用public关键词的时候,那么所有的人都可以访问跟在public后面声明的成员。
    (3) private:想碰都碰不到,除非你用这个类(包含这个成员的类)的方法,否则一律不能访问。同一个package里的类也不能访问private成员。
    (4) protected:继承的访问权限,protected关键词处理的就是一种被称为继承的概念。所谓的继承就是选一个已有的类作为基类,然后再不改变现有类的前提下,往里面添加新的成员,你也可以修改基类成员的行为方式。如果你创建了一个新的package,并且其中一个类继承了另一个package里的类,那么你只能访问基类里的public成员(当然如果是同一个package里的继承,你还可以访问package权限的成员).如果基类的创建者只想派生类访问某些成员,其他类不能访问,这就是protected关键词要做的。

    3.接口(interface)与实现(implementation)
    访问权限通常又被称为"隐藏实现"。在将数据和方法集成到了类里的同时,完成“隐藏实现”,这种做法常被称为封装。类的访问权限,不象类里的元素那样丰富,它只有package和public 两种,如果你不希望别人访问这个类,你可以把这个类的构造函数做成private的。那么如何得到这个对象呢?第一,你自己可以用一个静态方法来创建一个对象。第二,它只允许你创建一个这个类的对象。这个对象是被当作类的static private 成员创建的,然后通过一个public 方法返回这个对象即可。



    二,复用类
    1,java代码的复用有两种方法,第一种非常简单:在新的类里直接创建旧类的对象,这被称为合成(compostion),因为新的类是由旧的类合成来的,所以你只是复用了代码的功能。第二种方法比较神奇,它会创建一个新的,与原来那个类同属于一类型的类,这种做法被称为继承(inheritance) 合成的语法:合成很简单,你只要把对象的reference直接放到新的类里面就行了,先前我们讲过reference会被初使化为null,如果这个时候你去调用这个对象的方法,就会得到异常。如果你想为reference初始化,你可以在以下时间进行:
    (1),在定义对象的时候,在调用构造函数前,他们已经被初使化完毕了。
    (2),在这个类的构造函数里。
    (3),在即将使用那个对象前,如果碰到创建这个对象代价太高,或者不是每次都需要创建对象的时候,这种做法就能降低程序的开销了。下面这段代码演示了在三种情况下实例化对象,
class Cups{ private String s = new String (“hello”);// 在定义对象的时候 private String t; private String s1; Cups(){ t = new String(“constructed”);//构造函数里定义 } public String toString(){ if (s1 == null){ s1 = new String (“welcome”);//用到的时候 } return s1; } }
    对于Cups类的toString 方法,所有非primi tive类型的类都有一个toString方法,当编译器需要一个String却得到一个对象的时候,就会调用对象的这方法。s这样派生类就有了基类的全部成员和方法。现在你要创建一个派生类的对象已经不是一个类的事情了,他会涉及到两个类(基类和派生类).实际上当你创建一个派生类的对象的时候,这里面还有一个基类的子对象.这个子对象和基类创建的对象没有什么两样。

    java会用派生类的构造函数自动调用基类的构造函数,其构造的顺序为从基类向外发展,在基类的构造函数没有参数的情况下,即便是你不写构造函数,派生类会去调用默认的构造函数,但是如果基类构造函数带有参数怎么办?有办法:通过在派生类构造函数里使用super(参数)调用基类构造函数即可.


    2,把合成和继承结合起来:
    课堂(派生类)
    黑板(基类)--投影仪(派生类)(合成课堂)
    板凳(基类)--高级板凳(派生类)--皮椅(派生类) (合成课堂)
    普通教室(基类)--多媒体教室(派生类) (合成课堂)
    上课人(基类)
    你可以试着把课堂类通过继承(上课人基类),合成(投影仪,皮椅,多媒体教室类)生成。注意虽然编译器能强制基类初始化,但是不会检查成员是不是进行了初始化.
    当你对一个方法在基类里重载了n次,并且在派生类里对其中某个进行了重写,但是不会把基类里的任何一个方法给遮盖的。

    3,用合成还是继承
    一般来说,合成用于新类要使用旧类的功能,而不是其接口的场合,也就是说,把对象嵌进去,用它来实现新类的功能,而嵌进去的这个对象一般也是private的对象。继承则是对已有类进行改造,来获得一个特殊的类。总之,一句话,合成要表达的是一种‘有’的关系,继承表达的是一种‘是’的关系。说到这里,我们就知道protected关键词的意义了,在继承里,如果你想某些东西(数据成员,方法)不被外界知道,而又想对它的继承类开放,用protected就可以做到。

    4,上传
    继承最重要的特征不在于它为新类提供了现成的方法,而是它表达新类和旧类的关系把派生类传给基类,就是沿继承图向上送,因此被称为上传(upcasting)。上传总是安全的,因为你是把一个具体的类型转化成了一般的类型。下面就通过一个例子来说明:
class Person{ public void sleep(){}; static void getSleep( Person p){ p.sleep(); } } public class Student extends Person{ public static void main(String[] args){ Students st = new Students(); Person.getSleep(st); } }


    5,final关键词

    final的三种用途:数据(data),方法(method),类(class)常量用于下列情况:1,编译时的常量,这样就在也不能更改了。Java里这种变量必须是primitive的,而且要用final关键词表示。2,运行时初始化的值,这个值你以后就不想修改了。

    一个被static和final修饰的数据成员只会占据一段内存,并且不可以修改。对于primitive来说,final会将这个值定义成常量,当一个final不是指primitive而是一个对象的reference的时候,final的意思是这个reference是一个常量,一旦将这个reference连到某个对象后,那么他再也不能指向别的对象了。但是这个对象是可以修改的,不是常量(听起来挺好笑的)。Java里通常约定,
被初使化为常量的final static的primitive类型的名字全都用大写,词与词之间用下划线分开。

    final方法,有两个作用,第一,是为方法加锁,禁止派生类进行继承,如果你希望某个方法在继承当中保留下来,并且不被重写,你就可以使用这个方法。第二,就是效率,如果方法是final的,那么编译器会把调用转换成“内联的”。不过final的这个作用不怎么常用,而常常被用来明确的表示要禁止重写的场合。其实private 方法也隐含了final的意思,由于你不能访问private 方法,所以你也不能重写它。
    final类,把整个类定义成final的,那么这个类就不允许被继承了,String类就是一个final的类。

    6,初始化和类的装载
    类的装载,是在第一次创建这个类的对象的时候,但是在访问static数据和static方法也会装载。第一次使用static数据的时候也是static数据初始化的时候,static对象和static代码段会按照字面顺序初始化的。下面就用一个流程图来展示下:java编译器先访问派生类的mian(),装载派生类—基类—基类(static)变量初始化—派生类(static)变量初始化.类装载结束后,就可以创建对象了。首先对象的primitive被设为缺省值,reference被设为null,然后调用基类的构造函数,你也可以使用super来指定调用基类那个构造函数(这是派生类里构造函数要做的第一件事情)。
0
相关文章