最近在学习echo3源码时忽然发现自己对java的很多基础知识还是没有掌握,很多语法从前根本就没想过还可以这么用的!比如echo3对内部类、内部接口、静态构造、对象组合等出神入化的应用,直叫人叹为观止呀。有感于自己基础之薄弱,重新拾起《java核心技术,卷一》一书,复习一下一些重要语法知识及某些以前不太在意的基础语法。特作如下笔记。
一、接口
1、主要用来描述类具有什么功能,而并不给出这些功能的具体实现。
2、接口的方法自动属于public的,因此在声明方法不必显式地提供public关键字。在实现类中最好也声明为public的,否则编译器会给出弱访问权限的警告信息。
3、在接口中可以定义常量,常量自动具有public static final属性。
4、接口中绝不能含有实例域,也不能在接口中实现方法。可以将接口看成是没有实例域的抽象类。
5、接口不可实例化但可用于声明对象,也可用于对象的instanceof 方法。
6、有关Cloneable接口:Object类中提供了protected clone方法,子类是若需提供克隆功能,则必须实现Cloneable接口,重新声明一个public clone方法。若克隆时只须浅拷贝,则直接调用super.clone()即可,但若需深拷贝,则只能自定义了。
7、标记接口:Cloneable,Serialable等接口,这此接口没有提供任何方法,仅做为一个标记。使用它们的唯一目的是可以用instanceof 进行类型检查。
8、回调:事件监听器
二、内部类
1、内部类是定义在另一个类中的类,使用内部类的特点:
- 内部类可以访问外部类的数据,包括私有数据。
- 内部类对同一包中的其它类隐藏。
- 可以通过定义匿名内部类实现便捷回调。
- 内部类是一种编译器现象,与虚拟机无关。编译器将内部类翻译成用$将外部类名与内部类名分开的常规类文件,虚拟机对此类文件不做特殊处理。
2、局部内部类:不能用public或private修饰符进行声明,它的作用域限定在声明它的块中,比如声明这个局部类的方法中,它只能由声明它的块访问,任何类甚至它的外围类的其它方法都访问不到它。局部内容类除可以访问外围类的域外,还可访问局部变量,不过要求这些局部变量是final的。实际上,编译器为局部内部类声明了一个final的域,用以存储对局部变量的拷贝。
3、匿名内部类:没有类名,直接创建其实现。针对接口创建的匿名内部类即是对该接口的一个匿名实现,针对类创建的匿名内部类则是创建该类的一个匿名子类。匿名内部类没有构造器,因为这它没有类名。
- 对接口的匿名实现:new IntefaceType(){method and data}
- 对类的匿名子类:new ClassType(param){method and data}
4、静态内部类:当内部类无须引用外围类的域时可以将其声明为static的,这样就取消对外围类的引用。
5、代理:在运行时动态创建实现一组接口的新类 。注意,代理类是在运行期间动态创建的,所有代理类扩展于Proxy类,在Proxy基类中定义了一个InvocationHandler实例变量,这个实例变量实现InvocationHandler接口,对代理对象中所代理接口方法的调用最后会被转发到这个InvocationHandler实例变量的invoke方法,通过该方法实现对实际对象指定方法的调用。
三、断言
1、断言的两种形式:
- assert 条件
- assert 条件:表达式
断言会对条件进行判断,若条件为false,则抛出一个AssertionError异常。第二种形式下会将表达式传入AssertionError对象的构造器,转换成一个消息字符串。
2、jdk5默认支持断言,1.4在编译时需要使用javac -source 1.4来支持断言。
默认情况下断言是禁用的。运行程序时可通过-enableassertions或-ea来启用,通过-disableassertions或-da来禁用。
3、使用断言的注意事项:
- 断言失败是致命的、不可恢复的错误;
- 断言检查只用于开发和测试阶段。
四、泛型
1、泛型程序设计意味着所写的代码可以被许多不同类型的对象重用。在jdk5以前泛型通过继承和强制类型转换来实现,jdk5通过类型参数来提供泛型支持。例如ArrayList<T>有一个类型参数T,它指示ArrayList对象的元素类型为T,当调用get方法时编译器知道返回值类型为T,不再需要通过类型转换到T,而调用add方法添加元素时,编译器只允许T类型的元素被添加到集合中。故通过泛型可以提高程序的可读性和安全性。
2、类型变量限定:
<T extends BoundingType>
表示T应该是绑定类型(BoundingType)的子类型。
一个类型变量可以有多个限定:T extends BT1 & BT2,限定中可以有多个接口,但只能有一个类。
3、JVM会为每个泛型类型提供其原始类型实现,一个泛型的原始类型名即为该泛型类去除类型参数后的名字,其泛型变量被擦除,用泛型变量的相应限定类型(无限定类型的用Object)来替代。
五、流与文件
1、输入流:可以读取字节序列的对象。输出流:可以写入字节序列的对象。类InputStream与OutputStream分别对应,而抽象类Reader与Writer则读取双字节的Unicode码。
java.io.InputStream
- abstract int read():读取一个字节的数据并将其返回;当读到流的末尾时,返回-1。这是个抽象方法,需要具体的流来实现。该类的其它方法如read(int[])、skip等方法将会调用本方法。
- int read(byte[] b):将数据读取到字节数组中,返回实际读取的字节数目。当到达流末尾时调用此方法返回-1。
- int read(byte[] b,int off,int len):同上,但数组从off处开始存储,读取的字节数目最大为len。
- long skip(long n):在输入流中跳过n个字节,返回实际跳过的字节数。
- int available():返回可用的未阻塞的字节数。
2、StringBuilder与StringBuffer:二者提供一致的API,区别在于:
- StringBuffer是线程安全的
- StringBuilder是jdk5提供的,非线程安全,但效率较前者稍高。
在单线程环境下应该用StringBuilder。
六、访问修饰符总结
1、priate--仅对本类可见
2、public--对所有类可见
3、protected--对本包和所有子类可见
4、默认--对本包可见
六、移位运算
<< | 向左移位,从右边补0 | 相当于乘以2的幂 |
>> | 向右移位,从左边补符号位 | 相当于除以2的幂 |
>>> | 向右移位,从左边补0 | 相当于除以2的幂 |