5.1 static 关键字
static 可以修饰类的成员变量、成员方法和内部类。它与具体实例不相关;
5.1.1 类变量/静态变量。
静态变量:使用static 声明的变量。它在系统加载其所在类时分配空间并初始化,并且在创建类的实例时不再分配空间,所有的实例将共享静态变量。因此可用来在实例之间通信及跟踪该类实例的数
例5-1 Count类的对象赋予递增的序列号
class Count{
private int serialNumber ;
public static int counter = 0 ;
public Count( ){
counter++ ;
serialNumber = counter ;
}
public int getSerialNumber(){
return serialNumber;
}
}
public class TestStaticVar{
public static void main(String[] args){
Count[] cc = new Count[10];
for(int i=0;i<cc.length;i++){
cc[i]=new Count();
System.out.println("cc["+i+"].serialNumber = "+cc[i].getSerialNumber());
}
}
}
cc[0].serialNumber = 1
cc[1].serialNumber = 2
cc[2].serialNumber = 3
cc[3].serialNumber = 4
cc[4].serialNumber = 5
cc[5].serialNumber = 6
cc[6].serialNumber = 7
cc[7].serialNumber = 8
cc[8].serialNumber = 9
cc[9].serialNumber = 10
class GeneralFunction{
public static int add(int x, int y){
return x+y ;
}
}
public class UseGeneral{
public static void main(String[] args){
int c = GeneralFunction.add(9,10);
System.out.println("9 + 10 = "+c);
}
}
5.1.3 静态初始化程序
class StaticInitDemo{ static int i; static { i = 5; System.out.println("Static code: i="+ i++); } } public class TestStaticInit { public static void main(String args[]){ System.out.println(" Main code: i="+ StaticInitDemo.i); } } 结果:Static code: i=5
Main code: i=6
5.2 final关键字
被定义成final的类不能再派生子类。例如java.lang.string类就是一个final类。可以在成员方法,成员变量,在类的声明中使用
例5-4 声明类的final变量并在构造方法中赋值
class Customer{ private final long customerID; private static long counter=200901; public Customer(){ customerID = counter++; } public long getID(){ return customerID; } public static void main(String[] args){ Customer [] cc = new Customer[5]; for ( int i=0; i<cc.length; i++){ cc[i]=new Customer(); System.out.println("The customerID is "+cc[i].getID()); } } }The customerID is 200901
The customerID is 200902
The customerID is 200903
The customerID is 200904
The customerID is 200905
5.3抽象类
5.3.1 什么是抽象类
只有声明而没有方法体的方法称为抽象方法。抽象类必须在声中中abstract关键字,而抽象方法在声明中也要加上abstract
抽象类也不能创建实例。如果子类实现了抽象方法,则可以创建子类的实例对象,否则该子类也是抽象类,也不能创建实例。
abstract class Employee{ abstract void raiseSalary(int i) ; } class Manager extends Employee{ void raiseSalary(int i ){ ?.} }
…Employee e = new Manager();//创建Employee子类Manager的对象Employee e = new Employee();//错吴!Employee为抽象类
5.3.2 抽象类的作用
抽象类为类的体系提供通用的接口,这些通用的接口反映了一类对象的共同特征。定义了这样的抽象类后,就可以用java的多态机制,通过抽象类中的通用接口
处理类体系中的所有类。
5.4 接口
5.4.1 什么是接口
interface定义了一组行为的协议。两个对象之间通过这个协议进行通信。
interface 不属于类层次结构。不相关的类可以实现相同的接口。
5.4.2 接口的定义
【public】 interface interfacename
5.4.3 接口的实现与使用
用implements代替extends声明子类,该子类中必须实现接口(及其超类)中的所有方法。
例:interface SayHello{
void printMessage( );
}
class SayHelloImpl implements SayHello{
void printMessage( ){
System.out.println(“Hello”);
}
}
例5-5 通过接口实现多态示例
import java.util.Random; //将Shape定义为interface interface Shape1 { void draw(); void erase(); } //定义Circle类实现Shape class Circle1 implements Shape1 { public void draw() { System.out.println("Calling Circle.draw()"); } public void erase() { System.out.println("Calling Circle.erase()"); } } //定义Square类实现Shape class Square1 implements Shape1 { public void draw() { System.out.println("Calling Square.draw()"); } public void erase() { System.out.println("Calling Square.erase()"); } } //定义Triangle类实现Shape class Triangle1 implements Shape1 { public void draw() { System.out.println("Calling Triangle.draw()"); } public void erase() { System.out.println("Calling Triangle.erase()"); } } //包含main()的测试类 public class NewShapes{ static void drawOneShape(Shape1 s){ s.draw(); } static void drawShapes(Shape1[] ss){ for(int i = 0; i < ss.length; i++){ ss[i].draw(); } } public static void main(String[] args) { Random rand = new Random(); Shape1[] s = new Shape1[9]; for(int i = 0; i < s.length; i++){ switch(rand.nextInt(3)) { case 0: s[i] = new Circle1();break; case 1: s[i] = new Square1();break; case 2: s[i] = new Triangle1();break; } } drawShapes(s);} }
运行结果:
Calling Square.draw()
Calling Square.draw()
Calling Square.draw()
Calling Triangle.draw()
Calling Square.draw()
Calling Triangle.draw()
Calling Circle.draw()
Calling Circle.draw()
Calling Circle.draw()
5.4.4 多重继承
java中规定一个类只能继承一个父类。但可以实现多个接口
图5-3 java中的多重继承
5.4.5通过继承扩展接口
5.4.6 接口与抽象类
二者区别:
1.接口中的所有方法都是抽象的,而抽象类可以事实上定义带有方法体的不同方法。
2.一个类可以实现多个接口,但只能继承一个抽象父类
3.接口与实现它的类不构成类的继承体系,即接口不是类体系的一部分。
使用接口的优势在于:一是类通过实现多个接口可以实现多重继承
另一个优势是能够抽象出不相关类之间的相似性。
5.5包
5.6 泛型与集合类
5.6.1 泛型概述
泛型即泛化技术(Generics),通过一种类型或方法操纵各种类型的对象,而同时又提供了编译时的类型安全保证。
泛型技术的基本思想是类和方法的泛化,是通过参数化实现的,因此泛型又被称为参数化类型
例5-7 不使用泛型的集合示例
import java.util.*; public class ListTest { public static void main(String[] args) { // 注意:列表中只存放Integer 类型的对象! List listofInteger = new LinkedList(); listofInteger.add(new Integer(2000)); listofInteger.add("8"); Integer x = (Integer) listofInteger.get(0); System.out.println(x); x = (Integer) listofInteger.get(1); System.out.println(x); } }
结果出现:
Exception in thread "main" java.lang.Error: Unresolved compilation problem:
The method add(Integer) in the type List<Integer> is not applicable for the arguments (String)
将第7行代码改为listofInteger.add(new integer(8))或listofInteger.add(8);
5.6.2 泛化类型及子类
1.泛化类型(泛型)的定义
型的定义与普通类定义相比,在类名后增加了由尖括号标识的类型变量,一般用T表示
例5-9 泛型的定义及使用示
class MyBox<T> { private T t; public void add(T t) { this.t = t; } public T get() { return t; } } public class MyBoxTest{ public static void main(String args[]){ MyBox<Integer> aBox; aBox = new MyBox<Integer>(); aBox.add(new Integer(1000)); Integer i = aBox.get(); System.out.println("The Integer is : "+i); } } 例5-9的运行结果是:
The Integer is : 1000
MyBox<Integer>读作”My Box of integer”,泛型调用与普通方法调用类似,所不同的是泛型调用时传递的实参是一个具体的类型而不是普通意义上的实参值。实例化泛型时还是new关键字,只要在类名与()之间插入带有尖括号的参数类型。例如
aBox=new MyBox<integer>();
另外一个泛型可以有多个类型参数,但每个参数应该是唯一的。
2.类型参数的命名习惯
E-element,表示元素
K-KEY,表示键值
N-Number,表示数字
T-Type,表示类型
V-value,表示值
3.泛型中的子类。
在java中,父类的变量可以指向子类的对象,因为子类被认为是与父类兼容的类型,因此,下列的代码是合法的:
object someobject=new object();
Integer someinteger=new integer(10);
someobject=someinteger;
在泛型中,这一点仍成立的。可以使用一个父类作为类型参数调用泛型,而在后续对参化类的访问中,使用该父类的子类对象。例如:
MyBox<number> box=new MyBox<Number>();
box.add(new integer(10));
box.add(new double(10.1));
注意即使调用泛型的实参类型之间有父子类关系,调用后得到的参数化类型之间也不会具有同样的父子关系。
5.6.3 通配符
例5-10 泛型中的通配符示例。
import java.util.*;
class Cage<E> extends LinkedList<E>{};
class Animal{
public void feedMe(){ };
}
class Lion extends Animal{
public void feedMe(){
System.out.println("Feeding lions");
}
}
class ButterFly extends Animal{
public void feedMe(){
System.out.println("Feeding butterflies");
}
}
public class WildcardsTest{
public static void main(String args[]){
WildcardsTest t = new WildcardsTest();
Cage<Lion> lionCage = new Cage<Lion>();
Cage<ButterFly> butterflyCage = new Cage<ButterFly>();
lionCage.add(new Lion());
butterflyCage.add(new ButterFly());
t.feedAnimals(lionCage);
t.feedAnimals(butterflyCage);
}
void feedAnimals(Cage<? extends Animal> someCage) {
for (Animal a:someCage)
a.feedMe();
}
例5-10 的运行结果如下:Feeding lions
Feeding butterflies
5.6.4 泛化方法
泛化方法与泛型的声明类似,但泛化方法中类型参数的作用域只限于声明它的方法。
例5-11中给出了一个泛化方法的例子
class MyBox<T> {
private T t;
public void add(T t) {
this.t = t;
}
public T get() {
return t;
}//泛化方法,泛化方法的定义是在一般方法声明中增加了类型参数的声明。
public <U> void inspect(U u){
System.out.println(" T: " + t.getClass().getName());
System.out.println(" U: " + u.getClass().getName());
System.out.println();
}
}
public class BoxTest{
public static void main(String[] args) {
MyBox<Integer> integerBox = new MyBox<Integer>();
integerBox.add(new Integer(10));
System.out.println("The first inspection:");
integerBox.inspect("some text");
System.out.println("The second inspection:");
integerBox.inspect(new Double(100.0));
}
}结果:The first inspection:
T: java.lang.Integer
U: java.lang.StringThe second inspection:
T: java.lang.Integer
U: java.lang.Double
泛化方法和通配符适合怎样的应用呢?引入通配符的主要目的是支持泛型中的子类,从而实现多态。如果方法泛化的目的主要适用于多种不同类型,或支持多态,则应该使用通配符。
5.6.5 类型擦除。
java虚拟机中,并没有泛型类型的对象。泛型是通过编译器执行一个被称为类型擦除的前端转换来实现的。类型擦除可以理解为一种源程序到源程序的转换,即把带有泛型程序转换为不包含泛型的版本。
1.用泛型的原生类型替代泛型
2.对于含泛型的表达式,用原生类型替换泛型。
3.对于泛型方法的擦除,是将方法声明中的类型参数声明去掉,并进行类型变量的替换
java虚拟机对于泛型采用擦除机制的主要目的,是为了与jdk1.5之前的已有代码兼容。
5.6.6 集合类
1.集合类概述
一个集合对象或一个容器表示了一组对象,集合中的对象称为元素。
(1)Collection
Collection 接口是集合接口树的根,它定义了集合推行的通用API
(2) Set
set不能包含重复的元素。
public interface Set<E>- extends Collection<E>
一个不包含重复元素的 collection。更确切地讲,set 不包含满足
e1.equals(e2)
的元素对e1
和e2
,并且最多包含一个 null 元素。正如其名称所暗示的,此接口模仿了数学上的 set 抽象。在所有构造方法以及 add、equals 和 hashCode 方法的协定上,Set 接口还加入了其他规定,这些规定超出了从 Collection 接口所继承的内容。出于方便考虑,它还包括了其他继承方法的声明(这些声明的规范已经专门针对 Set 接口进行了修改,但是没有包含任何其他的规定)。
对这些构造方法的其他规定是(不要奇怪),所有构造方法必须创建一个不包含重复元素的 set(正如上面所定义的)。
注:如果将可变对象用作 set 元素,那么必须极其小心。如果对象是 set 中某个元素,以一种影响 equals 比较的方式改变对象的值,那么 set 的行为就是不确定的。此项禁止的一个特殊情况是不允许某个 set 包含其自身作为元素。
某些 set 实现对其所包含的元素有所限制。例如,某些实现禁止 null 元素,而某些则对其元素的类型所有限制。试图添加不合格的元素会抛出未经检查的异常,通常是 NullPointerException 或 ClassCastException。试图查询不合格的元素是否存在可能会抛出异常,也可能简单地返回 false;某些实现会采用前一种行为,而某些则采用后者。概括地说,试图对不合格元素执行操作时,如果完成该操作后不会导致在 set 中插入不合格的元素,则该操作可能抛出一个异常,也可能成功,这取决于实现的选择。此接口的规范中将这样的异常标记为“可选”。
(3)List
可以包含重复的元素,可以通过元素在LIST中的索引序号访问相应的元素。vector就是一种常用的list
(4)Map
Map实现键值到值的映射。Map中不能包含重复的键值,每个键值最多只能映射到一个值。Hashtable就是一种常用的Map
(5)Queue
Queue是存放等待处理的数据的集合,称为队列
(6)SortedSet和SortedMap
2.几种常用集合
1.set
set接口中包含方法如下,实现SET的类也实现了这些接口,所以我们可对具体的set对象调用这些方法:
public interface set<E> extends collection<E>{
//基本操作
size
int size()
- 返回 set 中的元素数(其容量)。如果 set 包含多个 Integer.MAX_VALUE 元素,则返回 Integer.MAX_VALUE。
- 指定者:
- 接口
Collection<E>
中的size
- 返回:
- 此 set 中的元素数(其容量)
isEmpty
boolean isEmpty()
- 如果 set 不包含元素,则返回 true。
- 指定者:
- 接口
Collection<E>
中的isEmpty
- 返回:
- 如果此 set 不包含元素,则返回 true
contains
boolean contains(Object o)
- 如果 set 包含指定的元素,则返回 true。更确切地讲,当且仅当 set 包含满足 (o==null ? e==null : o.equals(e)) 的元素 e 时返回
true
。
- 指定者:
- 接口
Collection<E>
中的contains
- 参数:
o
- 要测试此 set 中是否存在的元素- 返回:
- 如果此 set 包含指定的元素,则返回 true
- 抛出:
ClassCastException
- 如果指定元素的类型与此 set 不兼容(可选)NullPointerException
- 如果指定的元素为 null 并且此 set 不允许 null 元素(可选)
add
boolean add(E e)
- 如果 set 中尚未存在指定的元素,则添加此元素(可选操作)。更确切地讲,如果此 set 没有包含满足 (e==null ? e2==null : e.equals(e2)) 的元素 e2,则向该 set 中添加指定的元素 e。如果此 set 已经包含该元素,则该调用不改变此 set 并返回 false。结合构造方法上的限制,这就可以确保 set 永远不包含重复的元素。
上述规定并未暗示 set 必须接受所有元素;set 可以拒绝添加任意特定的元素,包括 null,并抛出异常,这与
Collection.add
规范中所描述的一样。每个 set 实现应该明确地记录对其可能包含元素的所有限制。
- 指定者:
- 接口
Collection<E>
中的add
- 参数:
e
- 要添加到 set 中的元素- 返回:
- 如果 set 尚未包含指定的元素,则返回 true
- 抛出:
UnsupportedOperationException
- 如果此 set 不支持 add 操作ClassCastException
- 如果指定元素的类不允许它添加到此 setNullPointerException
- 如果指定的元素为 null 并且此 set 不允许 null 元素IllegalArgumentException
- 如果指定元素的某些属性不允许它添加到此 set
remove
boolean remove(Object o)
- 如果 set 中存在指定的元素,则将其移除(可选操作)。更确切地讲,如果此 set 中包含满足 (o==null ? e==null : o.equals(e)) 的元素 e,则移除它。如果此 set 包含指定的元素(或者此 set 由于调用而发生更改),则返回 true(一旦调用返回,则此 set 不再包含指定的元素)。
- 指定者:
- 接口
Collection<E>
中的remove
- 参数:
o
- 从 set 中移除的对象(如果存在)- 返回:
- 如果此 set 包含指定的对象,则返回 true
- 抛出:
ClassCastException
- 如果指定元素的类型与此 set 不兼容(可选)NullPointerException
- 如果指定的元素为 null,并且此 set 不允许 null 元素(可选)UnsupportedOperationException
- 如果此 set 不支持 remove 操作
iterator
Iterator<E> iterator()
- 返回在此 set 中的元素上进行迭代的迭代器。返回的元素没有特定的顺序(除非此 set 是某个提供顺序保证的类的实例)。
- 返回:
- 在此 set 中的元素上进行迭代的迭代器
// 集合元素批操作containsAll
boolean containsAll(Collection<?> c)
- 如果此 set 包含指定 collection 的所有元素,则返回 true。如果指定的 collection 也是一个 set,那么当该 collection 是此 set 的子集 时返回 true。
- 指定者:
- 接口
Collection<E>
中的containsAll
- 参数:
c
- 检查是否包含在此 set 中的 collection- 返回:
- 如果此 set 包含指定 collection 中的所有元素,则返回 true
- 抛出:
ClassCastException
- 如果指定 collection 中的一个或多个元素的类型与此 set 不兼容(可选)NullPointerException
- 如果指定的 collection 包含一个或多个 null 元素并且此 set 不允许 null 元素(可选),或者指定的 collection 为 null- 另请参见:
contains(Object)
addAll
boolean addAll(Collection<? extends E> c)
- 如果 set 中没有指定 collection 中的所有元素,则将其添加到此 set 中(可选操作)。如果指定的 collection 也是一个 set,则 addAll 操作会实际修改此 set,这样其值是两个 set 的一个并集。如果操作正在进行的同时修改了指定的 collection,则此操作的行为是不确定的。
- 指定者:
- 接口
Collection<E>
中的addAll
- 参数:
c
- 包含要添加到此 set 中的元素的 collection- 返回:
- 如果此 set 由于调用而发生更改,则返回 true
- 抛出:
UnsupportedOperationException
- 如果 set 不支持 addAll 操作ClassCastException
- 如果某些指定 collection 元素的类不允许它添加到此 setNullPointerException
- 如果指定的 collection 包含一个或多个 null 元素并且此 set 不允许 null 元素,或者指定的 collection 为 nullIllegalArgumentException
- 如果指定 collection 元素的某些属性不允许它添加到此 set- 另请参见:
add(Object)
retainAll
boolean retainAll(Collection<?> c)
- 仅保留 set 中那些包含在指定 collection 中的元素(可选操作)。换句话说,移除此 set 中所有未包含在指定 collection 中的元素。如果指定的 collection 也是一个 set,则此操作会实际修改此 set,这样其值是两个 set 的一个交集。
- 指定者:
- 接口
Collection<E>
中的retainAll
- 参数:
c
- 包含要保留到此 set 中的元素的 collection- 返回:
- 如果此 set 由于调用而发生更改,则返回 true
- 抛出:
UnsupportedOperationException
- 如果此 set 不支持 retainAll 操作ClassCastException
- 如果此 set 元素的类与指定的 collection 不兼容(可选)NullPointerException
- 如果此 set 包含 null 元素并且指定的 collection 不支持 null 元素(可选),或者指定的 collection 为 null- 另请参见:
remove(Object)
removeAll
boolean removeAll(Collection<?> c)
- 移除 set 中那些包含在指定 collection 中的元素(可选操作)。如果指定的 collection 也是一个 set,则此操作会实际修改此 set,这样其值是两个 set 的一个不对称差集。
- 指定者:
- 接口
Collection<E>
中的removeAll
- 参数:
c
- 包含要从此 set 中移除的元素的 collection- 返回:
- 如果此 set 由于调用而发生更改,则返回 true
- 抛出:
UnsupportedOperationException
- 如果此 set 不支持 removeAll 操作ClassCastException
- 如果此 set 元素的类与指定的 collection 不兼容(可选)NullPointerException
- 如果此 set 包含 null 元素并且指定的 collection 不允许 null 元素(可选),或者指定的 collection 为 null- 另请参见:
remove(Object)
,contains(Object)
clear
void clear()
- 移除此 set 中的所有元素(可选操作)。此调用返回后该 set 将是空的。
- 指定者:
- 接口
Collection<E>
中的clear
- 抛出:
UnsupportedOperationException
- 如果此 set 不支持 clear 方法
//数组操作
Object[]
toArray()
返回一个包含 set 中所有元素的数组。
<T> T[]
toArray(T[] a)
返回一个包含此 set 中所有元素的数组;返回数组的运行时类型是指定数组的类型。