表格总结
目录
静态内部类 | 成员内部类 | 局部内部类 | 匿名内部类 | ||
1 | 是否可以用private、proteced、public或不写来修饰类名 | 是 | 是 | 否 | |
2 | 是否能实现接口 | 是 | 是 | 是 | 是 |
3 | 是否能有静态成员 | 是 | 是 | 是 | 是 |
4 | 是否能有非静态成员 | 是 | 是 | 是 | 是 |
5 | 能否直接访问外部类的静态成员 | 是 | 是 | 是 | 是 |
6 | 能否直接访问外部类的非静态成员(实例成员) | 都不能直接访问,必须创建外部类对象才能访问 | |||
7 | 能否直接访问外部类的私有静态变量 | 是 | 是 | 是 | 是 |
8 | 创建对象的方式 | 方式一A.B bb=new A.B(); 方式二B b= new B(); | C.D d=new C().new D(); | F f=new F();普通方法创建 | 自动创建 |
9 | 外部类能否调用内部类的静态成员 | 是 | 是 | 否 | 否 |
10 | 外部类怎样调用内部类的非静态成员 | 创建对象 | 创建对象 | 无法调用 | 无法调用 |
11 | 外部类怎样调用内部类私有静态成员 | 直接调用 | 直接调用 | 无法调用 | 无法调用 |
12 | 是否能为final类 | 是 | 是 | 是 | 一定是final类 |
13 | 是否能为abstract类 | 是 | 是 | 是 | 否 |
理解表格前的一些理解
静态内部类,用static修饰,我们知道static修饰的变量是全局变量,static修饰的类也是一个“全局”的类,也就是说,静态内部类是不依赖于外部类的,完全可以把它看成一个独立的类,所以,静态内部类可以看成外部类的一个静态成员或者看成一个独立的类!!!
成员内部类,理解它的关键是把他看成外部类的一个非静态成员,也就是实例成员
局部内部类和匿名内部类都可以当成局部变量来理解
表格里的理解
第1行,局部内部类的类名不能被private、proteced、public或不写来修饰,在方法内部定义的内部类,只能在方法的内部使用,也就是定义该类的区域内使用。这样的结果就是,在方法之外,并不能访问到该内部类,也即不需要private等访问控制符修饰,因为他本身就是在内部使用的,外部不能访问。
第3行,这个很重要,在JDK16之前,非静态内部类不能有静态成员的,原因是运行时静态成员要先加载,但是他所在的类不加载,就会产生冲突。但是!!!JDK16之后,所有内部类都可以定义静态成员了,具体我也不知道Java怎么处理的,但就是可以了,一定要记牢。
第七行,只是把两个类写一起可以,main方法里,private类型的变量只能通过get、set方法修改调用,所以就别想着在main里直接访问静态私有成员了。
第9行,静态内部类和成员内部类的静态成员都可以被外部类调用,也进一步印证了第3行,另外,局部内部类和匿名内部类只能被所在的内部使用,自然不会被外部类访问,外部类中也无法创建内部类的对象
第11行,静态内部类和成员内部类看作是外部类的一个成员,所以这两个类的成员自然也是外部类的成员,包括私有变量,你都是我的,你的心也是我的
还有之前说匿名内部类只能访问final型的局部变量,这句话好像在JDK8之后就不对了,我用的JDK17可以访问非final变量,深层次的原因不清楚,总之现在匿名内部类访问局部变量,局部变量不必非要加final。 另外我发现匿名内部类里面定义静态成员时候,静态方法默认是final类型的,可能因为匿名类是final类吧,但定义的静态变量不默认是final。
代码
静态内部类
//静态内部类
class A {
//创建外部类静态成员和非静态成员
static int aa = 1;
int bb = 1;
//创建外部类静态私有成员
static private int ee=11;
//外部类调用内部类静态成员
int cc=B.a;
//外部类直接调用内部类的私有成员
int dd=B.c;
//创建静态内部类
public static class B {
//内部类静态成员
static int a = 1;
static void run1() {
}
//内部类非静态成员
int b;
void b() {
}
//内部类私有静态成员
private static int c = 2;
private static void c() {
}
//直接访问外部类的静态成员
int temp=A.aa;
//int temp1=A.bb;不能直接访问外部类的非静态成员\
//直接访问外部类的静态私有成员
int e=A.ee;
}
}
成员内部类
//成员内部类
class C {
//创建外部类静态成员和非静态成员
static int aa = 1;
int bb = 1;
//创建外部类静态私有成员
static private int ee=11;
//外部类调用内部类静态成员
int cc= C.D.a;
//外部类直接调用内部类的私有成员
int dd= D.c;
//创建成员内部类
class D {
//内部类非静态成员
int b;
void b() {
}
//内部类静态成员
static int a = 1;
static void run1() {
}
//内部类私有成员
private static int c = 1;
private static void c() {
}
//直接访问外部类的静态成员
int temp=C.aa;
//int temp1=C.bb;// 不能直接访问外部类的非静态成员
//直接访问外部类的静态私有成员
int e=C.ee;
}
}
局部内部类
//局部内部类
class E {
//创建外部类静态成员和非静态成员
static int aa = 1;
int bb = 1;
//创建外部类静态私有成员
static private int ee=11;
//外部类调用局部内部类静态成员,不可以!
//int cc=E.F.a;
void a() {
//创建局部内部类
// public/protected/private class F implements Dog { public/protected/private都报错
class F {
//内部类非静态成员
int b;
void b() {
}
//内部类静态成员
static int a = 1;
static void run1() {
}
//直接访问外部类的静态成员
int temp=E.aa;
//int temp1=E.bb;// 不能直接访问外部类的非静态成员
//只能在类中调用内部类的静态成员,而且要写在类后
int aa=F.a;
F ff=new F();
//直接访问外部类的静态私有成员
int e=E.ee;
}
}
}
匿名内部类
//匿名内部类
class Test {
//外部类调用内部类静态成员,不可以!
//int cc= d.a;
//创建外部类静态成员和非静态成员
static int aa = 1;
int bb = 1;
//创建外部类静态私有成员
static private int eee=11;
//创建匿名内部类
void s(){
class aaa{
static int a=1;
}
}
//继承接口
Dog d = new Dog() {
@Override
public void run() {
}
//内部类非静态成员
int b;
void b() {
}
//内部类静态成员
final static void A (){
}
final static int a = 1;
//内部类私有成员
private int c = 1;
private void c() {
}
//创建对象访问外部类的实例成员
Test e11=new Test();
int aaaaaaa=e11.bb;
//直接访问外部类的静态成员
int aa=Test.aa;
//直接访问外部类的静态私有成员
int e=Test.eee;
};
}
不重要的,别看
一、静态内部类
理解核心:看成外部类的静态成员,也可看成一个独立的类!!!
1.特点、使用与普通类是一样的,类有的成分它都有,只是位置在别人里面而已,静态内部类不依赖于外部类而存在。
2.可以直接访问外部类的静态成员,不能直接访问外部类的实例成员。
因为在java运行时直接就给静态成员分配空间了,只要访问权限许可,都可以直接访问,但是实例成员必须依赖对象存在,所以没有创建对象就不能直接访问外部类的实例成员
拓展:其余内部类可以访问所有的外部类成员变量及方法,其他内部类可以访问外部类是因为持有了外部类的引用,内部类对象依赖外部类对象存在,创建内部类对象之前,必须先创建外部类对象。反过来,外部类不能直接使用内部类的成员变量和成员方法,必须要先创建内部类的对象再通过内部类对象访问内部类方法。
3.注意:开发中实际上用的还是比较少。
二、成员内部类
成员内部类,顾名思义,是外部类的一个成员,依赖外部类的对象而存在,所以创建内部类对象必须通过外部类创建,也就是要new两层
权限修饰符四种都能用
非静态内部类不能有静态成员(包括静态成员变量和静态成员方法),因为静态成员在类加载的时候就会存在于内存中,如果内部类不是静态的,而成员又是静态的就会发生冲突。但是!从JDK16之后,成员内部类可以定义静态成员了!这一点一定要特别注意!!!请看下面代码
//创建外部类
public class Outer {
//创建内部类
public class inner {
//定义静态成员a
public static int a=1;
}
//跑一下,看能不能运行
public static void main(String[] args) {
//创建内部类对象in
Outer.inner in=new Outer().new inner();
System.out.println(in.a);
}
}
输出结果为1,这一点一定要注意,面试能回答上这一点就无敌了!
另外要注意,在成员内部类中访问所在外部类对象,格式:外部类名.this
创建对象要点
class A{
public static class B{
void speak(){
System.out.println("!!!!!");
}
}
}
class C{
public static void main(String[] args) {
// A.B b=new A().new B();//B不是静态的,只能先创建一个A对象,在创建一个B对象
A.B b=new A.B();//有static的情况下,直接创建A,然后.B
}
}
三、局部内部类(鸡肋语法,了解即可)
顾名思义,定义在局部,和局部变量可以放一起理解,局部内部类放在方法、代码块、构造器等执行体中,局部内部类前不能被修饰符public、private和static修饰,它作用的范围是定义他的代码块,局部内部类可以访问包含他的内部类的局部常量,但这个常量必须用final修饰。这些东西不去问为什么了,这种鸡肋的语法开发中几乎不用。
四、匿名内部类(重点)
其本质是一个没有名字的局部内部类,定义在方法、代码块等中,他的作用是为了方便创建子类对象,最终简化代码。
特点总结:
1.匿名内部类是一个没有名字的内部类
2.匿名内部类写出来就会产生一个匿名内部类的对象
3.匿名内部类的对象类型相当于是当前new的那个类型的子类类型
4.匿名内部类是final类