之前看项目的代码中有使用到内部类的情况,但是不理解为什么要用内部类这种生僻而难以理解的语法,没有领悟到内部类的真正意义所在,故而在这里说下内部类的几种形式、用途以及使用方式
内部类定义
将一个类的定义放在另一个类内部,就是内部类。跟组合不同的是,组合只是将另一个类的引用指向一个实例后放在类里面,达到两个类之间的关联关系。从两个类通信角度来说,内部类可以直接访问外部类的所有属性方法,而组合中的定义在类内部的其他类的实例,是不能直接访问这个所谓的“外部类”的所有属性方法的,除非通过该外部类定义的公有方法去操作(但这样的话也就跟这个实例没毛关系了)。
内部类使用
上面我们说过,内部类访问外部类不需要任何特殊条件,拥有外部类所有的访问权,相当于是外部类本身一样随便访问。反编译内部类的class文件可以发现,每个内部类都持有一个外部类的引用,然后以此访问外部类的成员。如果存在相同的成员,又需要访问外部类成员变量,则访问方式如下:外部类类名.this.变量名,下面展示内部类和外部类之间的互相访问:
public class OuterClass {
int outer = 1;
class InnerClass{
int outer = 2;
public int getOuter() {
return OuterClass.this.outer;
}
}
public static void main(String[] args){
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
System.out.println("OuterClass:" + outer.outer + ";InnerClass:" + inner.getOuter());
}
}
打印结果:OuterClass:1;InnerClass:1
我们都知道java是没有C++多重继承这个概念的,在《Java编程思想》中,作者开篇就阐述了内部类诞生的初衷,为了解决无法多重继承问题。通过每个内部类都独立的继承自一个父类(接口的)实现,当一个外部类里面存在多个内部类,并且每个内部类都继承或者实现了不同的外部类的时候,就达到了多重继承的效果
内部类的分类
- 成员内部类
- 局部内部类
- 匿名内部类
- 静态内部类
成员内部类
成员内部类也叫实例内部类。每一个外部类对象都需要一个内部类的实例,内部类离不开外部类存在
既然是成员内部类,和成员属性成员方法地位上自然没有什么不同
每个外部类对象都有一个内部类对象,自然持有外部类的引用,如上面例子中定义的innerClass,能够通过this关键字直接访问外部类的成员属性
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.new InnerClass();
局部内部类
局部内部类不能用public或者private或者protected访问说明符,作用域被限定在了声明这个局部内部类中了
很好理解,局部的就跟方法变量一样,限定在了{}之中,自然就不需要设置访问说明符了,而且你可以想下,也只有类以及类的成员有访问修饰符,局部变量有访问修饰符么
局部类可以对外面完全的隐藏起来,即使是外部类的其他的代码也不能访问他
局部内部类虽然被限定在局部代码块{} 里面,但是他也是可以访问外部类的属性的,不要被分类迷惑了
匿名内部类
匿名内部类就是局部内部类的进一步隐藏,局部内部类定义了之后在局部区域内仍旧可以创建多个对象
匿名内部类声明一个类之后就只能创建一个对象了,因为他并没有类名字,所以匿名内部类适合那种只使用一次的情境。同时由于匿名内部类不能是抽象类,所以匿名内部类必须实现它的抽象父类或接口里包含的所有抽象方法。如下所示:
package innerclass;
interface Product
{
public double getPrice();
public String getName();
}
public class AnonymousInnerClass
{
public void test(Product p)
{
System.out.println("购买了一个" + p.getName()
+ ",花掉了" + p.getPrice());
}
public static void main(String[] args)
{
AnonymousInnerClass ta = new AnonymousInnerClass();
// 调用test()方法时,需要传入一个Product参数,
// 此处传入其匿名内部类的实例
ta.test(new Product()
{
public double getPrice()
{
return 3000;
}
public String getName()
{
return "笔记本";
}
});
}
}
运行结果:购买了一个笔记本,花掉了3000.0
在Java 8之前,Java要求被局部内部类、匿名内部类访问的局部变量必须使用final修饰,从Java 8开始这个限制取消了,Java 8更加智能:如果局部变量被匿名内部类访问,那么该局部变量相对于自动使用了final修饰。
package innerclass;
interface InnerInterface
{
void test();
}
public class InnerClass
{
public static void main(String[] args)
{
int i = 8; // ①
// 下面代码i = 2;将会导致编译错误
// 由于i局部变量被匿名内部类访问了,因此i相当于被final修饰了
// i = 2;
InnerInterface a = new InnerInterface()
{
public void test()
{
// 在Java 8以前下面语句将提示错误:age必须使用final修饰
// 从Java 8开始,匿名内部类、局部内部类允许访问非final的局部变量
System.out.println(i);
}
};
a.test();
}
}
这里顺嘴提一句,由于eclipse的bug,上面这段代码在eclipse跑的时候会报编译失败,即使已经使用了java8也没什么卵用,而实际上jdk8确实是支持了内部类访问局部变量的时候,局部变量不需要final修饰,应该是eclipse的更新跟不上jdk的缘故吧
静态内部类
使用static修饰的内部类,则是静态内部类。static可以修改内部类,但是不能修改外部类。
关于静态内部类,我的理解是当一个类只被某个类使用的时候,这个类就没必要单独写一个java文件来存放它,可以直接放在使用类的内部,并声明成静态内部类。
至于静态内部类的使用,其实也是相当简单,你就把他当成是外部类的一个静态成员即可,语法如下,具体实例我就不给了
假如StaticInnerClass是内部静态类,OuterClass是外部类:
OuterClass.StaticInnerClass inner = new OuterClass.StaticInnerClass();
转载:https://blog.csdn.net/JordanInShenzhen/article/details/102215302