一、概念
内部类就是在一个类的内部定义的类,在一个类的内部进行其它类结构的嵌套的操作。
二、内部类的作用(为什么要存在?)
a.内部类允许把一些逻辑相关的类组织在一起,并且控制内部类代码的可视性。
b.内部类方法可以访问该类定义所在作用域中的数据,包括被private修饰的私有数据。
c.内部类可以对同一包中的其它类(除外部类外)隐藏起来。
d.内部类可以弥补Java单继承的缺陷。(一类套一类)
e.当我们想要定义一个回调函数却不想写大量代码时,可以选择用匿名内部类实现。
三、内部类和外部类的关系
a.对于非静态内部类,内部类的实例化依赖于外部类的实例对象,必须先对外部类进行实例化后,才可以将内部类实例化。
b.内部类可以访问外部类的所有成员(包括private修饰的成员),但是外部类不能直接访问内部类的成员。
c.外部类可以通过实例化内部类间接访问内部类的元素。
d.内部类是一个相对独立的个体,与外部类不是类的父子继承关系(is-a关系)。
e.在多重嵌套时,内部类可以访问其所有外围类的元素。
f.一个外部类可以实例化多个内部类,但是一个内部类实例只会引用一个外部类。
四、内部类的分类、说明和使用
1.成员内部类
不被static修饰的内部类。如:
class A{
class B{//B为成员内部类
}
}
定义成员内部类:
外部类.内部类 内部对象=new 外部类().new 内部类(); eg:A.B b=new A().new B();
说明:
a.成员内部类中不能含有任何被static修饰的变量、方法和内部类。
b.成员内部类的实例化依赖于外部类,只有当外部类实例化后,内部类才可以实例化。
c.如果成员内部类B和外部类A具有相同的变量名v,这没有任何影响。在类B中,用this.v代表类B的变量v;用A.this.v代表类A的变量v.
2.静态内部类
用static修饰的内部类。如:
class A{
class B{
int v1;//实例变量
static int v2;//静态变量
public class C{//静态内部类
static int v3;
}
}
}
定义静态内部类:
外部类.内部类 内部对象=new 外部类.内部类(); eg:A.B b=new A.B();
说明:
a.静态内部类不能使用外部类的任何非静态成员,这些成员必须通过外部类的实例化访问。
b.静态内部类可以直接访问外部类的静态成员。A.B.v2=1;
c.在静态内部类中可以定义静态成员和非静态成员。
d.客户类可以通过完整的类名直接访问静态内部类的静态成员。
如: 在上例中,
访问v1: A.B b=new A.B(); b.v1=1;
访问v2: A.B.v2=1;
访问v3: A.B.C.v3=5;
3.方法内部类
定义在外部类方法中的内部类,只在该方法内有效。如:
public class Test{
public static void main(String[] args){
A a=new A();
A.fun();
}
}
class A{
int age;
static void fun(){
class B{
String date="2018-11-17";
public B(){
System.out.println("我是内部类的构造方法");
}
public void print(){
date="1998-8-20";
date="2018-11-18";
System.out.println(date);//通过定义匿名对象来调用方法内部类的属性
System.out.println("我是方法内部类");
}
}
new B().print();//通过定义匿名对象来调用方法内部类的函数
}
}
结果:
2018-11-18
我是方法内部类
说明:
a.静态内部类的实例化不依赖于外部类,可以直接创建。
b.方法内部类的作用域只在该方法内部有效。对于外部类,该内部类都是无效的。
c.局部内部类如果想使用方法形参,该形参必须使用final声明。(JDK8中形参声明为隐式final声明)。
d.局部内部类不允许使用任何修饰符public、private、protected修饰。
4.匿名内部类
没有名字的方法内部类.因此,它符合方法内部类的所有约束。 如:
public class Test{
public static void main(String[] args){
Outer outer=new Outer();
outer.display(20);
}
}
interface MyInterFace{
void test();
}
class Outer{
private int num;
public void display(int para){
//匿名内部类,实现MyInterface接口
new MyInterFace(){
public void test(){
System.out.println("匿名内部类"+para);
}
}.test();
}
}
结果:
匿名内部类20
说明:
a.匿名内部类不允许使用任何修饰符public、private、protected修饰。
b.匿名内部类必须继承一个抽象类或实现一个接口。
c.匿名内部类中不能存在任何静态方法或成员。
d.匿名内部类因为没有名字,不能有任何构造方法。
e.匿名内部类可以引用方法形参,但是必须声明为final。
五、内部类的一些其它说明
1.如果在外部类和内部类中定义了相同的属性(变量名相同,但是内容不同),则按照就近原则。要想在内部类中访问外部类的属性或方法,需要定义 外部类.this.属性名/方法名。
package com.xupu.testinnerclass;
class Outter{
private String str="Outter";
private class Inner{//只能由外部类定义
private String str="Inner";
void fun(){
System.out.println("我是成员内部类"+" "+str);
}
}
public void fun(){
System.out.println(str);
Inner inner=new Inner();
inner.fun();
}
}
public class TestInnerClass {
public static void main(String[] args) {
Outter outter=new Outter();
outter.fun();
}
}
结果: