[JAVA基础] 五、内部类详解

本文深入解析Java中的四种内部类:成员内部类、静态内部类、局部内部类和匿名内部类的特点与应用场景。详细阐述每种内部类的创建、访问方式及注意事项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java的四种内部类

内部类:一个类定义在另外一个类的内部,那么该类就称作为内部类。

内部类的class文件名: 外部类$内部类.  好处:便于区分该class文件是属于哪个外部类的。

Java的四种内部类包括如下:

  • 成员内部类
  • 静态内部类
  • 局部内部类
  • 匿名内部类

成员内部类:

定义在另一个类(外部类)的内部,而且与成员方法和属性平级叫成员内部类,......相当于外部类的非静态方法,如果被static修饰,就变成静态内部类了。

成员内部类的访问方式:
                    
                    方式一:在外部类提供一个方法创建内部类的对象进行访问。
                    
                    方式2二:在其他类直接创建内部类的对象。 格式:外部类.内部类  变量名 = new 外部类().new 内部类();
            
            注意: 如果是一个静态内部类,那么在其他类创建 的格式:
                    外部类.内部类  变量名 = new 外部类.内部类();


           内部类的应用场景: 我们在描述A事物的时候,发现描述的A事物内部还存在另外一个比较
           复杂的事物B时候,而且这个比较复杂事物B还需要访问A事物的属性等数据,那么这时候
           我们就可以使用内部类描述B事物。

           比如: 人--->心脏

           class 人{
            
            血

            氧气

            等....

            class 心脏{
            
            }        

           }

           内部类的好处:内部类可以直接访问外部类的所有成员。

            内部类要注意的细节:
                1. 如果外部类与内部类存在同名的成员变量时,在内部类中默认情况下是访问内部类的成员变量。
                   可以通过"外部类.this.成员变量名/方法名" 指定访问外部类的 成员。
                2. 私有的成员内部类只能在外部类提供一个方法创建内部类的对象进行访问,不能在其他类创建对象了。
                3. 成员内部类一旦出现了静态的成员,那么该类也必须 使用static修饰。

*/

//外部类
class Outer{
    
    //成员变量
    int x = 100; // Outer.class文件被加载到内存的时候存在内存中。  静态的成员数据是不需要对象存在才能访问。

    //成员内部类
    static    class Inner{      
        
        static    int i = 10;

        public void print(){
            System.out.println("这个是成员内部类的print方法!"+i);
        }
    }

    
    //在外部的方法中创建了内部类的对象,然后调用内部 方法。
    public void instance(){
        Inner inner = new Inner();
        inner.print();
    }

}

//其他类
class Demo4 
{
    public static void main(String[] args) 
    {
        /*
        System.out.println(Outer.Inner.i);
        
        Outer outer = new Outer();
        outer.instance();
        
        
        Outer.Inner inner = new Outer().new Inner();
        inner.print();
        */


        Outer.Inner inner = new Outer.Inner();
        inner.print();
    }
}

静态内部类

使用static修饰的成员内部类叫静态内部类。

可以这样理解:与外部类同级的类,或者叫做外部类的静态成员。与成员内部类的对比如下:

说明

成员内部类

静态内部类

静态成员

静态成员需同时有final关键词修饰

可以

静态方法

不可定义

可以

访问外部类非static属性/方法

外部类名.this.成员方法/属性

不可以

外部类访问内部类

需要通过内部类的一个实例来访问

需要通过内部类的一个实例来访问

创建实例

外部类名.内部类名 实例名 = new 外部类名(参数).new 内部类名(参数)

外部类名.内部类名 实例名 = new 外部类名.内部类名(参数)

编译后的class文件

单独的class文件(so内部类中的方法和变量可以跟父类的方法和变量同名),外部类$内部类.class

单独的class文件(so内部类中的方法和变量可以跟父类的方法和变量同名),外部类$内部类.class

其他

与外部类平级的类继承内部类时,其构造方法中需要传入父类的实例对象。且在构造方法的第一句调用“外部类实例名.super(内部类参数)”

局部内部类

定义在代码块、方法体内、作用域(使用花括号“{}”括起来的一段代码)内的类叫局部内部类。

  1. 局部内部类只能在代码代码块、方法体内和作用域中使用(如创建对象和使用类对象等)
  2. 局部内部类访问作用域内的局部变量,该局部变量需要使用final修饰。
  3. 可以使用abstract修饰,声明为抽象类。
class  Outer{

	String name= "外部类的name";

