解析JavaSe的内部类

 更新时间:2022年03月02日 16:09:21   作者:小小茶花女  
这篇文章主要为大家详细介绍了JavaSe的内部类,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助

内部类

1. 内部类简介

(1) 内部类提供了更好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。

(2) 内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,同一个类的成员之间可以互相访问。但外部类不能访问内部类的实现细节,例如内部类的成员变量。

(3) 匿名内部类适合用于创建那些仅需要一次使用的类。

(4) 在java中内部类主要分为成员内部类(非静态内部类、静态内部类)、匿名内部类、局部内部类。

2. 非静态内部类

成员内部类是一种与Field、方法、构造器和初始化块相似的类成员,成员内部类分为两种:静态内部类和非静态内部类,使用static修饰的成员内部类是静态内部类,没有使用static修饰的成员内部类是非静态内部类。

  • 因为内部类作为其外部类的成员,所以可以使用任意访问控制符如private、protected和public等修饰;
  • 非静态内部类不能有静态方法、静态属性、静态初始化块;
  • 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员;
  • 外部类的静态方法、静态代码块中不能直接创建非静态内部类实例,访问内部类成员;
  • 非静态内部类的对象必须寄存在外部类的对象里,因此创建非静态内部类对象之前,必须先创建其外部类对象;

当在非静态内部类的方法内访问某个变量时,系统优先在该方法内查找是否存在该名字的局部变量,如果存在就使用该变量;如果不存在,则到该方法所在的内部类中查找是否存在该名字的成员变量,如果存在则使用该成员变量;如果不存在,则到该内部类所在的外部类中查找是否存在该名字的成员变量,如果存在则使用该成员变量;如果依然不存在,系统将出现编译错误:提示找不到该变量。

(1) 非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员

public class OuterClass {
    private int a;
    public void test(){
        // 编译报错,因为外部类不能直接访问非静态内部类成员
        System.out.println(b);
        // 如需访问内部类的实例Field,需显式创建内部类对象
        InnerClass inner = new InnerClass();
        System.out.println(inner.b);
    }
    // 定义非静态内部类,使用private修饰符
    @Data
    private class InnerClass{
        private int b;
        public void info(){
            // 在非静态内部类里可以直接访问外部类的private成员
            System.out.println(a);
        }
    }
}

(2) 非静态内部类不能有静态方法、静态属性、静态初始化块

public class OuterClass {
    // 外部类Field
    private int a;
    // 定义非静态内部类,使用private修饰符
    @Data
    private class InnerClass{
        // 内部类Field
        private int b;
        private int c;
        // 编译报错,非静态内部类里面不能有静态属性
        private static int d;
        // 编译报错,非静态内部类里面不能有静态代码块
        static {
            System.out.println("非静态内部类里面不能有静态代码块");
        }
        // 编译报错,非静态内部类里面不能有静态方法
        public static void show(){
            System.out.println("非静态内部类里面不能有静态方法");
        }
    }
}

(3) 外部类的静态方法、静态代码块中不能直接创建非静态内部类实例,访问内部类成员

public class OuterClass {
    private int a;
    public static void test(){
        // 编译报错,外部类的静态方法中无法创建内部类实例
        InnerClass innerClass = new InnerClass();
    }
    static{
        // 编译报错,外部类的静态方法中无法创建内部类实例
        InnerClass innerClass = new InnerClass();
    }
    // 定义非静态内部类
    @Data
    private class InnerClass{
        private int b;
    }
}

在外部类的普通方法和静态方法中访问内部类成员

public class OuterClass {
    private int a;
    // 定义非静态内部类,使用private修饰符
    @Data
    private class InnerClass{
        private int b;
        public void info(){
            System.out.println("内部类的方法info()");
        }
    }
    // 外部类的代码块
    {
        InnerClass innerClass = new InnerClass();
        innerClass.info();
    }
    // 外部类的静态代码块
    static {
        OuterClass.InnerClass inner = new OuterClass().new InnerClass();
        inner.info();
    }
    // 外部类的普通方法
    public void test(){
        // 在外部类里使用非静态内部类时,与平时使用普通类并没有太大的区别
        InnerClass inner = new InnerClass();
        // 访问内部类的Filed
        System.out.println(inner.b);
        // 访问内部类的方法
        inner.info();
    }
    //  外部类的静态方法
    public static void test1(){
        // 外部类的静态方法、静态代码块中不能直接创建非静态内部类实例
        OuterClass.InnerClass inner = new OuterClass().new InnerClass();
        // 访问内部类的Filed
        System.out.println(inner.b);
        // 访问内部类的方法
        inner.info();
    }
    // 测试
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        outerClass.test();
    }
}

3. 静态内部类

如果使用static来修饰一个内部类,则这个内部类就属于外部类本身,而不属于外部类的某个对象。static关键字的作用是把类的成员变成类相关,而不是实例相关,即static修饰的成员属于整个类,而不属于单个对象。

  • 静态内部类可以包含静态成员,也可以包含非静态成员。
  • 静态内部类不能访问外部类的实例成员,只能访问外部类的类成员;
  • 外部类不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。

(1) 静态内部类不能访问外部类的实例成员,只能访问外部类的类成员

