内部类
创建内部类
定义:可以将一个类的定义放在另一个类的定义内部,这就是内部类。
创建方式:
其中B就是A的内部类
class A{
class B{
...
}
...
}
如果想从外部类的非静态方法之外的任意位置创建某个内部类的对象,那么必须具体地指明这个对象的类型:OuterClassName.InnerClassName
链接到外部类
当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其外围类的所有元素的访问权。
为什么可以访问外部所有元素呢?
因为当某个外围类的对象创建了一个内部类对象时,此内部类对象必定会秘密地捕获一个指向那个外围类对象的引用。然后,在你访问此外围类的成员时,就是用那个引用来选择外围类的成员。构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器访问不到这个引用就会报错。
使用.this与.new
如果需要生成对外部类对象的引用,可以使用外部类的名字后面紧跟圆点和this。
public class A{
public class B{
public A fun(){
return A.this;
}
}
}
如果想要告知某些其他对象,去创建其某个内部类的对象,要实现此目的,必须在new表达式中提供对其他外部类对象的引用,这是需要使用.new语法。
public class A{
public class B{}
public static void main(String[] args){
A a= new A();
A.B b = a.new B();
}
}
匿名内部类
如下,就是一个匿名内部类的例子
public interface C{
int func();
}
public class A{
public C funA(){
return new C(){
private i;
};
}
}
如果一个匿名内部类,想要使用外部定义的对象,那么编译器会要求参数必须是final 的,否则报错。
如果匿名内部类想要做一些构造行为,怎么办呢?
public interface C{
int func();
}
public class A{
public C funA(){
return new C(){
{i=1;}//构造器
private i;
};
}
}
这个再给出个实际的例子,方便理解:
public interface TestNA {
void funA();
}
public class TestC implements TestNA {
@Override
public void funA() {
// TODO Auto-generated method stub
}
public TestNA funNA(){
return new TestNA(){
int i;
{i=5;}
@Override
public void funA() {
// TODO Auto-generated method stub
System.out.println(i);
}
};
}
public static void main(String[] args){
TestC c = new TestC();
TestNA a= c.funNA();
a.funA();
}
}
嵌套类
如果不需要内部类与外部类有联系,那么,可以将内部类声明为static。这就是嵌套类。
使用了static意味着:
- 要创建嵌套类的对象,并不需要外部类的对象;
- 不能从嵌套类的对象中访问非静态的外围类对象;
嵌套类和内部类的区别:
普通的内部类不能包含static数据,static字段以及嵌套类,而嵌套类这些都可以包括。
嵌套类可以作为接口的一部分,甚至可以在嵌套类中实现外围接口。
public interface A{
void fun();
class B implements A{
public void fun(){
System.out.println("B");
}
public static void main(String{} args){
new B().fun();
}
}
}
另外嵌套类还可以用来测试代码:
public class A{
public void fun(){System.out.println("A");}
public static class TestA{
public static void main(String[] args){
A a = new A();
a.fun();
}
}
}
为什么使用内部类
- 内部类可以有多个实例,每个实例都有自己独立的状态信息。
- 在单个外围类中,可以让多个内部类以不同的方式实现同一接口,或继承同一类。
- 创建内部类对象的时刻并不依赖于外围类对象的创建。
- 内部类并没有令人迷惑的“is-a”关系,它就是一个独立的实体。
内部类的继承
在继承内部类的时候,内部类的构造器必须链接到指向外围类对象的引用,所以代码应该这样:
class WithInner{
class Inner{}
}
public class InheritInner extends WithInner.Inner{
InheritInner(WithInner w){
w.super();
}
public static void main(String[] args) {
// TODO Auto-generated method stub
WithInner w =new WithInner();
InheritInner i = new InheritInner(w);
}
}
内部类可以被覆盖吗?
当继承了某个外围类的时候,内部类并没有发生什么变化,两个内部类是独立的实体,各自在自己的命名空间。