内部类
前言
这里是 Java 系列文章,主要介绍Java语言的使用。
Java语言的重要性不言而喻
关于作者:
- 小白(Libra),计算机兴趣爱好者,Java,C,C++,Hadoop,MySQL
- Email : hewei20031009@163.com
- GitHub : https://github.com/Regel-zack
转载请注明出处
正文
为什么要使用内部类?
在这个世界上,有很多的技术,我们没有全部学习的必要,我们可以让专人去做专门的事,这也是社会分工的由来,那么问题来了,在Java中,我们有学习内部类的必要吗,或者说,我们为什么要学习内部类,由此,我们需要先论证出学习内部类的必要再引出下文,如何学习内部类
如果我们想要知道为什么a比b更好或者是更值得等,首先就得先知道a是什么
什么是内部类?
在一个类中以class关键字又定义一个类,我们便把里面的类称为内部类,外面的类称为外部类
例如如下实例
/**
* Country 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:42
* @author 别欺负小白了好咩
*/
public class Country {
class Capital{
}
}
在这其中,有一个外部类Country类,还有一个内部类Capital类
那这个时候肯定有人会说了,内部类不是破坏了类的结构吗,一个类应当包含属性和方法,但是这又多出来一个类,那里面的内部类还能再嵌套一层内部类咯?
那这是自然,内部类破坏了类的结构,但它所带来的优势却是不用内部类所带来不了的
例如如下实例
/**
* Country 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:42
* @author 别欺负小白了好咩
*/
public class Country {
String name = "name";
class Capital{
public void info(){
System.out.println(name);
}
class RoyalPalace{
}
}
public void print(){
new Capital().info();
}
}
/**
* Application 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:46
* @author 别欺负小白了好咩
*/
public class Application {
public static void main(String[] args) {
Country country = new Country();
country.print();
}
}
由此我们得出了内部类的基本特点以及优势和缺点,即
- 内部类定义在其他类的内部,重新用class关键字定义
- 内部类破坏了类的基本结构
- 尽管破坏了类的基本结构,但是其带来的方便,内部类可以很方便的操作外部类的属性,甚至是私有属性
那也就是说只要有人问你,为啥要用内部类呀,内部类是什么啊?
你统统都用这个回答即可
静态内部类
但是在上面我们发现一个问题,为什么不能直接在Application类中实例化内部类呢,比如说像这样
Capital capital = new Capital();
这样子不是更加方便吗,我们直接用内部类的对象去操作外部类的属性,这不比我们在外部类中再写一个实例化内部类的方法更加方便吗?
那这里呢,也就带来了一个逻辑上的问题,假如没有外部类,那就没有内部类,因为内部是相对于外部的,所以,内部类的对象的存在依赖于外部类的对象的存在,因此,我们不可能脱离外部类去实例化内部类。
那这个时候又会有人提出疑问了,那我将语句定义成这样:
Country.Capital capital = new Country.Capital();
这下总行了吧,体现出了内部类和外部类的包含关系,那我这样不也能达到我所想要的结果吗?
那实际上我们还差一步,那就是将内部类用static声明成静态的,这样,我们就可以用这样的语句了
那又产生疑问了,这是为啥?为啥我想直接调用内部类的对象还得声明它是个静态的?
那我们上面的话仍然可以回答下面这个问题,内部类的存在依赖于外部类的存在,如果没有外部类对象,那么也就没有有内部类这个说法了。
但这只解释了前半个问题,没有解决后半个,为什么是静态的?
这个跟JVM有关,当你用static声明一个变量,类等为静态的时候,其值就会在编译期被确定下来,也就是在最开始的时候就已经被划分了内存空间并且存储了,生成的字节码文件里有它了,不管你调不调用,都是有了,那由此也就减少了内部类对外部类的依赖,可以脱离于外部类而存在了,因此我们的代码实例可以改为以下:
/**
* Country 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:42
* @author 别欺负小白了好咩
*/
public class Country {
String name = "name";
class Capital{
public void info(){
System.out.println(name);
}
}
static class Person{
public void info(){
System.out.println(name);
}
}
public void print(){
new Capital().info();
}
}
/**
* Application 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:46
* @author 别欺负小白了好咩
*/
public class Application {
public static void main(String[] args) {
Country country = new Country();
country.print();
Country.Person person = new Country.Person();
}
}
但是这个时候我们会发现,假如我们去用静态内部类对象去直接调用外部类非静态属性的时候,就无法调用了
public static void main(String[] args) {
Country country = new Country();
country.print();
Country.Person person = new Country.Person();
person.info();
}
提示是无法从静态上下文中引用非静态变量name
那这个问题呢,还是可以用上面的回答来解决,被声明为静态的,在编译期间就已经确定了,它是被预先加载的,而没有被预先加载的,这个时候不可见,不知道,那你如何去引用呢,不可能引用一个不存在的嘛。
由此,静态内部类我们讲完了
外部调用内部类
那我们如何从外部去调用内部类呢,或者说,如何创建一个内部类对象呢,难道我们每一步都需要去调用外部类去创建一个匿名内部类对象才能用内部类吗?
那答案自然是否定的
接下来我们演示有外部类对象的情况下实例化内部类对象并实现内部类访问外部类私有属性
如下代码实例:
/**
* Country 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:42
* @author 别欺负小白了好咩
*/
public class Country {
String name = "name";
private int people = 10000;
class Capital{
public void info(){
System.out.println(name);
}
public void showPeople(){
System.out.println(people);
}
}
static class Person{
}
public void print(){
new Capital().info();
}
}
/**
* Application 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:46
* @author 别欺负小白了好咩
*/
public class Application {
public static void main(String[] args) {
Country country = new Country();
Country.Capital capital = country.new Capital();
capital.showPeople();
}
}
这就实现了实例化内部类对象去访问外部类私有属性的操作了,非常的方便,也符合人的思考逻辑
方法内部类
代码实例如下
/**
* Country 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:42
* @author 别欺负小白了好咩
*/
public class Country {
String name = "name";
private int people = 10000;
public void print(final int temp){
class Inner{
public void print(){
System.out.println(name);
System.out.println(temp);
}
}
new Inner().print();
}
}
/**
* Application 类
* 操作人:小白
* 日期:2021/11/13
* 时间:11:46
* @author 别欺负小白了好咩
*/
public class Application {
public static void main(String[] args) {
new Country().print(10);
}
}
如果在方法内想要访问到就必须要加final声明,这个跟构造器有关,在内部类编译好后,内部类会有指向外部类的的引用,其中包括外部类的属性,那也正是由于此内部类可以访问外部类的属性,而如果外部类的局部变量,不加final修饰的话,那么在外部类修改后,而内部类操作时就不一致了,这不一致的原因是,外部类方法执行完毕之后,局部变量随之消散,而内部类所拥有的只不过是一个副本罢了,而内部类构造完毕之后,也就是副本生成完毕之后,外部类的局部变量被修改了,那么就完完全全不一致了,因为内部类所拿到的局部变量也只是一个副本,因此,内部类若想要访问到局部变量,需要给局部变量添加上final声明。
结语
于此,内部类讲解完毕。感谢大家的阅读与观看,本博客提到的所有代码建议亲自上手敲打学习。