在一个外部类中定义的类称为内部类,内部类按照有无名字可以划分为有名内部类和匿名内部类
一.有名内部类
有名内部类顾名思义就是有名字的类,如下就是一个有名内部类,内部类中可以像正常的类一样定义属性和方法:
public class Body {
class Heart{
void work(){
System.out.println("working");
}
}
}
二.匿名内部类
匿名内部类天生没有类名,但是创建对象却需要类名,所以解决办法就是在匿名内部类定义的时候和创建对象一起定义,而创建对象使用父类的构造方法,如果父类是接口则使用new(接口名)()的方式创建对象,如下:
public class Mammal {
void work() {
System.out.println("...");
}
}
public class Body {
Mammal mammal=new Mammal() {//匿名内部类
};
}
对于这个创建和定义的方式,存在着好多的疑点,在下面会一一解答。
三.匿名内部类的特点
1.匿名内部类是普通类的子类
在匿名内部类的定义过程中,使用的是父类的构造方法,而所有普通类都可以作为匿名内部类的父类,上一段代码中就是使用的普通类
2.匿名内部类是抽象类的子类
当我们将Mammal类改为抽象类,在创建匿名内部类时还是可以使用Mammal类的构造方法,所以抽象类也可以作为匿名内部类的父类。
public abstract class Mammal {
void work() {
System.out.println("...");
}
}
public class Body {
Mammal mammal=new Mammal() {
};
}
3.匿名内部类是接口的实现类
如果将Mammal定义为接口,则匿名内部类则是接口的实现类,在创建对象时还是一样的操作,还可以在内部类中重写接口中的方法进行实现:
public interface Mammal {
void work();
}
public class Body {
Mammal mammal=new Mammal() {
@Override
public void work() {
System.out.println("working...");
}
};
}
4.匿名内部类不能为抽象类
因为匿名没有名字,如果可以抽象,则该匿名类必须有子类,但是由于没有名字,无法被继承,所以没有子类
5.匿名内部类的创建是对象上转型
它的原理就是将匿名内部类的对象的地址存放在了Mammal类的变量mammal中,所以用对象mammal调用work方法时,表面上调用Mammal中的work方法,实则调用匿名内部类中的work方法:
public class Mammal {
void work() {
System.out.println("work");
}
}
public class Body {
public static void main(String[] args) {
Mammal mammal=new Mammal() {
@Override
public void work() {
System.out.println("working...");
}
};
mammal.work();
}
}
6.匿名内部类新增的属性和方法
匿名内部类中可以新增属性和方法,但是因为匿名内部类创建的是上转型对象,而上转型对象调无法调用新增的属性和方法。
7.匿名内部类不能自定义构造方法
因为匿名内部类没有名字,所以根本就无法使用构造方法,自然也不能定义构造方法,只能通过调用父类的构造方法来创建对象
四.内部类的使用
1.编译方式
无论是有名内部类还是匿名内部类,javac都会产生一个独立的class文件,编译之后内部类会被编译成独立的.class文件。
如果该内部类为有名内部类,则有名内部类字节码文件名为外部类的类名+$+内部类类名;
如果为匿名内部类,则匿名内部类字节码文件名为外部类类名+$+数字;
去到存储项目的文件中即可查到编译生成的class文件
2.final修饰符
如果要在内部类中使用局部变量的值,需要在前面加final,如果JDK是8.0及以上版本的则不需要加:
public class Body{
public static void main(String[] args) {
Mammal mammal=new Mammal() {
public void work(final String name) {
System.out.println(name);
}
};
}
}
3.private修饰的成员变量
如果一个成员变量被private修饰,则说明该成员变量只能在本类中使用,而内部类就是定义在外部类中,所以该成员变量可以在内部类中使用
public class Body{
private static int age=12;
public static void main(String[] args) {
Mammal mammal=new Mammal() {
public void work() {
System.out.println(age);
}
};
mammal.work();
}
}
4.访问权限
能修饰类的访问权限修饰符有public和默认的,但是在直接定义在外部类中的内部类,public、默认的、protected、private都可以修饰它:
public class Body{
protected Mammal mammal=new Mammal() {
public void work() {
System.out.println();
}
};
}
5.内部类的调用
我们都知道,在静态方法中无法调用非静态方法,那么如果一个内部类是非静态的,且直接定义在类中,则不能直接在main方法中创建对象,要先创建外部类的对象,然后用外部类调用构造方法创建内部类对象,再通过内部类对象调用内部类中的方法:
public class Body{
class Heart{
public void work() {
System.out.println("working");
}
}
public static void main(String[] args) {
Body body = new Body();
Heart heart=body.new Heart();
heart.work();
}
}