Java中的四个不同的内部类

最近在学Java,在研究内部类的时候,发现有的文章或者视频没有很好的说出内部类之间的区别,所以下面内容我结合了我从哔哩哔哩看到的内容,来说说内部类(如果有不对的地方请留言评论)

内部类的分类

1、定义在外部局部位置上:局部内部类(有类名)、匿名内部类(没有类名)
2、定义在外部类的成员位置上:成员内部类(没有static修饰)、静态内部类(没有static修饰)

例如:
/*
内部类演示
*/
package innerclass;
//外部其他类
public class innerClass {
    public static void main(String[] args) {
    
    }
}
//外部类
class Outer{  
    // 内部类
    class Inner{  
    
    }
}

一、局部内部类

1、局部内部类是定义在外部类的局部位置,通常在方法
2、可以直接访问外部类的所有成员,包含私有的
3、不能添加访问修饰符,但是可以使用final修饰
4、作用域:仅仅在定义它的方法或代码块
5、局部类可以直接访问外部的成员
6、如果外部类和局部内部类的成员重名时,默认遵循就近原则,如果想访问外部类成员,使用“外部类名.this”

例如
package innerclass;

/*
演示局部内部类
 */
//外部其他类
public class LocalInnerClass {
    public static void main(String[] args) {
        Outer outer=new Outer();
        outer.m2();
    }
}
//外部类
class Outer{
    private int n1=100;
    private void m1(){
        System.out.println("Outer");
    }

    public void m2(){
    //局部内部类
        class Inner02{
            private int n1=800;
            public void f1(){
            // Outer02.this本质就是外部类的对象,即哪个对象调用了m1,Outer02.this就是哪个对象
            // 打印局部内部类Inner02的n1变量和外部类Outer的n1变量
                System.out.println("n1="+n1+" 外部类的 n1="+Outer.this.n1);
                // 调用外部类Outer的私有方法m1
                m1();
            }
        }
        // 定义一个Inner03类,继承自Inner02类
        class Inner03 extends Inner02{

        }
        // 创建Inner02类的一个实例对象inner02
        // 调用inner02实例的f1方法
        Inner02 inner02=new Inner02();
        inner02.f1();
    }
}
输出结果
n1=800 外部类的 n1=100
Outer02

二、匿名内部类

1、基于类的匿名内部类

  • father的编译类型Father
  • father的运行类型Outer04$2,同时返回类匿名内部类Outer04$2的对象
    底层实现:
      class Outer04$2 extends Father{
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        }

2、基于接口的匿名内部类

  • 需求:想使用IA接口,并创建对象
  • 传统方式,是写一个类,实现该接口,并创建对象
  • 现在需求是Tiger就用一次,后面不再使用
  • 可以使用匿名内部类简化开发
  • tiger的编译类型是“IA”
  • tiger的运行类型是匿名内部类:XXXX名字是存在的,为: “Outer04$1”
  • JDK底层在创建匿名内部类 Outer04,立即马上创建类Outer04$1实例,并把地址返回给tiger
  • 匿名内部类使用一次就不能再使用类,但是实例化的对象没关系
    底层实现:
   class Outer04$1 implements IA{
       @Override
       public void cry() {
           System.out.println("老虎叫~~~");
   }
例如
/*
演示匿名内部类
 */
package innerclass;
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer04 outer04=new Outer04();
        outer04.method();
    }
}
//外部类
class Outer04{
    private int n1=10;  
    public void method(){  
        // IA tiger=new Tiger();
        // tiger.cry();
        
        // 基于接口的匿名内部类
        IA tiger =new IA() {
            @Override
            public void cry() {
                System.out.println("老虎叫~~~");
            }
        };
        System.out.println("tiger的运行类型="+tiger.getClass());
        tiger.cry();
        
		//基于类的匿名内部类
        Father father =new Father("jack"){
            @Override
            public void test() {
                System.out.println("匿名内部类重写了test方法");
            }
        };
        father.test();
        System.out.println("father对象的运行类型="+father.getClass());
        
        //基于抽象类的匿名内部类
        Animal animal=new Animal() {
            @Override
            void eat() {
                System.out.println("小狗吃骨头");
            }
        };
        animal.eat();
    }
}
interface IA{
    public void cry();

}
//传统对接口的重写方式
//class Tiger implements IA{
//    @Override
//    public void cry() {
//        System.out.println("老虎叫~~~");
//    }
//}

class Father{
	//构造器
    public Father(String name){
        System.out.println("name:"+name);
    }
    public void test(){
    }
}
//抽象类
abstract class Animal{ 
    abstract void eat();
}
输出结果
tiger的运行类型=class innerclass.Outer04$1
老虎叫~~~
name:jack
匿名内部类重写了test方法
father对象的运行类型=class innerclass.Outer04$2
小狗吃骨头

