此篇涉及到一些前提知识点,单例模式和static关键字的作用。
可以将一个类定义在另一个类的内部或者类的方法内部,这样的类叫内部类。
内部类一般分为四种,分别是成员内部类、局部内部类、匿名内部类和静态内部类。
成员内部类是最普通的内部类,位于一个类的内部,具体呈现如下:
public class Laptop {
private String brand;
public Laptop(String brand) {
this.brand = brand;
}
// 内部类
class CPU {
public void print() {
System.out.println("CPU");
}
}
}
这样看起来,CPU类就像Laptop的一个成员,Laptop也被称为外部类;于是我们也可以推断出,CPU类能想成员方法愿意跟你访问外部类的变量和方法,包括private和静态成员,具体如下
public class Laptop {
private String brand = "ThinkPad";
public static double price = 9999;
public Laptop(String brand) {
this.brand = brand;
}
// 内部类
class CPU {
public void print() {
// 外部类的私有变量和静态变量
System.out.println(brand);
System.out.println(price);
}
}
}
当内部类和外部类有相同名字的对象时,成员内部类默认调用的是自身的成员。如若要访问外部成员,需要使用以下格式
外部类.this.成员变量
外部类.this.成员变量
public class Laptop {
private String brand;
private static double price = 9999;
public Laptop(String brand) {
this.brand = brand;
}
// 内部类
class CPU {
private String brand = "AMD";
public void print() {
System.out.println(brand); // 成员内部类对象
System.out.println(Laptop.this.brand); // 外部类对象
}
}
}
public class LaptopTest {
public static void main(String[] args) {
Laptop laptop = new Laptop("ThinkPad");
Laptop.CPU cpu = laptop.new CPU();
cpu.print();
}
}
输出如下:
然而外部类想访问成员内部类的成员时,就不能直接访问了,需要先创建内部类的对象,再通过对象去调用
public class Laptop {
private String brand = "ThinkPad";
private static double price = 9999;
private CPU cpu;
public Laptop(String brand) {
this.brand = brand;
getCPUInstances().print();
}
// 获取CPU类对象
public CPU getCPUInstances() {
return new CPU();
}
// 内部类
class CPU {
private String brand = "AMD";
public CPU() {
}
public void print() {
System.out.println(brand);
System.out.println(Laptop.this.brand);
}
}
}
public class LaptopTest {
@Test
public void laptopTest(){
Laptop laptop = new Laptop("ThinkPad");
}
}
这里用了junit进行测试,结果如下:
创建成员内部类对象的方法一般有两种,如下:
public class Laptop {
private CPU cpu = null;
public Laptop() {
}
public CPU getCPUInstances() {
if (cpu == null) {
return new CPU();
}
return cpu;
}
// 内部类
class CPU {
public CPU() {
}
}
}
class LaptopTest {
// 方式一:使用Laptop对象创建
Laptop laptop = new Laptop();
Laptop.CPU cpu = laptop.new CPU();
// 方式二:
Laptop.CPU cpuOther = laptop.getCPUInstances();
}
方式一的写法,后面的静态内部类会给出解释
成员内部类也是可以设置访问权限的,和外部类不同,外部类只能设置publish和protected两种权限,而内部类可以用四种。当设置为private时,只有外部类可以访问,当设置为publish时,所有类都可以访问,当设置为protected时,只有同包和继承外部类的情况下可以访问,设置为默认时,只有同包下可以访问。这种情况的原因可以想象成,成员内部类相当于外部类的一个成员,成员是可以有四种修饰方法的。
定义在一个方法或者一个作用域内的类是局部内部类,访问权限只限于方法或作用域内,和局部变量一样,它也不能有修饰符
public class Laptop {
public void laptop() {
class CPU {
}
}
}
静态内部类和成员内部类一样,也是定义在一个类中的,不一样的是前面加了个static关键字。静态内部类只能访问同样加了static的成员,否则就会报错。
匿名内部类,匿名内部类和局部内部类一样,在Android开发中属于用的比较多的一种。常见于各种按钮,开关等的点击监听事件的回调函数中。下面是一段Android中的匿名内部类:
// 方法
public void setOnClickListener(@Nullable OnClickListener l) {
............
}
// 接口
public interface OnClickListener {
/**
* Called when a view has been clicked.
*
* @param v The view that was clicked.
*/
void onClick(View v);
}
// 按钮调用方法
localMusicButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 打开本地音乐
}
});
setOnClickListener()的参数是一个接口,调用方法时需要传入一个实现类,上面的调用分开来写的话,就是:
class onClickListenImpl implements View.OnClickListener {
@Override
public void onClick(View v) {
// 进入本地音乐
}
}
localMusic.setOnClickListener(new onClickListenImpl());
使用匿名内部类就可以省略部分代码,甚至Java 8值后的lambda表达式可以进一步缩写为
localMusic.setOnClickListener(v -> {
// 打开本地音乐
});
不过这种情况只限于当做参数的接口内只有一个方法时才可以,具体可以查询Lambda表达式和Java回调相关的知识点。