	public void test(){
		//局部变量
		final	int y =100;  // y 什么时候从内存中消失? 方法执行完毕之后y消失。

		//局部内部类
		class In                                                           ner{     /*
							当test方法执行完毕之后,那么y马上从内存中消失,而Inner对象在方法
							执行完毕的时候还没有从内存中消失,而inner对象的print方法还在访问着
							y变量,这时候的y变量已经消失了,那么就给人感觉y的生命变量已经被延长了
							.

							解决方案: 如果一个局部内部类访问一个局部变量的时候,那么就让该局部内部类
							访问这个局部变量 的复制品。				
						*/
			int x = 10;

			public void print(){
				System.out.println("这个是局部内部类的print方法.."+y);
			}	
		}
		
		Inner inner = new Inner();  //这个inner对象什么时候消失?  Inner对象的生命周期比局部变量y的生命周期要长。
		inner.print();
	}


}



class Demo5 
{
	public static void main(String[] args) 
	{
		Outer outer = new Outer();
		outer.test();
	}
}

匿名内部类

匿名内部类:没有类名的类就称作为匿名内部类。

匿名内部类的好处:简化书写。

匿名内部类的使用前提:必须存在继承或者实现关系才能使用。

匿名内部类一般是用于实参。

  1. 只能使用一次,创建实例之后,类定义会立即消失(想要多次使用就要用到反射的知识了)
  2. 必须继承一个类(抽象的、非抽象的都可以)或者实现一个接口。如果父类(或者父接口)是抽象类,则匿名内部类必须实现其所有抽象方法。
  3. 不能是抽象类,因为匿名内部类在定义之后,会立即创建一个实例。
  4. 不能定义构造方法,匿名内部类没有类名,无法定义构造方法,但是,匿名内部类拥有与父类相同的所有构造方法。
  5. 可以定义代码块,用于实例的初始化,但是不能定义静态代码块。
  6. 可以定义新的方法和属性(不能使用static修饰),但是无法显式的通过“实例名.方法名(参数)”的形式调用,因为使用new创建的是“上转型对象”(即父类声明指向子类对象)。
  7. 是局部内部类,所以要符合局部内部类的要求。

说明

成员内部类

匿名内部类

静态成员

静态成员需同时有final关键词修饰

不可定义

静态方法

不可定义

不可定义

访问外部类非static属性/方法

外部类名.this.成员方法/属性

外部类名.this.成员方法/属性

外部类访问内部类

需要通过内部类的一个实例来访问

需要通过内部类的一个实例来访问

创建实例

外部类名.内部类名 实例名 = 外部类实例名.new 内部类构造方法(参数)

如上:父类 实例名 = new 父类(){}

编译后的class文件

单独的class文件(so内部类中的方法和变量可以跟父类的方法和变量同名),外部类$内部类.class

单独的class文件,使用类$数字.class

其他

与外部类平级的类继承内部类时,其构造方法中需要传入父类的实例对象。且在构造方法的第一句调用“外部类实例名.super(内部类参数)”

abstract class Animal{
	
	public abstract Animal run();

	public abstract void sleep();
}


class Outer{

	public void print(){
		//需求: 在方法内部定义一个类继承Animal类,然后调用run方法与sleep()。
		
		/*
		//局部内部类   这种为了调用run()方法,创建了一个Dog对象,有点浪费
		class Dog extends Animal{
			
			public void run(){
				System.out.println("狗在跑..");
			}

			public void sleep(){
				System.out.println("狗趴在睁开眼睛睡..");
			}
		}
		
		//创建对象
		Dog d = new Dog();
		d.run();	
		d.sleep();
		*/
	
		//匿名内部类 :匿名内部类只是没有类名,其他的一概成员都是具备的。

		// 匿名内部类与Animal是继承 的关系。  目前是创建Animal子类Dog的对象. 

                   new Animal(){  //多态   本身没有类名Dog,只能借用父类的类名Animal
		
			//匿名内部的成员 
			public Animal run(){
				System.out.println("狗在跑..");
				return this;
			}.run(); //这个就是一个匿名对象,所以可以.run()

      //如果有多个父类方法想要调用,可以让前面的方法有返回父类对象
	Animal	a = new Animal(){  
		
			//匿名内部的成员 
			public Animal run(){
				System.out.println("狗在跑..");
				return this;//让该方法返回一个对象Animal
			}
			
			public void sleep(){
				System.out.println("狗趴在睁开眼睛睡..");
			}
	
		}.run().sleep();//因为run()方法有返回值Animal,所以可以继续调用sleep()


       //如果有特有方法想要调用,就不能用匿名内部类了
 
	Animal	a = new Animal(){  //多态
		
			//匿名内部的成员 
			public Animal run(){
				System.out.println("狗在跑..");
				return this;
			}
			
			public void sleep(){
				System.out.println("狗趴在睁开眼睛睡..");
			}

			//特有的方法
			public void bite(){
				System.out.println("狗在咬人..");
			}
	
		};
	
		//a.bite();
		a.run();
		a.sleep();
		
	}
}



class Demo6 
{
	public static void main(String[] args) 
	{
		//System.out.println("Hello World!");
		
		Outer outer = new Outer();
		outer.print();
	
	}
}
//实现关系下匿名内部类
interface Dao{

