Java内部类

内部类

内部类不是在一个java源文件中编写俩个平行的类,而是在一个类的内部再定义另外一个类。
	例如:
		Person.java文件中
		//虽然这个俩个类在一个文件中,但是它们是平行的关系
		//所以这种情况不是内部类
		public class Person{
		

}
	class PersonTest{
	
	}

例如:
	Person.java文件中
	public class Person{
		//这个就是一个内部类
		//类A的是定义在Person类中的
		public class A{
		
		}

	}

注意,内部类是类和类之间的嵌套关系
我们可以把定义在外面的类叫做外部类,嵌套定义在里面的类叫做内部类。
java中的内部类,可以分为四种:成员内部类,静态内部类,局部内部类,匿名内部类
通过以下几个方法,对内部类进行学习了解:
			在语法上,该内部类如何编写
			在该内部中,都可以定义哪些属性和方法
			内部类和外部类之间,如何相互方法对方的属性和方法
			在外部类中,以及在其他类的代码中,该如何创建这个内部类对象
   		最后还需要从意义上,了解为什么要编写内部类

1 成员内部类

//成员内部类例子
				//MemberOutterClass是当前外部类
				public class MemberOutterClass{
					

				/* 成员内部类 声明开始 */
				public class MemberInnerClass{
				
				}
				/* 成员内部类 声明结束 */

			}

定义属性和方法、构造器
例如:

public class MemberOutterClass{

					/* 成员内部类 声明开始 */
					public class MemberInnerClass{
						private String name;
						private int age;
						
						public void run(){}

					}
					/* 成员内部类 声明结束 */

		        }

注意,成员内部类中,【不能】编写静态的属性和方法
注意,成员内部类中,可以编写构造器,如果有需要的话,如果不编写的话,那么默认使用无参的构造器。

成员内部类和外部类的相互访问
例如:

				public class MemberOutterClass{
				
				private String name;

				private static int age;

				public void run(){}

				public static void go(){}

				public void test(){
					//在外部类中,任何访问成员内部类中的属性和方法
					//MemberInnerClass mic = this.new MemberInnerClass();
					//在外部类中,可以把 this. 省去
					//这个意思就是成员内部类对象的创建,是需要依托于外部类对象的
					//就像一个类中的成员属性、成员方法,需要依托于这个类的对象才能访问
					MemberInnerClass mic = new MemberInnerClass();
					System.out.println(mic.name);
					System.out.println(mic.age);
					mic.run();
				}

				/* 成员内部类 声明开始 */
				public class MemberInnerClass{
					private String name;
					private int age;
					
					public void run(){}

					public void test(String name){
						//这个方法的输参数name
						System.out.println(name);

						//访问当前内部类中name属性
						System.out.println(this.name);
						System.out.println(MemberInnerClass.this.name);
						
						//访问外部类中的name属性(非静态)
						System.out.println(MemberOutterClass.this.name);
						
						//访问外部类中的age属性(静态)
						System.out.println(MemberOutterClass.age);
						
						//访问外部类中的run方法(非静态)
						MemberOutterClass.this.run();
						//访问外部类中的go方法(静态)
						MemberOutterClass.go();

						//访问内部类中自己的run方法
						MemberInnerClass.this.run();
						
					}

				}
				/* 成员内部类 声明结束 */

			}

			注意,在内部类中,可以使用 类名.this 的形式,当前使用的this指的是哪一个类中的this
			注意,在外部类中,要访问成员内部类中的属性和方法,需要先创建这个成员内部类的对象
			注意,成员内部类对象,是要依托于外部类对象,也就是一定先创建了外部类对象,然后才能创建这个成员内部类对象。

在其他类中,怎么使用这个成员内部类创建对象
注意,首先要先确认这个内部类的访问控制修饰符使用的是哪一个,如果是private修饰的话,那么在其他类中,就不可能访问到这个成员内部类

​ 注意,在其他类中使用这个内部类的时候,一定要先进行import导入

​ 例如:

		import com.briup.day26.MemberOutterClass.MemberInnerClass;
		
    public class MemberOutterClass{

				/* 成员内部类 声明开始 */
				public class MemberInnerClass{
					private String name;
					private int age;
					public void run(){}

				}
				/* 成员内部类 声明结束 */

			}

			class MemberOutterClassTest{
				
				public static void main(String[] args){
					
					//MemberOutterClass moc = new MemberOutterClass();
					//MemberInnerClass mic = moc.new MemberInnerClass();

					MemberInnerClass mic = new MemberOutterClass().new MemberInnerClass();
					
					mic.run();

				}

			}