public class OuterClass {
    private int a;
    private static int b;
    public void test(){
        System.out.println(a);
    }
    @Data
    private static class InnerClass{
        private int c;
        // 静态内部类中可以包括静态成员
        private static int d;
        public void info(){
            // 编译报错,静态内部类不能访问外部类的实例成员
            System.out.println(a);
        }
        public static void show(){
            // 静态内部类可以访问外部类的静态成员
            System.out.println(b);
        }
    }
}

(2) 外部类不能直接访问静态内部类的成员,但可以使用静态内部类的类名作为调用者来访问静态内部类的类成员,也可以使用静态内部类对象作为调用者来访问静态内部类的实例成员。

public class OuterClass {
    private int a;
    private static int b;
    public void test(){
        // 外部类不能直接访问静态内部类的成员
        // 可以使用静态内部类对象作为调用者来访问静态内部类的实例成员
        InnerClass innerClass = new InnerClass();
        innerClass.show();
        // 可以使用静态内部类的类名作为调用者来访问静态内部类的类成员
        InnerClass.show();
    }
    public static void main(String[] args) {
        OuterClass outerClass = new OuterClass();
        outerClass.test();
    }
    @Data
    private static class InnerClass{
        private int c;
        private static int d;
        public static void show(){
            System.out.println(b);
        }
    }
}

4. 匿名内部类

匿名内部类适合创建那种只需要一次使用的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失,匿名内部类不能重复使用。

  • 匿名内部类必须继承一个父类,或实现一个接口,但最多只能继承一个父类,或实现一个接口;
  • 匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。因此不允许将匿名内部类定义成抽象类;
  • 匿名内部类不能定义构造器,因为匿名内部类没有类名,所以无法定义构造器,但匿名内部类可以定义实例初始化块,通过实例初始化块来完成构造器需要完成的事情;
public interface Product {
     public int getPrice();
     public String getName();
}
public class Test {
    public void test(Product product){
        System.out.println("name:"+product.getName() +"-------"+"name:"+product.getPrice());
    }
    public static void main(String[] args) {
        Test test = new Test();
        test.test(new Product() {
            @Override
            public int getPrice() {
                return 12;
            }
            @Override
            public String getName() {
                return "苹果";
            }
        });
    }
}

Test类定义了一个test方法,该方法需要一个Product对象作为参数,但Product只是一个接口,无法直接创建对象,因此此处考虑创建一个Product接口实现类的对象传入该方法——如果这个Product接口实现类需要重复使用,则应该将该实现类定义成一个独立类;如果这个Product接口实现类只需一次使用,则可采用上面程序中的方式,定义一个匿名内部类。

总结

本篇文章就到这里了,希望能够给你带来帮助,也希望您能够多多关注脚本之家的更多内容!   

相关文章

  • Eclipse下基于Java的OpenCV开发环境配置教程

    Eclipse下基于Java的OpenCV开发环境配置教程

    这篇文章主要为大家详细介绍了Eclipse下基于Java的OpenCV开发环境配置教程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • java必学必会之equals方法

    java必学必会之equals方法

    java必学必会之equals方法,equals方法是 java.lang.Object 类的方法,想要了解更多关于equals方法的朋友,可以参考下文
    2015-12-12
  • Spring入门到精通之注解开发详解

    Spring入门到精通之注解开发详解

    Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势。本文将通过示例为大家详细讲讲Spring如何实现注解开发,感兴趣的可以学习一下
    2022-07-07
  • Java8中的默认方法(面试者必看)

    Java8中的默认方法(面试者必看)

    这篇文章主要介绍了Java8中的默认方法(面试者必看),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-11-11
  • mybatis-plus中的Enum用法实例

    mybatis-plus中的Enum用法实例

    本文主要介绍了mybatis-plus中的Enum用法实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-01-01
  • Java线程中的notifyAll唤醒操作(推荐)

    Java线程中的notifyAll唤醒操作(推荐)

    这篇文章主要介绍了Java线程中的notifyAll唤醒操作,非常不错,具有参考借鉴价值,需要的朋友可以参考下
    2017-03-03
  • Java8新特性之再见Permgen_动力节点Java学院整理

    Java8新特性之再见Permgen_动力节点Java学院整理

    这篇文章主要介绍了Java8新特性之再见Permgen的相关知识,非常不错,具有参考借鉴价值,需要的的朋友参考下吧
    2017-06-06
  • Mybatis-Plus实现SQL拦截器的示例

    Mybatis-Plus实现SQL拦截器的示例

    这篇文章主要介绍了Mybatis-Plus实现一个SQL拦截器,通过使用SQL拦截器,开发人员可以在执行SQL语句之前或之后对其进行修改或记录,从而更好地控制和优化数据库操作,对Mybatis-Plus SQL拦截器相关知识感兴趣的朋友一起看看吧
    2023-05-05
  • JAVA8 List<List<Integer>> list中再装一个list转成一个list操作

    JAVA8 List<List<Integer>> list中再装一个list转成一个list操

    这篇文章主要介绍了JAVA8 List<List<Integer>> list中再装一个list转成一个list操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-08-08
  • java中初始化MediaRecorder的实现方法

    java中初始化MediaRecorder的实现方法

    这篇文章主要介绍了java中初始化MediaRecorder的实现方法的相关资料,希望通过本文能帮助到大家,让大家实现这样的功能,需要的朋友可以参考下
    2017-10-10

最新评论