	public void add();
}


class Outer{

	public void print(){
		//创建一个匿名内部类的对象
		new Dao(){   //不是接口不能创建对象吗?怎么现在又可以了?
			     //现在创建的是接口的实现类对象,只是用了接口的名字
			 public void add(){
				System.out.println("添加成功");
			 }
		}.add();
	}
}



class Demo7 
{
	public static void main(String[] args) 
	{
		test(new Dao(){
			
			public void add(){
				System.out.println("添加员工成功");
			}
		});


	}

	//调用这个方法...
	public static void  test(Dao d){  //形参类型是一个接口引用..
		d.add();
	}
}

 

基于数据挖掘的音乐推荐系统设计与实现 需要一个代码说明,不需要论文 采用python语言,django框架,mysql数据库开发 编程环境:pycharm,mysql8.0 系统分为前台+后台模式开发 网站前台: 用户注册, 登录 搜索音乐,音乐欣赏(可以在线进行播放) 用户登陆时选择相关感兴趣的音乐风格 音乐收藏 音乐推荐算法:(重点) 本课题需要大量用户行为(如播放记录、收藏列表)、音乐特征(如音频特征、歌曲元数据)等数据 (1)根据用户之间相似性或关联性,给一个用户推荐与其相似或有关联的其他用户所感兴趣的音乐; (2)根据音乐之间的相似性或关联性,给一个用户推荐与其感兴趣的音乐相似或有关联的其他音乐。 基于用户的推荐和基于物品的推荐 其中基于用户的推荐是基于用户的相似度找出相似相似用户,然后向目标用户推荐其相似用户喜欢的东西(和你类似的人也喜欢**东西); 而基于物品的推荐是基于物品的相似度找出相似的物品做推荐(喜欢该音乐的人还喜欢了**音乐); 管理员 管理员信息管理 注册用户管理,审核 音乐爬虫(爬虫方式爬取网站音乐数据) 音乐信息管理(上传歌曲MP3,以便前台播放) 音乐收藏管理 用户 用户资料修改 我的音乐收藏 完整前后端源码,部署后可正常运行! 环境说明 开发语言:python后端 python版本:3.7 数据库:mysql 5.7+ 数据库工具:Navicat11+ 开发软件:pycharm
MPU6050是一款广泛应用在无人机、机器人和运动设备中的六轴姿态传感器,它集成了三轴陀螺仪和三轴加速度计。这款传感器能够实时监测并提供设备的角速度和线性加速度数据,对于理解物体的动态运动状态至关重要。在Arduino平台上,通过特定的库文件可以方便地与MPU6050进行通信,获取并解析传感器数据。 `MPU6050.cpp`和`MPU6050.h`是Arduino库的关键组成部分。`MPU6050.h`是头文件,包含了定义传感器接口和函数声明。它定义了类`MPU6050`,该类包含了初始化传感器、读取数据等方法。例如,`begin()`函数用于设置传感器的工作模式和I2C地址,`getAcceleration()`和`getGyroscope()`则分别用于获取加速度和角速度数据。 在Arduino项目中,首先需要包含`MPU6050.h`头文件,然后创建`MPU6050`对象,并调用`begin()`函数初始化传感器。之后,可以通过循环调用`getAcceleration()`和`getGyroscope()`来不断更新传感器读数。为了处理这些原始数据,通常还需要进行校准和滤波,以消除噪声和漂移。 I2C通信协议是MPU6050与Arduino交互的基础,它是一种低引脚数的串行通信协议,允许多个设备共享一对数据线。Arduino板上的Wire库提供了I2C通信的底层支持,使得用户无需深入了解通信细节,就能方便地与MPU6050交互。 MPU6050传感器的数据包括加速度(X、Y、Z轴)和角速度(同样为X、Y、Z轴)。加速度数据可以用来计算物体的静态位置和动态运动,而角速度数据则能反映物体转动的速度。结合这两个数据,可以进一步计算出物体的姿态(如角度和角速度变化)。 在嵌入式开发领域,特别是使用STM32微控制器时,也可以找到类似的库来驱动MPU6050。STM32通常具有更强大的处理能力和更多的GPIO口,可以实现更复杂的控制算法。然而,基本的传感器操作流程和数据处理原理与Arduino平台相似。 在实际应用中,除了基本的传感器读取,还可能涉及到温度补偿、低功耗模式设置、DMP(数字运动处理器)功能的利用等高级特性。DMP可以帮助处理传感器数据,实现更高级的运动估计,减轻主控制器的计算负担。 MPU6050是一个强大的六轴传感器,广泛应用于各种需要实时运动追踪的项目中。通过 Arduino 或 STM32 的库文件,开发者可以轻松地与传感器交互,获取并处理数据,实现各种创新应用。博客和其他开源资源是学习和解决问题的重要途径,通过这些资源,开发者可以获得关于MPU6050的详细信息和实践指南
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值