一、Inner Class
Inner Class 即内部类,也即C++和C#中的Nested Class。但Java 的Inner Class 与 C++和C#最大的不同之处在于,内部类包含一个指向其容器类的引用,可以访问容器类的成员。以下代码演示了这一点:
public class Container {
String Name;
class InnerClass
{
InnerClass(){};
public void func()
{
System.out.println(Name);
}
}
public Container(String name){
Name=name;
InnerClass a=new InnerClass();
}
public static void main(String [] arg)
{
Container a=new Container(“ContainerA");
InnerClass b=a.new InnerClass(); //注意此处
InnerClass c=(new Container(“ContainerB")).new InnerClass(); //本质上等价于上一句
a.func();
c.func();
}
}
注意其中独特的new语法,在静态函数要创建一个Inner Class,必须有一个其容器类的实例。如果直接创建InnerClass b=new InnerClass();则会导致编译出错。
而在Container的构造函数中,创建InnerClass时,自动将this作为InnerClass的引用。在Inner Class 中使用容器类的成员,不需指定实例,自动指向创建它的容器类。这是一个很有用的语法特征,编译器替我们省了许多事。
本例的输出是:
ContainerA
ContainerB
还可以看到,Inner Class 可以访问容器类的任何成员,不管是public、private或protected的成员全是透明的。反之则不然,容器类只能访问Inner Class的public成员。
二、Static Inner Class
即在内部类的前面增加了static修饰符(modifier)。注意,仅仅只有内部类能够被声明为static类型,通常我们声明一个普通类的时候不能使用static,否则编译出错。
前面讲过,编译器会自动给内部类加上一个reference,指向产生它的那个外部类的对象,如果不想要或者说不需要这个reference,那么我们就可以把这个内部类声明为static,禁止这个reference的产生。除此之外静态类的使用与普通的静态类是一样的。
public class StaticInnerClassTest {
public StaticInnerClassTest() {
super();
}
public static void main(String[] args) {
double d[]=new double[20];
for(int i=0;i<d.length;i++)d[i]=100*Math.random();
//FindMinMax test=new FindMinMax();
FindMinMax.Pair pair=FindMinMax.getMinMax(d);
System.out.println("最小值是:"+pair.getFirst());
System.out.println("最大值是:"+pair.getSecond());
}
}
class FindMinMax{
static double min=Double.MAX_VALUE;
static double max=Double.MIN_VALUE;
public static Pair getMinMax(double d[]){
for(double value:d){
if(min>value) min=value;
if(max<value) max=value;
}
return new Pair(min,max);
}
public static class Pair{
private double first;
private double second;
public Pair(double first,double second){
this.first=first;
this.second=second;
}
public double getFirst(){
return this.first;
}
public double getSecond(){
return this.second;
}
}
}
下面是又一例子:
内部类
public class Test {
class A{
public void setA(){
}
}
public static void main(String[] args){
Test t=new Test();
}
}
调用方式:
public class Test2 {
public static void main(String[] args){
Test test=new Test();
Test.A t=test.new A();
t.setA();
}
}
静态内部类
调用静态内部类的非静态方法:
public class Test {
static class A{
public void setA(){
}
}
}
public class Test2 {
public static void main(String[] args){
Test.A a=new Test.A();
a.setA();
}
}
调用静态内部类的静态方法:
public class Test {
static class A{
static public void setA(){
}
}
}
public class Test2 {
public static void main(String[] args){
Test.A.setA();
}
}
new Outer.Inner(); // 可以
new Inner(); // 在Outer类内部可以
new foo.Outer.Inner(); // 在包外做内部类实例化, 或者先导包再像第一个那样写.
三、Anonymous Inner Class
匿名内部类(Anonymous Inner Class),顾名思义,就是没有名字的内部类,这是Java为了方便我们编写程序而设计的一个机制。因为有时候有的内部类只需要创建一个它的对象就可以了,以后再不会用到这个类,这时候使用匿名内部类就比较合适,而且也免去了给它取名字的烦恼。
匿名类的语法,如下所示:
new SuperType(){
内部类的方法和域;
}
注意,这里的SuperType指超类,它可以是一个接口(interface)或者是一个类(Class),当它是一个接口的时候就不能有构造参数(Construction parameters)了。匿名类的语法相对于Java的其他部分来说稍微复杂一点,我们可以按如下方式理解:
1.SuperType为接口
例子:Interface1() test=new Interface1(){
要实现的的方法;
Interface1的域;
内部类的域以及方法;
}
我们可以如下理解:
先声明了如下一个类,
class Anonymous1 implements Interface1{
要实现的的方法;
Interface1的域;
内部类的域以及方法;
}
然后,Interface1() test=new Anonymouse1();
这样就比较容易理解了。
2.SuperType为类
例子:Class2 test=new Class2(Construction parameters){
内部类的域以及方法;
}
我们可以如下理解:
先声明了如下一个类,
class Anonymous2 extends Class2{
public Anonymous2(Construction parameters){
super(Construction parameters);
}
内部类的域以及方法;
}
然后,Class2 test=new Anonymouse2(Construction parameters);
四、Local Inner Class
在方法中定义的内部类称为局部内部类。与局部变量类似,局部内部类不能有访问说明符,因为它不是外围类的一部分,但是它可以访问当前代码块内的常量,和此外围类所有的成员。
局部内部类不需要任何access modifier(private,public,pretected...),否则编译出错,它的作用域一般都被限制在它所在的block中。局部内部类有如下两个优点:
1.它对外面的所有类来说都是隐藏的,即时是它所属的外部类,仅有它所在的方法知道它;
2.它不仅可以访问它所属外部类中的数据,还可以访问局部变量,不过局部变量必须生命为final类型
public class OuterC {
private String name="hehe";
public void useLocalInner(){
final int id=10;
class LocalInner{
public void accessMethod(){//只能访问外部方法的final属性
System.out.println(id);
}
public void accessOuter(){//可以访问外部类的属性和方法
System.out.println(name);
}
};
LocalInner localInner = new LocalInner();
localInner.accessMethod();
localInner.accessOuter();
}
}