解析JavaSe的内部类
作者:小小茶花女 发布时间:2022-08-14 18:19:33
内部类
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接口实现类只需一次使用,则可采用上面程序中的方式,定义一个匿名内部类。
来源:https://hengheng.blog.csdn.net/article/details/122704594


猜你喜欢
- 一.问题1.HashSet,TreeSet是如何使用hashCode()和equal()方法的2.TreeMap,TreeSet中的对象何时
- 输入方法第一种输入方法:scannerimport java.util.Scanner; // 导入java.util.Scannerpub
- 本文实例讲述了c#图像截取的实现方法。分享给大家供大家参考。具体如下:图像截取的相关代码如下: public Form1()&nb
- 1.pom文件导入依赖<!-- kafka --><dependency> <groupId>
- 为什么需要多线程?模型的简化,如某些程序是由多个相对独立任务的运行:图形界面的出现,输入、输出的阻塞多核CPU的更好利用异步行为的需要Jav
- @Conditional的使用@Conditional可以根据条件来判断是否注入某些Bean。package com.morris.spri
- Kotlin中StateFlow的使用StateFlow 是 Flow 的实现,是一个特殊的流,默认的 Flow 是冷流,而StateFlo
- 在Android开发中,有时候可能会要用到碎纸机的效果,今天小编为大家整理好代码,一起来看看吧。首先来看下效果图实例代码xml<com
- 目录背景解决方案1、设置热点数据永远不过期。2、加互斥锁,互斥锁参考代码如下:总结说明1、缓存中有数据,直接走下述代码就返回结果了2、缓存中
- 题目描述原题链接 :88. 合并两个有序数组给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2,另有两个整数 m
- 在公司的项目中用到了分布式锁,但只会用却不明白其中的规则所以写一篇文章来记录使用场景:交易服务,使用redis分布式锁,防止重复提交订单,出
- 本文实例分析了Android开发之TabHost选项卡及相关疑难解决方法。分享给大家供大家参考,具体如下:前言:虽然现在谷歌已经不推荐使用T
- 本文实例为大家分享了Java实现图片旋转,供大家参考,具体内容如下方法一:普通方法实现图片旋转/** * 图像旋转  
- mybatis多个区间处理如图:要实现车辆数不同区间查询条件思路a.前端传数组,数组里面放"1-5"String类型值
- 实现说明这里的核心在于如何在大并发的情况下保证数据库能扛得住压力,因为大并发的瓶颈在于数据库。如果用户的请求直接从前端传到数据库,显然,数据
- Spring多配置文件有什么好处? 按照目的、功能去拆分配置文件,可以提高配置文件的可读性与维护性,如将配置事务管理、数据源等少改动的配置与
- 本文实例讲述了Android编程实现的首页左右滑动切换功能。分享给大家供大家参考,具体如下:很多软件会选择左右滑动的主界面,实现方式也很多,
- 本文实例讲述了C#在运行时动态创建类型的实现方法。是C#项目开发中很实用的技巧。分享给大家供大家参考。具体分析如下:具体来说,C# 在运行时
- 刚开始做开发学习的小伙伴可能在有一个知识上面有错误的认知,我们天天写程序是在Idea下写的,运行也是在Idea下运行的。但是实际开发完成后,
- 【前言】AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统