内部类
可以将一个类的定义放在另一类的定义内部,这就是内部类。
创建内部类
public class Parcel {
class Contents{
private int i=11;
public int getI(){
return i;
}
}
class Destination{
private String label;
Destination(String label){
this.label=label;
}
String getLabel()
{
return label;
}
}
public Contents contents()
{
return new Contents();
}
public Destination destination(String s)
{
return new Destination(s);
}
public void ship(String dest)
{
Contents c=contents();
Destination d=destination(dest);
System.out.println(d.getLabel());
}
public static void main(String[] args) {
Parcel parcel=new Parcel();
parcel.ship("Tasmania");
Parcel q=new Parcel();
Parcel.Contents c= q.new Contents();
Parcel.Destination d= q.new Destination("Bomb");
}
}
可以看出我们在使用内部类的时候和普通类没什么区别。但是在我们也可以看出,非静态内部类的对象创建是需要依赖于外部类的对象,所以我们需要先创建出外部类才能创建出内部类。
从上面的例子中可以看出在使用.new创建内部类的时候,需要使用外部类的对象来创建内部类,这样也解决了内部类作用域的问题
为什么需要内部类
在我们知道如何创建内部类后可能会有个疑问,内部类看起来没有比在外部创建一个类更加实用,那我我们为什么需要内部类呢?
一般来说来说内部类继承或者实现某个接口,或者继承某个类,每个内部类都能独立的继承一个接口的实现,所以无论外围类是否已经被继承了,对内部类都没有影响,内部类提供了一个可以继承多个具体或者抽象类的能力,每个内部类都可以继承一个具体或者抽闲的类,那么使用多个内部类的话,就能优先的实现多重继承。
链接到外围对象
当创建一个内部类对象时,次对象与创造他的外围对象之间存在一种联系,所以不需要任何特殊条件,就能范围其外围对象的所有成员,下面我们来看一个例子:
public class Sequence {
private Object[] items;
private int next=0;
public Sequence(int size){
items=new Object[size];
}
public void add(Object item){
items[next]=item;
next++;
}
private class SequenceSelector{
private int i=0;
public boolean end(){
return i==items.length;
}
public Object current(){
return items[i];
}
public void next(){
if(i<items.length) i++;
}
}
public SequenceSelector sequenceSelector()
{
return new SequenceSelector();
}
public static void main(String[] args) {
Sequence sequence=new Sequence(10);
for(int i=0;i<10;i++)
{
sequence.add(Integer.toString(i));
}
SequenceSelector Selector=sequence.sequenceSelector();
while (!Selector.end())
{
System.out.println(Selector.current()+" ");
Selector.next();
}
}
}
输出结果:
0
1
2
3
4
5
6
7
8
9
在上面这个例子中,Seqence只是一个固定大小的Object数组,以类的形式包装了起来,而且其中的items是private类型,而我们的内部类中的end current等函数可以直接对items进行访问,从而可以遍历整个items数组。 内部类可以访问外围类的方法和字段就像自己的一样,这带来了很大的方便。
那么内部类对象在创建的时候,会自动的捕获一个指向外围类的引用,当我们访问外围对象时就是用那个引用来获取外围对象的成员。
匿名内部类
我们先来看一个例子
public interface Content {
public int value();
}
public class Pracel2 {
public Content contents(){
return new Content(){
private int i=11;
public int value() {return i;}
};
}
public static void main(String[] args) {
Pracel2 p=new Pracel2();
Content c=p.contents();
}
}
上面这个例子似乎有点奇怪,我们可以看到,contents方法是将返回值的生成与返回值的类的定义结合在了一起,并且这个类是匿名的。
这种写法的实际含义就是,创建一个继承自Content的匿名类对象,然后通过new的表达式返回的引用被自动向上转型为对Content的引用,上述例子就是对下面这个例子的简化
public interface Content {
public int value();
}
public class Pracel2 {
class MyContent implements Content{
private int i=11;
public int value() {return i;}
}
public Content contents(){
return new MyContent();
}
public static void main(String[] args) {
Pracel2 p=new Pracel2();
Content c=p.contents();
}
}
在匿名内部类定义字段的时候,还能对其执行初始化操作
public interface Destination {
String getLabel();
}
public class Parcel3 {
public Destination destination(final String dest){
return new Destination() {
private String label=dest;
public String getLabel() {
return label;
}
};
}
public static void main(String[] args) {
Parcel3 p=new Parcel3();
Destination d=p.destination("Tom");
System.out.println(d.getLabel());
}
}
输出结果是:
TOM
如果定义一个内部类希望他使用外部定义的对象的话,那么编译器会要去这个参数的引用是final的,不过这个限制在JAVA8以后就放宽了,不过还是要求不能重复修改。
嵌套类
如果不需要内部类对象与其外围对象之间有联系,那么可以将内部类声明为static,这通常称为嵌套类。嵌套类也意味着:
1、要创建嵌套类的对象,并不需要其外围类的对象
2、不能从嵌套类的对象中范围非静态的外围类对象
看下面这个例子:
public class Parcel4 {
private static class ParcelContents implements Content{
private int i;
public int value(){
return i;
}
}
protected static class ParcelDestination implements Destination{
private String label;
private ParcelDestination(String whereto){
label=whereto;
}
public String getLabel(){
return label;
}
}
public static void main(String[] args) {
Content c=new ParcelContents();
ParcelDestination p=new ParcelDestination("Tsa");
System.out.println("i: "+c.value()+" label: "+p.getLabel());
}
}
out:
i: 0 label: Tsa
从这个例子中可以看出,嵌套类的创建不依赖与外部类就可以创建出该对象。
正常情况下,是不能在接口内放置任何代码的,但是嵌套类可以作为接口的一部分,且放到接口中的任何类都自动的是public和static的,因为类是static的,只是将嵌套类置于接口的命名空间内,这并不违反接口的规则,甚至可以在内部类中实现其外围接口。
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface{
public void howdy(){
System.out.println("Howdy");
}
public static void main(String[] args) {
new Test().howdy();
}
}
}
局部内部类
内部类不仅仅可以创建在类中,也可以创建在一个方法体中,如下所示例子:
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("chenssy");
String string = ts.getSlip();
}
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}