2 静态内部类

		格式:
			//静态内部类的例子
			public class StaticOutterClass{
				
				/* 静态内部类 声明开始 */
				public static class StaticInnerClass{
				}
					/* 静态内部类 声明结束 */
				 
				}

		
			定义属性和方法、构造器:
				
				public class StaticOutterClass{

					/* 静态内部类 声明开始 */
					public static class StaticInnerClass{
						private String name;
						private static int age;

						public void run(){}
						public static void go(){}

					}
					/* 静态内部类 声明结束 */
				 
				}

				注意,静态内部类中,【可以】编写静态的属性和方法,另外在四种内部类中,只有静态内部类可以编写静态属性和方法
				注意,静态内部类中,可以编写构造器,如果有需要的话,如果不编写的话,那么默认使用无参的构造器。

内部类和外部类的相互访问:

				例如:
					public class StaticOutterClass{
						private String name;
						private static int age;
        
          private void run(){}
					private static void go(){}

					public void test(){
						
						//在外部类中,访问静态内部类中的静态属性和方法
						System.out.println(StaticInnerClass.age);
						StaticInnerClass.go();
						//在外部类中,访问静态内部类中的非静态属性和方法
						//这时候需要先创建静态内部类对象,使用对象来访问
						StaticInnerClass sic = new StaticInnerClass();
						System.out.println(sic.name);
						sic.run();
					}
					/* 静态内部类 声明开始 */
						public static class StaticInnerClass{
							private String name;
							private static int age;
	
							public void run(){}
							public static void go(){}
	
							public void test(String name){
								//这name是参数
								System.out.println(name);
								
								//静态内部类访问自己的属性和方法
								//静态 和 非静态的都可以访问
								System.out.println(this.name);
								System.out.println(StaticInnerClass.this.name);
								System.out.println(StaticInnerClass.age);
								StaticInnerClass.this.run();
								StaticInnerClass.go();
								//静态内部类中访问外部类中的静态属性和静态方法
							//注意,在静态内部类中访问不了外部类中的非静态属性和方法
							//System.out.println(StaticOutterClass.this.name);
							System.out.println(StaticOutterClass.age);
							StaticOutterClass.go();
													}

					}
					/* 静态内部类 声明结束 */
				 
				}

				注意,在静态内部类中访问不了外部类中的非静态属性和方法
				注意,在外部类中,如果要访问静态内部类中的静态属性和方法,那么可以直接使用 内部类的名字来访问,如果要访问静态内部类中的非静态属性和方法,那么这个时候就需要先创建内部类对象,然后使用对象再访问。
			
			在其他类中,怎么使用这个静态内部类创建对象
				注意,要先确认这个内部类的 访问控制修饰符 使用的是哪一个,如果是private修饰的话,那么在其他类中,就不可能访问到这个成员内部类
				
				注意,在其他类中使用这个内部类的时候,一定要先进行import导入

				注意,静态内部类和成员内部类不同,静态内部类由于是静态的,它可以独立存在,并不会依赖于外部类的对象。而成员内部类就必须依赖于外部类对象,也就是必须先要创建出外部类对象,才能接下来创建成员内部类对象。

例如:

			import com.briup.day26.StaticOutterClass.StaticInnerClass;

			public class StaticOutterClass{

				/* 静态内部类 声明开始 */
				public static class StaticInnerClass{
					public void run(){}
				}
				/* 静态内部类 声明结束 */
			 
			}
			class StaticOutterClassTest{
				
				public static void main(String[] args){
					
					//直接使用静态内部类来创建对象,不需要依赖外部类
					//但是要记得先import导入
					StaticInnerClass sic = new StaticInnerClass();
					sic.run();

				}

			}

3 局部内部类

​ 注意,这个是四种内部类中,使用的最少最少的一种内部类形式

				格式:
			//局部内部类的例子
			public class LocalOutterClass{
				
				public void test(){
					
					/* 局部内部类 声明开始 */
					class LocalInnerClass{
						
					}
					/* 局部内部类 声明结束 */

				}
			}

			注意,局部内部类是定义在方法中的一种内部类,这种情况下,这个内部类的作用范围就比较小了,只能在方法中起作用,出了这个方法代码块,局部内部类就没有了。
		定义属性和方法、构造器:
			//局部内部类的例子
			public class LocalOutterClass{
				
				public void test(){
					
					/* 局部内部类 声明开始 */
					class LocalInnerClass{
						private String name;
						private int age;
						
						public void run(){}

					}
					/* 局部内部类 声明结束 */
					
				}

			}

			注意,局部内部类中,【不能】编写静态的属性和方法
			注意,局部内部类中,如果有需要的话,可以编写构造器,如果不编写的话,那么默认使用无参的构造器。

