java内部类与匿名内部类

引入

创建内部类

  • 在一些项目需求中,会出现一个类中的属性还有其他属性的情况,比如:
    • 对于餐馆类,通常会有的属性有餐馆的名字,餐馆的地址,餐馆的菜单,但对于菜单来说,其内部又有菜名,价格,辣度等属性
    • 面对怎样的需求,就可以建立一个Restaurant餐馆类,在Restaurant类中再创建一个MenuItem内部类,如下方代码所示:
java 复制代码
package com.inside;
public class Restaurant {  
    private  String name;  
    private  String address; //地址  
  
    public Restaurant() {}  
    
    public void CreateMenuItem(String name,double price){  
        MenuItem menuItem = new MenuItem(name,price);  
    }  
  
    //菜单里面包含的属性也很多,直接在Restaurant中创建单个属性似乎不能满足我们的需求,因此在类Restaurant中创建一个成员内部类MenuItem  
    //public class MenuItem{
    //要在其他类中使用内部类,内部类要加上修饰符static,这样这个内部类在内存空间中才真正属于外部类,除非使用外部类的实例化对象,在通过外部类的实例化对象访问内部类  
    public static class MenuItem{    
        private String name;  
        private double price;  
  
        public MenuItem(String name, double price) {  
            this.name = name;  
            this.price = price;  
        }  
  
        public String getName() {  
            return name;  
        }  
  
        public double getPrice() {  
            return price;  
        }  
    }  
  
    @Override  
    public String toString() {  
        return "Restaurant{" +  
                "name='" + name + ''' +  
                ", address='" + address + ''' +  
                '}';  
    }  
    
    public static void main(String[] args) {  
        Restaurant restaurant = new Restaurant();   
    }  
}

在外层类中使用内部

  • 在外部类中,必须通过外部类示例化对象类访问内部类的属性和方法 ,如下方代码中的test方法,一些版本的JDK甚至允许使用内部类对象.属性的方式来访问内部类中的私有化属性
java 复制代码
public class Restaurant {  
    public static class MenuItem{  
        private String name;  
        private double price;

        public MenuItem(String name, double price) {  
            this.name = name;  
            this.price = price;  
        }  

        public String getName() {  
            return name;  
        }  

        public double getPrice() {  
            return price;  
        }  
    }
    public void test(){  
        MenuItem rice = new MenuItem("java炒饭",12.0);
        //必须通过实例化对象来访问内部类的属性和方法 
        String foodName = rice.name;
        //一些版本的JDK可以直接使用`内部类对象.属性`的方式来访问内部类中的私有化属性  
        System.out.println(foodName);  
        String foodName1 = rice.getName();  
        System.out.println(foodName1);  
    }  
    //测试在外部类中通过内部类对象访问属性和方法
    public static void main(String[] args) {  
        Restaurant restaurant = new Restaurant();  
        restaurant.test();  
    }  

}

内部类的修饰符

Public Static

  • 在创建内部类的时候,最好使用static进行修饰,这样才可以在外层类中访问该内部类,因为如果没有使用static进行修饰,内部类并不是属于外层类的,而是属于外部类实例化的对象的属性类,类似于静态方法和成员方法的区别

public

  • 当没有使用static 修饰内部类,则需要使用外层类的示例化对象访问内部类 ,类似于成员方法,如下方代码所示,我们只使用public修饰内部类:

    java 复制代码
    package com.inside;  
    public class Restaurant {  
        private String name;  
        private String address; //地址  
        public Restaurant() {}  
        public void CreateMenuItem(String name,double price){  
        MenuItem menuItem = new MenuItem(name,price);  
    }
    
        public class MenuItem{//使用外部类的实例化对象,在通过外部类的实例化对象访问内部类  
            private String name;  
            private double price;  
    
            public MenuItem(String name, double price) {  
                this.name = name;  
                this.price = price;  
            }  
    
            public String getName() {  
                return name;  
            }  
    
            public double getPrice() {  
                return price;  
            }  
        }  
        public static void main(String[] args) {  
        
        }  
    
    }
    • 只用public修饰,当我们在其他类中访问Restaurant.MenuItem则要通过外层类的示例化对象, 测试用例如下方代码所示:
    java 复制代码
    package com.inside;
    public class RestaurantMain {  
        public static void main(String[] args) {  
            //使用外部类的实例化对象,通过外部类的实例化对象访问内部类  
            Restaurant restaurant = new Restaurant();  
            Restaurant.MenuItem menuItem = restaurant.new MenuItem("python炒面",10);  
        }  
    }

