前言
这几天趁着时间多多,回顾并总结出来超全面的Java内部类知识;Java内部类老实说我们在开发的时候用的不多,然而正是因为用的不多,久而久之我们就忘了Java内部类,所以才想写这一篇博客,相信看了这篇博客之后,你绝对敢说学会了Java内部类,如果遇到面试的时候,吹给面试官听,很可能面试官就会对你刮目相看(面试官内心独白:这个小伙子不错哟,Java内部类用的不多都这么熟悉,那么经常使用的技术是不是非常熟练?)。
下面先贴出一张超全的Java内部类知识图谱
上面思维导图已经大部分说明了Java内部类,但是还是想把这篇博客的大纲列出来,这样会更清晰一些。
Java内部类知识大纲
- 什么是内部类
- 内部类间接体现Java多继承?
- 四大内部类
- 成员内部类
- 静态内部类
- 局部(方法)内部类
- 匿名内部类
什么是内部类
将一个类定义在另一个类的内部,这就是内部类。内部类和普通类一样,都是类,都可以定义属性、方法 (包括构造方法,静态方法等等)。通常将内部类分为4种:成员内部类、静态内部类、局部(方法)内部类、匿名内部类。在这四种内部类之中,有的内部类可以定义静态成员,有些内部类就不能定义静态成员,再下面将会一一说明。
内部类间接体现Java多继承?
我们都知道在Java中,一个类继承另一个类,就会继承那个类(父类、基类)公有成员(属性、方法),如果外部类继承一个类,内部类也继承一个类(内部类也是类,可以继承类,或者实现接口),又因为内部类可以直接访问外部类的成员(属性、方法),所以内部类也可以访问外部类继承父类的成员,所以说内部类的出现间接体现Java多继承(虽然最多是继承两个类,外部类一个,内部类一个)。这个是我个人的见解,如果有不同的想法看法,可以评论交流一下下。
四种内部类
虽然内部类和普通的类一样,都可以继承类,实现接口,而且都可以定义成员(属性,方法),但是它们之间还是有区别的;
比如成员内部类就不能定义静态成员(静态变量,静态方法),而静态内部类就可以定义静态成员,下面将会一一介绍这四大内部类,而且都会附带完整的代码说明,只讲理论不给代码都是不贴心的。
成员内部类
我们在学面向对象的时候,应该都知道static这个关键字,被static修饰(属性、方法)就是类级别的了,也就是类成员(不依赖于对象,被该类所有对象共享),那么反过来不被static修饰就是对象成员了,所以成员内部类就是不能被static修饰的,但是可以被四大权限修饰符修饰(public、private、...)。
外部类与成员内部类
下面给出成员内部类代码,下面还会给出成员内部类总结,而这个总结就是从这个代码里浓缩出来的(因为语法错误编译器会报红)。
代码可能看起来有点长,可以复制到IDEA中慢慢细读,相信会有收获的。
/**
* 外部类内部使用成员内部类
* 1.成员内部类可以继承类,实现接口
* 2.成员内部类不能创建静态成员(静态变量,静态方法)
* 3.不能在外部类静态方法内部创建成员内部类对象
* 4.如果外部类属性与内部类属性同名时,
* 直接调用是访问内部类属性,通过外部类名.this.属性名访问的是外部类属性
* 其他类内部使用成员内部类
* 第一种方式:
* //创建外部类对象
* MemberInnerClass outer = new MemberInnerClass();
* //创建内部类对象
* MemberInnerClass.InnerClass inner = outer.new InnerClass();
* 第二种方式:
* //链式创建内部类对象
* MemberInnerClass.InnerClass innerClass = new MemberInnerClass().new InnerClass();
*/
@Data
public class MemberInnerClass {
private Integer age = 22;
private String name = "xq";
private static String country = "中国";
public void outerMethod() {
System.out.println("我是外部类的成员方法!");
}
public static void outerStaticMethod() {
System.out.println("我是外部类的静态方法!");
}
public class InnerClass {
/**
* 成员变量
*/
private Integer age = 18;
/**
* 成员内部类不允许定义静态变量
*/
// public static String name; //报错
/**
* 构造器
*/
public InnerClass() {
}
/**
* 内部类成员方法,访问外部类信息(属性、方法)
*/
public void innerCallOuter() {
//当内部类属性和外部类属性不同名时,直接调用即可
System.out.println(name);
//当内部类属性和外部类属性同名时,访问的是内部类属性
System.out.println("内部类age属性:" + age);
//当内部类属性和外部类属性同名时,可通过外部类名.this.属性名
System.out.println("外部类age属性:" + MemberInnerClass.this.age);
System.out.println("外部类静态变量:" + country);
//访问外部类的方法
outerMethod();
outerStaticMethod();
}
/**
* 成员内部类不允许定义静态方法,报错
*/
/*public static void innerStaticMethod(){}*/
}
/**
* 外部类静态方法不能创建内部类对象,
* 也就是在外部类静态方法内访问不了内部类信息
* @param args
*/
/*public static void main(String[] args) {
InnerClass innerClass = new InnerClass();
}*/
/**
* 外部类非静态方法创建内部类对象,访问内部类信息
*/
public void outerCallInner() {
InnerClass innerClass = new InnerClass();
innerClass.innerCallOuter();
}
/**
* 外部类静态方法,创建外部类对象,调用外部类成员方法(内部访问内部类信息)
*
* @param args
*/
public static void main(String[] args) {
MemberInnerClass memberInnerClass = new MemberInnerClass();
memberInnerClass.outerCallInner();
}
}
其他类使用成员内部类
public class MemberInnerClassTest {
public static void main(String[] args) {
//创建外部类对象
MemberInnerClass outer = new MemberInnerClass();
outer.outerCallInner();
System.out.println("=========================");
//创建内部类对象
MemberInnerClass.InnerClass inner = outer.new InnerClass();
inner.innerCallOuter();
System.out.println("========================");
//链式创建内部类对象
MemberInnerClass.InnerClass innerClass = new MemberInnerClass().new InnerClass();
innerClass.innerCallOuter();
}
}
成员内部类总结
- 成员内部类可以被任何的访问修饰符修饰。
- 成员内部类的内部不能定义静态成员。
- 成员内部类也是类,可以继承类,可以实现接口,方法也可以重写,重载,this和super随便使用。
- 成员内部类可以直接使用外部类的任何信息,如果属性或者方法发生冲突,调用外部类.this.属性或者方法。
- 其它类如何访问成员内部类,被public修饰的成员内部类,可以被不同包的其他类访问;其他情况和普通类一样...
静态内部类
静态内部类就是static修饰的内部类,也可以被四大权限修饰符修饰。
外部类定义以及使用静态内部类
下面代码以及注释非常清晰说明了静态内部类的特性。
/**
* 外部类&静态内部类
*/
public class StaticInnerClass {
//和内部类属性同名
private int age = 22;
private String outer = "outerClass";
private static String country = "china";
static {
System.out.println("外部类静态代码块...");
}
public void outerMethod() {
System.out.println("我是外部类的成员方法!");
}
public static void outerStaticMethod() {
System.out.println("我是外部类的静态方法!");
}
/**
* 静态内部类,需要使用static修饰
*/
public static class InnerClass {
private int age = 18;
private String inner = "innerClass";
//静态内部类可以定义静态变量
private static String country = "中国";
static {
System.out.println("内部类静态代码块...");
}
public void innerMethod() {
//静态内部类不能访问外部类非静态成员属性
// System.out.println("outer:"+outer); 报错
System.out.println("inner:" + inner);
System.out.println("静态内部类age属性:" + age);
//静态类内部不能通过这种方式访问外部类的同名属性
// System.out.println("外部类age属性:"+StaticOuterClass.this.age);
System.out.println("静态内部类static属性:" + country);
System.out.println("外部类static属性:" + cn.zwq.innerclass.StaticInnerClass.country);
//静态内部类不能调用外部类成员方法
// outerMethod(); 报错
//静态内部类可以调用外部类静态方法
outerStaticMethod();
}
/**
* 静态内部类可以定义静态方法
*/
public static void innerStaticMethod() {
// outerMethod(); 报错
outerStaticMethod();
}
public static void main(String[] args) {
//访问静态内部类静态属性
System.out.println(cn.zwq.innerclass.StaticInnerClass.InnerClass.country);
//访问静态内部类静态方法
cn.zwq.innerclass.StaticInnerClass.InnerClass.innerStaticMethod();
}
}
}
其他类使用静态内部类
创建静态内部类对象和创建成员内部类对象稍微不同,可以和上面稍微对比一下就清晰了。
public class StaticInnerClassTest {
public static void main(String[] args) {
//创建静态内部类对象,和创建成员内部类稍微不同
StaticInnerClass.InnerClass innerClass = new StaticInnerClass.InnerClass();
//访问静态内部类方法(静态、非静态)
innerClass.innerMethod();
innerClass.innerStaticMethod();
//直接调用静态内部类静态属性:外部类.静态内部类.静态属性(非私有的)
StaticInnerClass.InnerClass.innerStaticMethod();
}
}
静态内部类总结
- 静态内部类使用static修饰,可以定义非静态成员,也可以定义静态成员。
- 静态内部类中的方法(成员方法、静态方法)只能访问外部类的静态成员,不能访问外部类的非静态成员。
- 静态内部类可以被4大权限修饰符修饰,被public修饰而任意位置的其他类都可以访问,被private修饰只能被外部类内部访问。
- 静态内部类内部的静态成员,可以直接使用外部类.静态内部类.静态成员访问。
局部内部类
局部内部类是定义在方法内部的,我们可以想一下,以前定义方法的时候,有哪些限制?
- 首先呢,是变量不能使用权限修饰符修饰,而局部内部类就是方法内部定义的变量,所以局部内部类也不能使用权限修饰符修饰。
- 这里先列举一条限制,下面还会给出更加详细的总结。
/**
* 局部内部类
*/
public class LocalInnerClass {
//和局部内部类属性同名
private int age = 22;
private String outer = "outerClass";
private static String country = "china";
public void outerMethod() {
System.out.println("我是外部类的成员方法!");
}
public static void outerStaticMethod() {
System.out.println("我是外部类的静态方法!");
}
/**
* 外部类成员方法,内部定义局部内部类
*/
public void localInnerClass() {
String name = "java";
name = "javaEE";
//报错,局部内部类不能被权限修饰符修饰
/*public class InnerClass{
}*/
class InnerClass {
private String inner = "inner";
private int age = 18;
//报错,局部内部类不能定义静态成员(属性、方法)
// private static String country = "中国";
/*public static void innerStaticMethod(){
}*/
public void innerMethod() {
//报错,因为局部内部类访问方法定义的变量,该变量必须是final修饰的
// System.out.println(name);报错
System.out.println("局部内部类inner属性:" + inner);
//访问外部类信息
System.out.println("外部类outer属性:"+outer);
System.out.println("局部内部类age属性:"+age);
System.out.println("外部类age属性:"+LocalInnerClass.this.age);
System.out.println("外部类静态属性country:"+country);
outerMethod();
outerStaticMethod();
}
}
/*
局部内部类只能在声明的方法内部使用
*/
InnerClass innerClass = new InnerClass();
innerClass.innerMethod();
System.out.println(innerClass.age);
System.out.println(innerClass.inner);
}
}
局部内部类总结
- 局部内部类不能被权限修饰符修饰。
- 局部内部类只能在方法内部使用。
- 局部内部类不能定义静态成员。
- 局部内部类可以直接访问方法内部的局部变量和方法参数。
- 局部内部类可以访问外部类的静态成员、非静态成员。
局部内部类注意点(重点)
如果局部内部类访问方法内部的局部变量、方法形参,那么就要求这些局部变量、方法形参被final修饰,否则会报错。
下图很好的说明了这个问题:
匿名内部类
- 首先匿名内部类也是内部类的一种,只不过它没名字。
- 匿名内部类最常用的使用场景就是快速创建抽象类或接口的实例。
- 如果某个类判定只使用一次,那么就不要通过new关键字创建那个类的对象,而是使用匿名内部类的方式。
- 匿名内部类的格式:
new 实现接口() | 父类构造器(实参列表){ //匿名内部类类体部分 };
5.接下来使用匿名内部类创建Runnable接口的实例,创建Thread类的实例。
public static void main(String[] args) {
//使用匿名内部类创建接口实例
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
//使用匿名内部类创建Thread类实例
Thread thread = new Thread(runnable,"小小线程"){
};
}
好了,到这里Java内部类已经说完了,相信你看了这篇之后,之后面试被问到,或者笔试题考到Java内部类题目,都可以轻松解决了。
如果感觉OK的话,可以关注或者点赞博主我一下下,感谢!