局部内部类和外部类的相互访问:

					例如:
					public class LocalOutterClass{
						private String name;
						private static int age;
					public void run(){}
					public static void go(){}
					
					public void say(final String myName){
						
						final int a = 1;
						
												/* 局部内部类 声明开始 */
						class LocalInnerClass{
							private String name;
							private int age;
							
							public void run(){}

							public void test(String name){
								
								//访问当前最近的name变量,也就是这个参数
								System.out.println(name);

								//访问say方法中的myName属性
								//也可以访问这个方法中的局部变量
								//但是要求这个局部变量必须是final修饰的
								//JDK1.8的时候,这个局部变量不是final修饰的也可以被局部内部类访问,但是访问之后,这个变量就自动变为final的了。
								System.out.println(myName);
								System.out.println(a);

								//访问LocalInnerClass类中的属性name
								System.out.println(this.name);
								System.out.println(LocalInnerClass.this.name);
								
								//访问LocalOutterClass类中的属性和方法(静态和非静态)
								System.out.println(LocalOutterClass.this.name);
								System.out.println(LocalOutterClass.age);
								LocalOutterClass.this.run();
								LocalOutterClass.go();

							}

						}
						/* 局部内部类 声明结束 */
						
						//由于局部内部类在方法中,所以也只能在这个方法中使用
						LocalInnerClass lic = new LocalInnerClass();
						System.out.println(lic.name);
						System.out.println(lic.age);
						lic.run();
						
					}

				}

		在其他类中,怎么使用这个内部类创建对象
			出了这个局部内部类所在的方法之后,其他任何地方都使用不到这个局部内部类

