在之前的博客中,我发现自己没有对内部类进行一个初步了解,所以在学习完内部类后,用这篇博客做个笔记
内部类:顾名思义,就是一个在内部的类,在类的内部的类(有点绕),当然也可以是接口,即在接口的内部的类或接口。内部类的特性之一是可以访问外部类的属性和方法,而外部类想访问内部类的属性和方法需要创建内部类对象才可。
代码如下,一眼明了内部类张啥样:
public class Lei {
public class NeiBuLei{
}
}
内部类分为4种:
- .非静态内部类
- 静态内部类
- 局部内部类
- 匿名内部类
其中非静态和静态内部类统称为成员内部类
非静态内部类:
简单来说就是没有用static来修饰的类,不是静态的类,需要知道的是非静态内部类是需要外部类对象存在的时候才有意义的,没有外部对象时,就无法通过外部对象创建内部类的实例,就访问不到内部类的属性和方法。
如下代码演示:
public class Fei_jin_tai {
class NeiBulei{//非静态内部类
String name ;
public void PrintName(){
System.out.println(name);
}
}
public static void main(String[] args) {
Fei_jin_tai.NeiBulei a = new Fei_jin_tai().new NeiBulei();//利用外部类对象创建内部类的实例
a.name = "NB";//对象a访问内部类属性
a.PrintName();//对象a调用内部类方法
}
}
创建内部对象的格式:外部类.内部类 对象名 = 外部类对象.内部类对象;
这是非静态内部类,实例化时需要有一个外部对象为基础。
当内部类想要访问外部类的属性和方法时,需要有个内部对象就可以直接访问外部成员。
静态内部类:
简单来说就是用static修饰的的内部类,与非静态内部类不同的是,静态内部类不依赖于外部类对象,外部类想要访问内部类的属性和方法时,直接用类名创建内部类对象。
代码如下演示:
public class Jin_tai {
static class NeiBuLei{//静态内部类
String name;
public void PrintName(){
System.out.println(name);
}
}
public static void main(String[] args) {
Jin_tai.NeiBuLei a = new Jin_tai.NeiBuLei();//直接通过类名创建内部类实例
a.name = "NB";
a.PrintName();
}
}
创建内部对象的格式:外部类.内部类 对象名 = new 外部类.内部类对象;
静态内部类和普通类区别不大,除了可以直接访问外部类的私有静态属性和静态方法,普通类也是创建一个该类的实例就可以访问类中的属性和方法。
当静态内部类想要访问外部类的属性和方法时,那就只能访问外部的静态成员了。
补充说一句,如果静态内部类的PrintName方法也是静态的,有些人调用这个方法时会直接写a.PrintName,但是在idea中是不提倡这样做的,这方法都是静态的了干嘛还有对象去调用呢,直接类名调用就好了。
如下:
public static void Printname(){
System.out.println(Name);
}
}
public static void main(String[] args) {
NeiBuLei.Printname();
}
}
局部内部类:
简单来说就是定义在方法里的类,和静态内部类似的地方是,外部类访问局部内部类时,也需要创建一个内部对象来访问内部成员,不过需要在方法内部创建
代码如下演示:
public class Ju_Bu {
public void Ju_bu() {
class NeiBuLei {//局部内部类
String name;
public void PrintName() {
System.out.println(name);
}
}
NeiBuLei a = new NeiBuLei();
a.name = "NB";
a.PrintName();
}
public static void main(String[] args) {
Ju_Bu A = new Ju_Bu();//创建外部对象调用方法
A.Ju_bu();
}
}
局部内部类与成员内部类的位置是相对的,一个在成员位置,一个在局部位置。
匿名内部类:
简单来说是不显示类名的内部类,并同时实例化它。匿名内部类可以更方便的实现接口或抽象类,当一个接口或抽象类只需要实现一次,通过匿名内部类就可以实现,将方法重写到内部类中,这就避免了重新创建独立的一个类去实现。
创建匿名内部类的格式如下:
外部类 对象名 = new 外部类对象{
重写方法
}
};
这看起来像是在创建对象,其实从语法上来说,它的一个整体就是创建一个匿名内部类的对象。
如下代码演示:
先创建一个接口:
public interface PrintName {
public abstract void PrintName();
}
再创建一个测试类:
public class Ni_ming {
public static void main(String[] args) {
PrintName A =new PrintName() {
String name = "NB";
@Override
public void PrintName() {
System.out.println(name);
}
};
A.PrintName();
}
}
观察代码可以发现,这样子做就直接实现了PrintName接口并实现里面的方法,而不使用内部类的话,因为接口不能自己创建对象的,就要再创建一个类实现该接口,再到创建测试类中创建对象实现该方法,代码量就多了。当然,除了接口,抽象类也是一样。上面代码我写在了main方法中,也就是说,这可以说是一个局部匿名内部类。
说到类名被不显示,其实类名还是有的,只是隐匿了起来,在idea中打开源文件我们们找到out文件夹。这里面装了所以的字节码文件,也就是编译后的class文件,我们可以看到其中一个Ni_ming类后面有$这样一个符号再另加一个数字1,如果在Ni_ming类中创建了一个新的内部类,数字就会更新为2,其实这就是匿名内部类的类名。
补充:当匿名内部类中只有一个方法时而且只要使用一次时,创建匿名内部类对象可以不创建对象名,在后面也可以直接调用类中的方法。
public static void main(String[] args) {
new PrintName() {
String name = "NB";
@Override
public void PrintName() {
System.out.println(name);
}
}.PrintName();
}
匿名内部类还有个重要的作用,就是可以作为参数传递,因为匿名内部类本身整体就是一个对象,当方法中需要以对象作为参数时,那就可以把这一个整体传进去,如下代码演示:
public class Test {
public static void main(String[] args) {
method(new PrintName(){
String name = "NB";
public void Printname(){
System.out.println(name);
}
});
}
public static void method(PrintName p){
p.Printname();
}
}
匿名内部类在应用开发中很重要,它提高了代码的简洁性和灵活性。我还浅浅的了解到,在Java开发游戏,游戏优化和匿名内部类有点联系。说点题外话,除了我们都熟知的我的世界和FIFA,我感觉现在没多少游戏用Java开发的了,像apex,pubg,堡垒之夜大多都用c++。