基本定义与分类
内部类不同于普通类,在一个类的类体内部或类内部的方法内部或类体外部产生,而无需重建一个Class来产生。依照使用位置和关键字修饰不同可以分为成员内部类、局部内部类、静态内部类和匿名内部类。
- 成员内部类
不用static修饰,存在于外部类类体中,可以看做是外部类的一个成员,可以无条件的使用外部类的所有成员和方法,使用方式为OuterClassName.this.xxx(成员名)和OutClassName.this.xxx(方法名)。
class InheritInner {
public void show() {}
class Inner {
public void showOut () {
InheritInner.this.show();
}
}
}
外部类无法直接访问成员内部类的成员和属性,要想访问必须得先创建一个成员内部类的对象然后通过指向这个对象的引用来访问。
class InheritInner {
public void show() {System.out.println("something");}
InheritInner.Inner inner = null;
public InheritInner.Inner getInner() {
if(inner == null) inner = new InheritInner.Inner();
return inner;
}
class Inner {
public void showOut () {
InheritInner.this.show();
}
}
}
然后再应用层进行InheritInner.Inner的具体使用。
public class Demo {
public static void main(String[] args) {
InheritInner.Inner inner = new InheritInner().getInner();
inner.showOut();
}
}
something
- 局部内部类
1.是定义在一个方法里面的类,和成员内部类的区别在于局部内部类的访问仅限于方法内;
2.局部内部类就像是方法里面的一个局部变量一样,所以其类 class 前面是不能有 public、protected、private、static 修饰符的,也不可以在此方法外对其实例化使用。
- 静态内部类
静态内部类是用static关键字修饰的内部类,class的修饰词可以使pubic、protected和private,必须作为内部类的最外层存在。
class Inner {
static class InInner {}
}
如上的定义方法是错误的。
静态内部类无需依靠外部类实例就可实例化。关于其调用成员的能力,只能调用外部类的静态成员和方法。
注意:当其外部方法为静态方法时无需用static关键词修饰,因为静态方法内的所有成员都默认被static修饰,静态内部类可以使用静态方法的所有成员。
public class Demo {
public static void main(String[] args) {
InheritInner.makeMan();
// InheritInner.Inner inner = new InheritInner().getInner();
// inner.showOut();
}
}
class InheritInner {
// public void show() {System.out.println("something");}
// InheritInner.Inner inner = null;
//
// public InheritInner.Inner getInner() {
// if(inner == null) inner = new InheritInner.Inner();
// return inner;
// }
public static void makeMan() {
String staticName = "Tony Stark";
class Men {
private String name;
public Men() {
}
public Men make() {
this.name = staticName;
return this;
}
@Override
public String toString() {
return "his name is " + name;
}
}
}
Men men = new Men();
men.make();
System.out.println(men);
}
- 匿名内部类
1.是一种没有构造器的类(实质是继承类或实现接口的子类匿名对象),
2.由于没有构造器所以匿名内部类的使用范围非常有限,大部分匿名内部类用于接口回调,匿名内部类在编译的时候由系统自动起名为 OutClass$1.class,一般匿名内部类用于继承其他类或实现接口且不需要增加额外方法的场景(只是对继承方法的实现或是重写);匿名内部类的 class 前面不能有 pravite 等修饰符和 static 修饰符;匿名内部类访问外部类的成员属性时外部类的成员属性需要添加 final 修饰(1.8 开始可以不用)。
最常见用法就是AddKeyListener,new Thread时产生的一堆需要实现的方法,这些用法就是接口回调的一种。
转载几道有意思的小题目
原文链接:https://www.cnblogs.com/dolphin0520/p/3811445.html
1.根据注释填写(1),(2),(3)处的代码
public class Test{
public static void main(String[] args){
// 初始化Bean1
(1)
bean1.I++;
// 初始化Bean2
(2)
bean2.J++;
//初始化Bean3
(3)
bean3.k++;
}
class Bean1{
public int I = 0;
}
static class Bean2{
public int J = 0;
}
}
class Bean{
class Bean3{
public int k = 0;
}
}
从前面可知,对于成员内部类,必须先产生外部类的实例化对象,才能产生内部类的实例化对象。而静态内部类不用产生外部类的实例化对象即可产生内部类的实例化对象。
创建静态内部类对象的一般形式为: 外部类类名.内部类类名 xxx = new 外部类类名.内部类类名()
创建成员内部类对象的一般形式为: 外部类类名.内部类类名 xxx = 外部类对象名.new 内部类类名()
因此,(1),(2),(3)处的代码分别为:
Test test = new Test();
Test.Bean1 bean1 = test.new Bean1();
Test.Bean2 b2 = new Test.Bean2();
Bean bean = new Bean();
Bean.Bean3 bean3 = bean.new Bean3();
2.下面这段代码的输出结果是什么?
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
outter.new Inner().print();
}
}
class Outter
{
private int a = 1;
class Inner {
private int a = 2;
public void print() {
int a = 3;
System.out.println("局部变量:" + a);
System.out.println("内部类变量:" + this.a);
System.out.println("外部类变量:" + Outter.this.a);
}
}
}
3
2
1
最后补充一点知识:关于成员内部类的继承问题。一般来说,内部类是很少用来作为继承用的。但是当用来继承的话,要注意两点:
1)成员内部类的引用方式必须为 Outter.Inner.
2)构造器中必须有指向外部类对象的引用,并通过这个引用调用super()。这段代码摘自《Java编程思想》
class WithInner {
class Inner{
}
}
class InheritInner extends WithInner.Inner {
// InheritInner() 是不能通过编译的,一定要加上形参
InheritInner(WithInner wi) {
wi.super(); //必须有这句调用
}
public static void main(String[] args) {
WithInner wi = new WithInner();
InheritInner obj = new InheritInner(wi);
}
}