1. 局部内部类
- 局部内部类是定义在外部类的局部位置,通常在方法中并且有类名
- 可以直接访问外部类的所有成员,包含私有的
- 不能添加访问修饰符,但可以用final修饰
- 作用域:仅仅在定义它的方法或者代码块中
- 外部类访问局部内部类的方式:创建对象 再访问(必须在作用域内)
- 外部其他类不能直接访问局部内部类(局部内部类地位是一个局部变量)
- 如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想要访问外部类的成员,使用 外部类名.this.成员 去访问
public class LocalInnerClass {
public static void main(String[] args) {
Outer02 outer02 = new Outer02();
outer02.m1();
}
}
class Outer02{
private int n1=100;
private void m2(){//私有方法
System.out.println("Outer02 m2()");
}
public void m1(){ //公有方法
//1. 局部内部类是定义在外部类的局部位置,通常在方法
//2. 可以直接访问外部类的所有成员,包含私有的
//3. 不能添加访问修饰符,但可以用final修饰
//4. 作用域:仅仅在定义它的方法或者代码块中
final class Inner02{//局部内部类(本质还是一个类,可以看作一个局部变量)
private int n1=800;//6.如果外部类和局部内部类的成员重名时,默认遵循就近原则
//如果想要访问外部类的成员,使用 外部类名.this.成员 去访问
public void f1(){
System.out.println("n1="+n1+"外部类的n1="+Outer02.this.n1);
m2();
}
}
//5. 外部类如何使用局部内部类 :创建Inner02方法,然后调用方法即可
Inner02 inner02 = new Inner02();
inner02.f1();
}
}
2.成员内部类
- 成员内部类是定义在外部类的成员位置,没有static修饰,可以直接访问外部类的所有成员,包含私有的
- 成员内部类可以添加访问修饰符(public,protected,默认,private)因为它本身就是一个成员
- 作用域:和外部类其他成员一样,为整个类整体
- 成员内部类访问外部类成员的方法:直接调用
- 外部类访问成员内部类的方法: 创建对象再访问
- 外部其他类访问成员内部类有两种方法
第一种:先创建一个外部类对象,然后再new一个内部类实例,相当于把内部类当作一个成员
第二种:在外部类中编写一个方法,可以返回Inner对象,然后用外部类的引用调用该方法即可
代码实现如下:
public class Inner01 { //这个相当于外部其他类
public static void main(String[] args) {
//外部其他类访问成员内部类的方式1:
Outer outer = new Outer();//先创建一个外部类对象
//然后再new一个内部类实例,相当于把内部类当作一个成员,相当于把new Inner()当作outer的成员
//固定语法
Outer.Inner inner = outer.new Inner();
inner.hi();
//外部其他类访问成员内部类的方式2:
//在外部类中编写一个方法,可以返回Inner对象,然后用外部类的引用调用该方法即可
Outer.Inner innerInstance = outer.getInnerInstance();
inner.hi();
}
}
class Outer{ //外部类
private int n=10;
class Inner{ //成员内部类
public void hi(){ //内部类中的方法
System.out.println("hi...");
}
}
public void t1(){ //外部类使用成员内部类要先创建成员内部类的对象然后使用相关属性或方法
Inner inner = new Inner();
inner.hi();
}
//这是一个方法,返回成员内部类的实例,返回类型是成员内部类,用于测试方式2
public Inner getInnerInstance(){
return new Inner();
}
}
- 如果外部类和成员内部类重名时,内部类访问的话默认遵循就近原则,如果想访问外部类的成员,就可以用(外部类名.this.成员)去访问
3. 静态内部类
不细说了,根成员内部类对比吧
public class StaticInnerClass { ///外部其他类
public static void main(String[] args) {
Outer10 outer10 = new Outer10();
Outer10.Inner10 inner10 = new Outer10.Inner10();//第一种访问方式,通过外部类类名直接访问静态内部类(满足访问权限的前提)
inner10.say();
//第二种访问方式 编写一个方法返回静态内部类的对象实例
Outer10.Inner10 inner10instance = outer10.getInner10instance();
System.out.println("*********");
inner10instance.say();
}
}
class Outer10 {//外部类
private int n1 = 10;
private static String name = "张三";
//1.Inner10这是一个静态内部类,放在外部类的成员位置,使用static修饰
//2.可以直接访问外部类的所有静态成员,包含私有的,但是不能直接访问非静态成员
//3.可以添加任意访问修饰符(public ,protected,默认,private) 因为他的地位就是成员
//4.作用域同其他成员,为整个类体
//5.类访问静态内部类先创建对象再访问
//6.其他外部类访问静态内部类同样两种方法,注意对比方法内部类
//7.外部类和静态内部类重名时静态内部类访问时遵循就近原则,如果访问外部类的成员,可以用(外部类名.成员名)去访问,注意没有this
static class Inner10 {
public void say() {
// System.out.println(n1);//报错,不能访问非静态类属性
System.out.println(name);//正确,因为name也是一个静态的
}
}
public Inner10 getInner10instance(){ //编写一个方法返回静态内部类的对象实例
return new Inner10();
}
}
4. 匿名内部类(四个内部类中最重要的)
为何要引入匿名内部类?
有时候我们的某个类只是用一次,此时我们可以用匿名内部类简化开发
下面是匿名内部类的使用
匿名内部类也相当于一个对象
1.基于接口的匿名内部类
这是一个A接口
interface A{ //接口
public void cry();
}
传统想要使用这个接口的话,我们需要写一个类来实现这个接口,然后在主方法中调用这个接口,然后实现接口中的cry方法,但是如果这个类只是使用一次的话再创建这个类就显得代码冗余,这时候就可以用基于接口的内部类如下
A tiger=new A(){ //基于接口的匿名内部类
@Override
public void cry() {
System.out.println("老虎叫");
}
};
tiger.cry(); //直接调用方法
那么这个代码如何解释呢?
1.tiger的编译类型是 A
2. tiger的运行类型是 匿名内部类 系统分配的 外部类名+$1
那么匿名内部类的底层是什么呢?
如下,不过这些都是底层默认的,我们并不能看见,底层其实有一个类实现了接口,用一次就没有了
3.jdk底层在创建匿名内部类 外部类名$1,立马就创建了 外部类名$1的实例,并把地址返回给了tiger
4.匿名内部类使用一次就没有了,但是tiger可以多次调用
class 外部类名称$1 implements A{ //是指A所在的那个外部类,这个类名是系统自动分配的
@Override
public void cry() {
System.out.println("老虎叫");
}
}
2.基于类的匿名内部类
这是一个类
class Father{
public Father(String name) {
}
public void test(){ //方法
}
同理,我们想在另一个类中基于类使用匿名内部类,就可以这样使用
//演示基于类的匿名内部类
Father father=new Father("jack"){
@Override
public void test() {
System.out.println("匿名内部类重写了test方法");
}
};
1.同基于接口的编译类型运行类型一样
2.底层也会生成匿名内部类 同基于接口的匿名内部类