private

  • 当我们使用private修饰内部类的时候则在外层类和通过外层类对象就都无法访问了,这时候我们就要在外层类中创建一个方法类管理内部类:
    • 这里我们将内部类用private修饰内部类,并创建管理内部类MenuItem的方法CreateMenuItem(),如下方代码所示:
java 复制代码
public class Restaurant {
    private  String name;
    private  String address; //地址
    public Restaurant() {}

    //用于创建private内部类的方法
    public void CreateMenuItem(String name,double price){
        MenuItem menuItem = new MenuItem(name,price);
    }
    private class MenuItem{ //将权限修饰符设置为private
        private String name;
        private double price;

        public MenuItem(String name, double price) {
            this.name = name;
            this.price = price;
        }

        public String getName() {
            return name;
        }

        public double getPrice() {
            return price;
        }
    }

}
    • 这是private内部类的测试用例,因为使用private进行修饰,所以在其他类,无论如何都是无法访问的,所以我们用外层类中公开的管理内部类的方法进行访问,如CreateMenuItem()方法:
    java 复制代码
    public class RestaurantMain {  
        public static void main(String[] args) {
    // 当内部类的权限修饰符为private即为私有的,那么就无法通过外部类实例化对象来访问了
      //如果修饰符是private那么就只能在外部类设计方法,在外部类中创建内部类的实例化对象  
            Restaurant restaurant = new Restaurant();  
            restaurant.CreateMenuItem("python炒面",10);
        }
    }

函数内部类(局部内部类)

  • 函数中也可以有内部类(函数内部类)
java 复制代码
package com.inside;  
public class Restaurant {  
    private  String name;  
    private  String address; //地址  
    public Restaurant() {}  
    public  void showSpicy(String spicy){  
  
        class LocalClass{  
            public void display(){  
                System.out.println("辣度是" + spicy);  
            }  
        } //局部内部类只能在外面一层的花括号内使用  
  
        LocalClass spicyObject = new LocalClass();  
        spicyObject.display();  
    }    
}
java 复制代码
package com.inside;  
public class RestaurantMain {  
     public static void main(String[] args) {  
        //局部类测试用例  
        restaurant.showSpicy("特辣");  
    }  
}

匿名内部类

什么是匿名内部

  • 匿名内部类是一种特殊的局部内部类;所谓匿名:指的是不需要为这个类声明名字。

匿名内部类的格式

java 复制代码
new 抽象类名/接口名(){  
    重写抽象类名或者接口中的抽象方法等  
};

匿名内部类的特点

  • 匿名内部类的本质就是在外层类中一个会立刻创建对象的类,一般是其他接口或抽象方法的实现类。

匿名内部类例

  • 首先创建一个接口Swimming
java 复制代码
interface Swimming{
    public abstract void swim();
}
  • 按照正常步骤如果我们需要使用接口就要先实现接口,然后实例化实现类,将实现类的对象传入需要接口实现类实例化对象的方法中像这样:

    • 实现接口
    java 复制代码
    // 接口的实现  
    class swimmingImpl implements Swimming{  
        @Override  
        public void swim() {  
            System.out.println("我们去游泳了...");  
        }  
    }
    • 然后将接口实现类实例化为对象的同时传入到方法中
    java 复制代码
    public class Test1{  
        public static void main(String[] args){  
            useSwimming(new swimmingImpl());  
        }
        public static void useSwimming(Swimming swimming){  
            swimming.swim();  
        }
    }  
  • 但其实,有了匿名内部类,我们可以将实现接口的swimmingImpl实现类和调用需要实现类对象的useSwimming方法合并,如下方代码所示:

