目录
组合性是指整体与部分之间的关系,整体是由一个或多个部分构成的。例如,树是由树根、树枝和树叶等部分构成,订单是由一组订单项构成,计算机是由CPU、内存和硬盘等部分构成的。为了显式地表达类之间的整体-部分关系,Java支持在一个类中声明另一个类,这样的类称为内部类(inner class),内部类所在的类称为外部类(outer class)。根据内部类在外部类中所处的位置可分为:成员类、局部类和匿名类。
1. 成员类
在一个类中除了可以定义成员变量和成员方法外,还可以定义类,这样的类被称为成员类,成员类不能与外部类重名。与成员变量和成员方法类似,成员类的访问权限也分为四种:public、protected、private和默认,它们的含义与成员变量和成员方法是一致的。如果成员类的前面用final修饰,则该成员来不能被继承。成员类可以定义为抽象类,但是需要被其它的内部类继承或实现。下面介绍非静态成员和静态成员类的定义和使用。
1.1. 非静态成员类
非静态成员类没有static修饰符,在非静态成员类中不能定义静态成员(静态变量和静态方法)。非静态成员类可以访问外部类的所有成员,在非静态成员类中访问外部类的成员时,若外部类的成员与其内部的成员不重名时,可以直接用成员名称访问,否则,访问外部类成员的语法格式如下:
外部类名.this.外部类成员变量名; //访问外部类的成员变量
外部类名.this.外部类成员方法名([实参列表]);//访问外部类的成员方法
在外部类之外创建非静态成员类的对象时,需要先创建外部类的对象,然后使用以下语句创建非静态成员类的对象:
外部类名.非静态成员类名 对象名=外部类的对象名.new 非静态成员类名([实参数列表]);
【例1】下面的代码演示了定义非静态成员类的方法。
/*
* 外部类:订单
*/
public class Order {
String number; //编号
double money; //总金额
Item items[]; //订单项集合
//带参数的构造方法
public Order(String number) {
this.number=number;
}
//设置订单项集合
public void setItem(Item items[]) {
this.items=items;
}
//计算订单总金额
public void setMoney(){
money=0;
for(int i=0;i<items.length;i++) {
money+=items[i].amount*items[i].money;
}
}
//输出订单信息
public void print() {
System.out.println("number:"+number+",money:"+money);
for(Item item:items) {
item.print();
}
}
/*
* 非静态成员类:订单项
*/
class Item{
String number; //订单编号
int no; //序号
String product; //产品
double price; //价格
int amount; //数量
double money; //金额
//带参数构造方法
Item(int no,String product,double price,int amount){
number=Order.this.number;//访问外部类中的成员变量
this.no=no;
this.product=product;
this.price=price;
this.amount=amount;
money=amount*price;
}
//输出订单项信息
void print() {
System.out.println(" "+number+","+no+","+product
+","+amount+","+price+","+money);//访问自己的成员变量
}
}
}
在上面代码中,类Item为类Order的一个非静态成员类,类Order中声明了一个数据类型为Item的数组成员变量items。类Item和类Order中都有一个名为number的成员变量,因此,在类Item中,访问类Order的成员变量number时的语句为:Order.this.number。另外,在类Item中还有一个与类Order中重名的变量money,由于是访问Item自己的成员变量,因此可以直接按名访问。
【例2】下面程序演示了创建非静态成员类的对象。
public class OrderManage {
public static void main(String[] args) {
//创建订单 (外部类的对象)
Order order=new Order("fc001");
//定义订单项数组 (非静态成员类的对象)
Order.Item items[]=new Order.Item[2];
//订单项数组的初始化(在外部类之外创建非静态成员类的对象)
items[0]=order.new Item(1,"computer",0.8,5);
items[1]=order.new Item(2,"telephone",0.5,10);
//设置订单的订单项集合
order.setItem(items);
//计算订单的总金额
order.setMoney();
//输出订单信息
order.print();
}
}
程序运行结果为:
number:fc001,money:70.0
fc001,1,computer,5,0.8,4.0
fc001,2,telephone,10,0.5,5.0
1.2.静态成员类
如果使用static关键字来修饰一个成员类,则该成员类为静态成员类。静态成员类属于外部类的本身,而不属于外部类的某个对象。静态成员类既可以定义静态成员,也可以定义非静态成员。在静态成员类中,可以直接访问外部类的所有静态成员,但不能直接访问外部类的非静态成员。
在静态成员类中访问外部类的成员时,若外部类的成员与该静态成员类的成员不重名,则可以直接用成员名进行访问,若外部类与该静态成员类的成员重名,则访问外部类的成员语法为:
外部类名.静态成员变量名; //访问外部类的静态成员变量
外部类名.静态成员方法名([实参列表]);//访问外部类的静态成员方法
在外部类之外创建静态成员类的对象的语法格式为:
外部类名.静态成员类名 对象名=new 外部类名.静态成员类名([实参列表]);
【例3】下面的代码演示了定义静态成员类的方法。
/*
* 外部类:计算机
*/
public class Computer {
String brand; //品牌
String model; //型号
CPU cpu; //CPU
static int cpuNum; //当前序号(静态变量)
//带参数构造方法
public Computer(String brand,String model,CPU cpu){
this.brand=brand;
this.model=model;
this.cpu=cpu;
}
//设置计算机的CPU
public void setCPU(CPU cpu) {
this.cpu=cpu;
}
//输出计算机信息
public void print() {
System.out.println(brand+","+model);
cpu.print();
}
/*
* 静态成员类:CPU
*/
static class CPU{
int no; //编号
String brand;//品牌
String type; //类型
double GHz; //主频
int core; //核数
//带参数的构造方法
CPU(String brand,String type,double GHz,int core){
this.brand=brand;
this.type=type;
this.GHz=GHz;
this.core=core;
cpuNum++; //访问外部类的静态成员变量
no=cpuNum;
}
//输出CPU信息
void print() {
System.out.println(" cpu:"+no+":"+brand+","
+type+","+GHz+"GHz,"+core+"core");
}
}
}
在上面代码中,类CPU为类Computer的一个静态成员类,在类Computer中声明了一个数据类型为CPU的成员变量cpu。在静态成员类CPU中的可以访问外部类中的静态成员变量cpuNum,但是,不能访问非静态成员变量。
【例4】下面程序演示了创建静态成员类的对象。
public class ComputerManage {
public static void main(String[] args) {
//创建两个CPU对象(成员类的对象)
Computer.CPU cpu1=new Computer.CPU("Intel","i7",2.81,2);
Computer.CPU cpu2=new Computer.CPU("Intel","i5",3.2,4);
//创建两个计算机对象(外部类的对象)
Computer computer1=new Computer("Lenovo","T470p",cpu1);
Computer computer2=new Computer("Dell","T3420",cpu2);
//输出计算机的信息
computer1.print();
computer2.print();
}
}
程序运行结果为:
Lenovo,T470p
cpu:1:Intel,i7,2.81GHz,2core
Dell,T3420
cpu:2:Intel,i5,3.2GHz,4core
2. 局部类
局部类是在外部类的方法中定义的类,其名称不能与其所在的外部类重名。与局部变量类似,局部类的作用域是定义它的代码块。局部类可以是abstract和final型,权限访问符只能是缺省的,不能是public、private或protected。局部类中不允许包括静态成员(变量和方法)。在局部类中只能访问它所在方法中的final型变量,而不能访问非final型的变量。局部类只在定义它的代码段中可见,只能在外部类的内部使用,在外部类之外是不可见的,不能在外部类之外创建局部类的对象。
在局部类中可以访问外部类的成员,如果局部类成员与外部类成员不重名,可以直接用成员名进行访问,如果外部类成员与局部类成员重名,访问规则如下:
(1)访问外部类的非静态成员需要使用以下语法:
外部类名.this.外部类成员变量名;
外部类名.this.外部类成员方法名([实参列表]);
(2)访问外部类静态成员的语法:
外部类名.静态成员变量名;
外部类名.静态成员方法名([实参列表]);
局部类的典型用法是与接口相配合,用局部类来实现接口,并在方法中返回接口类型。
【例5】下面程序演示了局部类的定义与使用方法。
public interface OuterInter {
public int sign(int value);
}
public class OuterClass {
public OuterInter getInterface(){
//局部类(实现外部接口)
class LocalClass implements OuterInter{
//实现接口的方法
public int sign(int value) {
if(value<0)
return -1;
else if(value==0)
return 0;
else
return 1;
}
}
//常见局部类的对象并返回
return new LocalClass();
}
public static void main(String[] args) {
OuterClass oc=new OuterClass();
OuterInter oi=oc.getInterface();
System.out.println("10的符号为:"+oi.sign(10));
System.out.println("0的符号为:"+oi.sign(0));
System.out.println("-10的符号为:"+oi.sign(-10));
}
}
执行类OuterClass,程序运行结果为:
10的符号为:1
0的符号为:0
-10的符号为:-1
3. 匿名类
匿名类是指没有名称的类。一般情况下,如果用一个类对另一个类进行扩展(继承)或者实现一个特定的接口,同时,这个类实现的功能比较简单,或者在程序中只使用一次,就可以用匿名类的方式创建这个类的对象。
匿名类可以直接用其父类的名称或接口的名称来定义,其语法格式如下:
new 父类名或接口名(){
类体;
}
匿名类具有如下特征:
(1)匿名类必须是一个具体的对象,不允许是abstract的,也不可以是static。
(2)匿名类的类体必须将其继承或实现的内容具体化,这与普通类没有差别。
(3)匿名类本身没有名字,所以没有构造方法,只能用super关键字调用其父类的构造方法。
(4)匿名类只能是final型的,其中包括的所有变量和方法都是final型的。
由匿名类的定义可知,其返回的是一个对象的引用,因此,可以直接使用或者将其赋给一个引用变量,也可以将其作为方法调用的实参。
【例6】下面的程序演示了匿名类的定义与使用。
public class OuterClass1 {
public void print() {
System.out.println("这是一个外部类");
}
}
public class AnonyClassDemo {
public static void print(OuterClass1 oc) {
oc.print();
}
public static void main(String[] args) {
OuterClass1 oc=new OuterClass1();
oc.print();
//直接使用匿名类
(new OuterClass1() {
public void print() {
System.out.println("直接使用匿名类");
}
}).print();
//将匿名类的返回值赋给一个引用变量
OuterClass1 obj=new OuterClass1() {
public void print() {
System.out.println("将匿名类的返回值赋给一个引用变量");
}
};
obj.print();
//将匿名类的返回值赋给方法的参数
print(new OuterClass1() {
public void print() {
System.out.println("将匿名类的返回值赋给方法的参数");
}
});
}
}
执行类AnonyClassDemo,程序运行的结果为:
这是一个外部类
直接使用匿名类
将匿名类的返回值赋给一个引用变量
将匿名类的返回值赋给方法的参数