4 匿名内部类

		注意,匿名内部类是将来我们在程序中,使用最多的一种内部类形式。

		注意,匿名内部类可以定义在方法中,也可以在类中属性赋值的时候进行使用。但是绝大多数都会是在方法中进行定义和使用。

		注意,匿名内部类由于没有名字,所以在定义的时候形式上也会比较特殊一些。

		匿名内部类必须依附在一个类或者接口上来进行定义,如果是依附在一个类上,那么这个匿名内部类就默认是这个类的子类。如果是依附在一个接口上,那么这个匿名内部类就默认是这个接口的实现类。

		注意,一个普通的类,都是先声明,然后再使用这个来创建对象,但是匿名内部类,就必须在声明的同时就创建出这个类的对象,并且只能使用这一次。因为它没有名字。
		格式:
			public class AnonymousOutterClass{

				//在给类中属性private Person person; 赋值的时候
				//=号右边使用了匿名内部类对象,来给=号左边的引用person进行赋值
				private Person person = new Person(){
					public void run(){
					
					}
				};
				
				public void test(){
					//虽然抽象类不能直接new对象,但是我们可以依附在这个抽象类上,声明出一个匿名内部类,并且同时就创建这个匿名内部类的对象。
					//注意,这个里的这个大括号,就是这个匿名内部类的代码实现
					//这个匿名内部类,就相当于继承了Person这个父类型

					//父类型的引用,指向子类对象,只不过这次的这个子类对象,是一个匿名内部类对象。
					Person p = new Person(){
						
						public void run(){
							System.out.println("这里就是匿名内部类的实现");
						}

					};
					
											//虽然接口不能直接new对象,但是我们可以依附在这个接口上,声明出一个匿名内部类,并且同时就创建这个匿名内部类的对象。
						//这个匿名内部类,默认就是对这个接口的实现
						Action a = new Action(){
							
							public void go(){
								System.out.println("这里就是匿名内部类的实现");
							}

						};

					}

				}

				abstract class Person{
					public abstract void run();
				}

				interface Action{
					public void go();
				}




		定义属性和方法、构造器
			在这个点上,匿名内部类和其他的内部类不太一样。其他的内部类都可以定义自己的属性、方法、构造器,然后将来将来需要的时候可以使用。

			匿名内部类,虽然可以定义属性和方法,但是定义之后无法调用到。

			匿名内部类,我们是没有办法编写构造器的,因为这个类没有名字,但是编译之后会自动生成构造器的,通过javap就可以看到这个构造器的声明。

			总结:在匿名内部类中,一般情况,我们不会编写单独的属性、方法(如果有需要的话,可以编写),因为在外面不能能直接调用,我们也编写不了构造器,因为没有名字。我们在匿名内部类中,做的最多的事情,就是【重写】父类中的方法,或者【实现】接口中的抽象方法。

			例如:
			Action a = new Action(){
				private String name;
				public void run(){
				
				}
				//go方法是实现接口Action中的抽象方法
				public void go(){
					this.name = "tom";
					this.run();
					System.out.println("这里就是匿名内部类的实现");
				}
			};
			//编译报错
			a.run();

			因为run方法是匿名内部类中独有的方法,变量a是Action类型的,Action中没有定义run方法,所以使用变量a无法调用到run方法

			把变量a进行类型转换,转为这个匿名内部类的类型就可以了,因为这个run方法就是这个匿名内部类中独有的。

			但是由于匿名内部类没有名字,所以我们也无法把变量a转为这个类型。那么也就是我们无法直接调用到这个独有的run方法。

			但是可以【间接】的调用到,例如可以在go方法中调用run方法,然后再使用变量a俩调用go方法,最后也可以让run方法执行。

			总结:在你们内部类中,定义直接的独有的属性和方法,一般情况意义不大,除非是想在这匿名内部类中自己单独使用。因为外部是没有办法【直接】调用到的。
		匿名内部类和外部类的相互访问:
			
			匿名内部类在方法中定义的时候,其实就是一个没有名字的局部内部类,所以这时候它和外部类相互访问的情况和局部内部类是一样的。
			例如:
			public class AnonymousOutterClass{

				private String name;
				private static int age;
				
				public void test(){

					final int num = 1;

					Person p = new Person(){
						
						public void run(){
							System.out.println(num);
							System.out.println(AnonymousOutterClass.this.name);
							System.out.println(AnonymousOutterClass.age);
						}

					};

					p.run();
						}

				}
		在其他类中,怎么使用这个内部类创建对象
			匿名内部类大多定义在方法中,并且没有名字,所以其他地方都无法使用这个匿名内部类。但是我们可以使用return语句把这个匿名内部类的对象,返回出去,让别人使用。

			例如:

			public Person test(){

				final int num = 1;

				Person p = new Person(){
					
					public void run(){
						System.out.println(num);
						System.out.println(AnonymousOutterClass.this.name);
						System.out.println(AnonymousOutterClass.age);
					}

				};
					return p;
				}
  1. 不同内部类的选择
    ​ 例如现在已经确定了要使用内部类,那么接下来该如何选择?
    ​ 1.考虑这个内部类,如果需要反复的进行多次使用
    ​ 1.1 在这个内部类中,如果需要定义静态的属性和方法
    ​ 选择使用静态内部类

    ​ 1.2 在这个内部类中,如果需要访问外部类的非静态属性和方法
    ​ 选择使用成员内部类

    ​ 2.考虑这个内部类,如果只需要使用一次
    ​ 选择使用匿名内部类


​ 注意,基本没有什么情况下,我们会选择局部内部类,这种内部类几乎不用。


​ 6. 内部类的意义(为什么要使用内部类)
​ 例如现在有一个类A,在类A中需要完成一些工作,在这个过程中,需要另一个类B进行辅助,这个类B是专门针对类A进行设计编写的,在其他类中根本不会用到这个类B,这时候,考虑到类A和类B之间的这种紧密的联系,那么我们就可以把类B以内部类的形式,定义在类A中。

​ 例如现在有一个类A,还有一个类B,这俩个类需要相互访问对方的属性或者方法,共同合作来完成一些功能。基于这种特点,为了能让类A和类B之间更加方便的进行相互访问,那么我们也可以考虑以内部类的形式,把类B定义在类A之中

​ 注意,很多使用内部类来完成的功能/效果,其实不使用内部类,也就是用普通的类,也能完成,但是可能这样的话,俩个类之间的相互访问没内部类的形式容易,另外没不能突出这俩个类之间的紧密的关系。还有就是也行分开后的这个类,在其他地方根本就不会被使用,因为这个类作为一个辅助的类,只是辅助我们的主类来完成一些操作的,在其他代码中根本用不上。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值