将一个类定义在另一个类里面,对里面那个类,就叫内部类(嵌套类,内置类)
内部类样式
class Out{
//内部类
class Inner{
}
}
- 生成的class文件样为 Out$Inner.class
内部类的特点
- 内部类可以使用所属类的所有成员
class Out{
private int x=5;
class Inner{
void print(){
System.out.println("Inner print"+x);
}
}
public void show(){
Inner in = new Inner();
in.print();
}
}
- 所属类要访问内部类的成员,则需要创建对象
- 内部类定义在成员的位置,所以可以被成员修饰符修饰,private,protected,public
- 直接访问内部类的定义格式
class Out{
private int x=5;
class Inner{
void print(){
System.out.println("Inner print"+x);
}
}
public void show(){
Inner in = new Inner();
in.print();
}
}
class TestInnerClass {
public static void main(String[] args) {
Out.Inner in = new Out().new Inner();
in.print();
}
}
- 静态内部类的创建方式,可以直接使用,不常用static
class Out{
private int x=5;
static class Inner{
void print(){
System.out.println("Inner print");
}
static void test(){
System.out.println("test");
}
}
public void show(){
Inner in = new Inner();
in.print();
}
}
class TestInnerClass {
public static void main(String[] args) {
//内部类方法调用
Out.Inner in = new Out.Inner();
in.print();
//内部类静态方法调用
Out.Inner.test();
}
}
- 如果内部类有静态成员,则该内部类也必须是静态的
- 内部类之所以能访问外部类的成员,是因为内部类持有了外部类的引用(外部类ming.this)
局部内部类
- 内部类可以放在局部位置上
class Out{
int num=10;
void show(){
//类定义在方法内
class Inner{
void showInner(){
System.out.println("showInner"+num);
}
}
Inner inner = new Inner();
inner.showInner();
}
}
class TestInnerClass2 {
public static void main(String[] args) {
new Out().show();
}
}
- 局部内部类中,只能访问局部中被final修饰的局部变量
class Out{
int num=10;
void show(){
int x=2;
//这里这样就会报错了,因为局部内部类只能访问被final修饰的变量,如果未加,则编译器自动加上final
//所以x=3报错
x=3;
class Inner{
void showInner(){
System.out.println("showInner="+x);
}
}
Inner inner = new Inner();
inner.showInner();
}
}
class TestInnerClass2 {
public static void main(String[] args) {
new Out().show();
}
}
匿名内部类
- 匿名内部类,其实就是内部类的简写格式。
- 匿名内部类的前提是:内部类必须继承或者实现一个外部类或者接口。
抽象类
/**
* 抽象父类
*/
abstract class Parent {
abstract void show();
}
class Out {
public void function() {
//匿名内部类的定义
new Parent() {
@Override
void show() {
System.out.println("show");
}
}.show();
}
}
class UnName {
public static void main(String[] args) {
new Out().function();
}
}
接口
/**
* 接口
*/
interface Parent {
public void show();
}
class Out {
public void function() {
//匿名内部类的定义
new Parent() {
@Override
public void show() {
System.out.println("show");
}
}.show();
}
}
class UnName {
public static void main(String[] args) {
new Out().function();
}
}
- 匿名内部类的格式 new 父类[接口]{匿名类实现内容+自己的内容}
匿名内部类的使用场景
- 当函数的参数是接口类型时,而且接口中的方法不超过三个,可以使用匿名内部类作为实际参数进行传递,方法不超过三个,主要是方法过多会使得该类过于庞大,不便于阅读。
扩展方法时,直接使用
class Out {
public void function() {
//匿名内部类的定义
new Object() {
public void show() {
System.out.println("show1");
}
}.show();
}
}
class UnName {
public static void main(String[] args) {
new Out().function();
}
}
扩展方法时使用变量接收则编译错误
class Out {
public void function() {
//匿名内部类的定义
Object obj = new Object() {
public void show() {
System.out.println("show1");
}
};
obj.show();
}
}
class UnName {
public static void main(String[] args) {
new Out().function();
}
}
原因在于子类对象被类型提升之后,就不能使用子类的特有方法了