三、成员内部类

  • 注意:成员内部类,是定义在外部内的成员位置上
  • 可以直接访问外部类的所有成员,包括私有的
  • 可以添加任意访问修饰符(public、protected、默认、private),因为它的本身就是一个成员
  • 如果成员内部类的成员和外部类的成员重名,会遵守就近原则
  • 可以通过,外部类.this.属性 来访问外部类的成员
  • 外部其他类,使用成员内部类的2种方式,1、第一种方式:outer08.new Inner08(); 相当于把 new Inner08()当作是Outer08一个成员;2、第二种方式:在外部类中,编写一个方法,可以返回Inner08对象
例如
package innerclass;

public class MemberInnerClass01 {
    public static void main(String[] args) {
        Outer08 outer08=new Outer08();
        outer08.t1();
        System.out.println();
        //外部其他类,使用成员内部类的2种方式
        //第一种方式
        //outer08.new Inner08(); 相当于把 new Inner08()当作是Outer08一个成员
        //这就是一个语法
        Outer08.Inner08 in08=outer08.new Inner08();
        in08.say();
        System.out.println();
        //第二种方式
        //在外部类中,编写一个方法,可以返回Inner08对象
        Outer08.Inner08 inner08Instance = outer08.getInner08Instance();
        inner08Instance.say();
    }
}

class Outer08{
    private int n1=10;
    public String name="李四";
    private void hi(){
        System.out.println("hi()方法~~~");
    }
	//成员内部类
    class Inner08{ 
        private double num=10.1;
        private int n1=66;
        public void say(){
            System.out.println("内部 的n1="+n1+"   Outer08 的name="+name+"  外部 的n1="+Outer08.this.n1);
            hi();
        }
    }
    public Inner08 getInner08Instance(){
        return new Inner08();
    }
    public void t1(){
        //使用成员内部类
        //创建成员内部类的对象,然后调用的方法
        Inner08 inner08=new Inner08();
        inner08.say();
        System.out.println("inner08: num="+inner08.num);
    }
}
输出结果
内部 的n1=66   Outer08 的name=李四  外部 的n1=10
hi()方法~~~
inner08: num=10.1

内部 的n1=66   Outer08 的name=李四  外部 的n1=10
hi()方法~~~

内部 的n1=66   Outer08 的name=李四  外部 的n1=10
hi()方法~~~

四、静态内部类

  • 放在外部类的成员位置
  • 使用static修饰
  • 可以直接访问外部类的所有静态成员,包含私有的,但不能直接访问- 非可以直接添加任意访问修饰符(public、protected、默认、private),因为它的地位就是一个成员
  • 作用域:同其他的成员,整个类体
  • 如果外部类和静态内部类的成员重名时,静态内部类访问默认,遵循就近原则,如果想访问外部类的成员,则可以使用(外部类.成员)
  • 外部其他类访问静态内部类的方式。方式一:因为静态内部类是可以通过类名直接访问(前提是满足访问权限);方式二:编写一个方法可以返回静态内部类的对象示例
例如
package innerclass;

public class StaticInnerClass01 {
    public static void main(String[] args) {
        Outer10 outer10 = new Outer10();
        outer10.m1();

        //外部其他类访问静态内部类的方式
        //方式一:
        //因为静态内部类是可以通过类名直接访问(前提是满足访问权限)
        Outer10.Inner10 inner10 = new Outer10.Inner10();
        inner10.say();
        //方式二
        //编写一个方法可以返回静态内部类的对象示例
        Outer10.Inner10 inner101=outer10.getinner10();
        inner101.say();
        Outer10.Inner10 inner102=outer10.getinner101();
        inner102.say();

    }
}
//外部类
class Outer10{ 
    private int n1=10;
    private static String name="Tom";
    // 静态内部类
    static class Inner10{
        private static String name="Jack";
        public void say(){
            System.out.println("内部 name:"+name+"   外部 name:"+Outer10.name);
        }
    }
	//外部类访问静态内部类方式:创建对象,再访问
    public void m1(){ 
        Inner10 inner10 =new Inner10();
        inner10.say();
    }
    public Inner10 getinner10(){
        return new Inner10();
    }

    public static Inner10 getinner101(){
        return new Inner10();
    }
}
输出结果
内部 name:Jack   外部 name:Tom
内部 name:Jack   外部 name:Tom
内部 name:Jack   外部 name:Tom
内部 name:Jack   外部 name:Tom
  • 25
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值