可以将一个类的定义放在另外一个类的定义内部,这就是内部类。
内部类是一种非常有用的特性,因为它允许你把一些逻辑相关的类组织在一起,并控制位于内部的类的可视性。然后必须要了解,内部类与组合是完全不同的概念,这一点很重要。
在最初,内部类看起来就像是一种代码隐藏机制;将类置于其他类的内部。但是,你将会了解到,内部类远不止于此,它了解外围类,并能与之通信;而且你用内部类写出的代码更加优雅而清晰,尽管不总是这样。
最初,内部类可能看起来有些奇怪,而且要花些时间才能在设计中轻松地使用它们。对内部类的需求并非总是很明显的,但是在描述完内部类的基本语法与语义之后,10.8节就应该使得内部类的益处明确显现了。
10.1 创建内部类
创建内部类的方式就如同你想的一样---把类的定义置于外围类的里面:
/**
* @Author: xushuqiu
* @Description:
* @Date: Create in 11:58 2020/8/29
*/
public class Parcel1 {
//内部类Contents
class Contents {
private int i=11;
public int value(){
return i;
}
}
//内部类Destination
class Destination {
private String label;
Destination(String whereTo){
label=whereTo;
}
String readLabel(){return label;}
}
public Destination to(String s){
return new Destination(s);
}
public Contents contents(){
return new Contents();
}
public void ship(String dest){
Contents contents = new Contents();
Destination destination=new Destination(dest);
System.out.println(destination.readLabel());;
}
当我们在ship方法里面使用内部类时候。发现与使用普通类没什么不同。在这里,我们只是看到, 实际的区别只是内部类的名字是嵌套在Parcel1类里面的。不过你将会看到这并不是唯一的区别。更典型的情况是,外部类中将有一个方法,该方法返回一个指向内部类的引用。就行contents方法。
/**
* @Author: xushuqiu
* @Description:
* @Date: Create in 11:42 2020/8/29
*/
public class TestClass {
public static void main(String[] args) {
Parcel1 p = new Parcel1();
p.ship("jackXu");
Parcel1 q = new Parcel1();
Parcel1.Contents contents = q.contents();
Parcel1.Destination borneo = q.to("Borneo");
}
}
如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须像上面一样,具体的指明这个对象的类型:
OutClassName.InnerClassName.
10.2、链接到外部类
到目前如此,内部类似乎还只是一种名字隐藏和组织代码的模式。这些是很有用,但还不是最引人注目的,它还有其他的用途。当生成一个内部类的对象时,此对象与制造它的外围对象直接就有了一种特殊的联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外部类的所有元素的访问权。
import javax.sound.midi.Soundbank;
/**
* @Author: xushuqiu
* @Description:
* @Date: Create in 12:33 2020/8/29
*/
interface Selector{
boolean end();
Object current();
void next();
}
public class Sequence {
private Object[] items;
private int next=0;
public Sequence(int size){
items=new Object[size];
}
public void add(Object x){
if (next<items.length){
items[next++]=x;
}
}
private class SequenceSelector implements Selector{
private int i=0;
@Override
public boolean end() {
return i==items.length;
}
@Override
public Object current() {
return items[i];
}
@Override
public void next() {
if (i<items.length) i++;
}
}
private Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args) {
Sequence sequence = new Sequence(10);
for (int i = 0; i <10 ; i++) {
sequence.add(i);
}
Selector selector = sequence.selector();
while (!selector.end()){
System.out.println(selector.current());
selector.next();
}
}
}
Sequence类只是一个固定大小的Object类型的数组,以类的形式包装起来。可以调用add方法在序列末增加新的Object(只要还有空间)。要获取Sequence的每一个对象,可以使用selector接口。这是“迭代器”设计模式的一个例子。
Selector允许你检查序列是否到达了末尾(end方法),访问当前对象(current方法),以及移到序列中的下一个对象(next方法)。因为Selector是一个接口,所以别的类可以按它们自己的方式来实现这个接口,并且别的方法能以此接口为参数,来生成更加通用的代码。
这里,SequenceSelector是提供Selector功能的private类。可以看到,在main方法中创建了一个Sequence,并向其中添加了一些string对象。然后通过selector方法获取一个Selector,并且它在Sequence中移动和选择每一个元素。
最初看到SequenceSelector可能只会觉得他只是一个内部类,但是请仔细观察他的三个方法都用到了objects.这是一个引用.它并不是SequenceSelector的一部分,而是外围类的一个private字段。然而内部类可以访问其外部类的方法和字段,就像他们自己拥有一样。这带来了很大的方便。
所以内部类自动拥有对其外部类所有成员的访问权。这是如何做到的呢?当某个外围类的对象在创建一个内部类对象时候,这个内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。然后在你访问外围类的成员时候,就是那个引用来选择外围类的成员。幸运的是,编译器会帮你处理所有的细节,但是你现在可以看到,内部类的对象只能与外围类对象相关联情况下才能被创建。构建内部类对象时候,需要一个对象指向其外围类的引用,如果编译器找不到这个引用就会报错。不过绝大多数情况下都不需要程序员操心这个问题。(在另外一个无关外部类直接继承这个内部类时候就需要初始化这个内部类所在的外围类。
转自:https://blog.csdn.net/AdolfQiu/article/details/108292718?utm_medium=distribute.pc_category.none-task-blog-hot-4.nonecase&depth_1-utm_source=distribute.pc_category.none-task-blog-hot-4.nonecase&request_id=