java 复制代码
public class Test1{  
    public static void main(String[] args){  
    useSwimming(new swimmingImpl());
        useSwimming(new Swimming() {  
            @Override  
            public void swim() {  
                System.out.println("我是在Test1中的匿名内部类,我要去游泳了");  
            }  
        }); //相当于直接在Test1中创建了一个匿名的内部类并且立刻用其来实现接口,并立刻实例化  
        // 并且让示例化的对象立刻传入到方法useSwimming(Swimming swimming)中  

    //方法的参数是一个接口,那么调用这个方法要传入的是这个接口的实现对象,
    //同时这个接方法的参数就是一个多态对象,多态对象 编译看左执行看右 
    }
    vpublic static void useSwimming(Swimming swimming){  
        swimming.swim();    
    } 
}
  • 有时候我们可能会想向匿名内部类中写入一些不是用于实现接口的方法,也就是只是内部类的方法,那我们调用就只可以在内部类末尾使用.方法名()的方式调用
java 复制代码
public class Test1{  
    public static void main(String[] args){  
        new Swimming() {  
            @Override  
            public void swim() {  
                System.out.println("我是在Test1中的匿名内部类,我要去游泳了");  
            }  
            public void test(){  
                System.out.println("我是匿名内部类中的特殊方法");  
            }  
        }.test();  
    }  
    public static void useSwimming(Swimming swimming){  
        swimming.swim();  
        // swimming.test();  
        // 无法调用,接口的多态对象只能拥有接口的抽象方法  
    }  
}  

应用场景

  • 通常来说当一个方法的参数只需要一个接口的实现对象,而且这个实现对象在可以未来遇见的开发中只使用这一次
  • 例如匿名内部类通常用于实现接口或继承其他类,并立即创建该类的对象;使用匿名内部类创建线程
  • 常用于线程、事件监听器等场景。

总结

  • 内部类可以更好的帮我们封装或者组织代码,对于属性中还有属性的需求,我们可以通过内部类将需求拆分为类中的内部类
  • 根据修饰符的不同内部类也可以分多种
    • public : 成员内部类
    • public static: 静态成员内部类
    • private:私有内部类
    • Class.func.Class -- 即为函数中的内部类:局部内部类
  • 外层的类想要访问内部类中的属性和方法,只能通过内部类的实例化对象
  • 在外层类之外的类,根据属性的不同访问的方式也不同
    • public (成员内部类):通过外层类的实例化对象进行访问
    • public static( 静态成员内部类):直接通过外层类访问
    • private(私有内部类):除了外层类,其他类无法访问,在外层类编写管理内部类的函数
    • Class.func.Class -- 即为函数中的内部类(局部内部类): 通过调用函数访问
相关推荐
开心就好20251 小时前
不依赖 Mac 也能做 iOS 开发?跨设备开发流程
后端·ios
一只叫煤球的猫1 小时前
RAG 如何落地?从原理解释到工程实现
人工智能·后端·ai编程
卷心菜投手ovo2 小时前
一个页面支持自定义字段,后端该怎么设计数据库?
后端
隔壁家滴怪蜀黍2 小时前
AgentScope MsgHub 多智能体通信机制详解
后端
孟陬2 小时前
国外技术周刊 #3:“最差程序员”带动高效团队、不写代码的创业导师如何毁掉创新…
前端·后端·设计模式
Cosolar2 小时前
Transformer训练与生成背后的数学基础
人工智能·后端·开源
lay_liu2 小时前
Spring Boot 自动配置
java·spring boot·后端
程序员cxuan2 小时前
说点掏心窝子的话
后端·程序员
写Cpp的小黑黑2 小时前
WebSocket 连通性测试方法
后端