Java内部类

此篇涉及到一些前提知识点,单例模式和static关键字的作用。

一、定义

可以将一个类定义在另一个类的内部或者类的方法内部,这样的类叫内部类。

二、分类

内部类一般分为四种,分别是成员内部类、局部内部类、匿名内部类和静态内部类。

2.1 成员内部类

成员内部类是最普通的内部类,位于一个类的内部,具体呈现如下:

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();
    }
}

输出如下:

Java内部类_第1张图片

然而外部类想访问成员内部类的成员时,就不能直接访问了,需要先创建内部类的对象,再通过对象去调用

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进行测试,结果如下:

Java内部类_第2张图片

创建成员内部类对象的方法一般有两种,如下:

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时,只有同包和继承外部类的情况下可以访问,设置为默认时,只有同包下可以访问。这种情况的原因可以想象成,成员内部类相当于外部类的一个成员,成员是可以有四种修饰方法的。

2.2 局部内部类

定义在一个方法或者一个作用域内的类是局部内部类,访问权限只限于方法或作用域内,和局部变量一样,它也不能有修饰符

public class Laptop {

    public void laptop() {
        class CPU {

        }
    }
}

2.3 静态内部类

静态内部类和成员内部类一样,也是定义在一个类中的,不一样的是前面加了个static关键字。静态内部类只能访问同样加了static的成员,否则就会报错。

Java内部类_第3张图片

2.4 匿名内部类

匿名内部类,匿名内部类和局部内部类一样,在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回调相关的知识点。

你可能感兴趣的:(Java,java)