Java内部类详解

Java内部类的概念

  Java支持在一个类中定义另一个类,这样的类就是内部类
  通俗来说,就是在类A(或者类A的某一个方法)中定义一个类B,那么类B就是类A的内部类(内嵌类),类A是类B的外部类(外嵌类)。
  内部类B可以定义在类A的某个成员方法里或者类A的成员变量部分,甚至是比成员方法更小的代码块中。
  一般当内部类的内容只对其外部类有意义或者内部类依赖于外部类的时候我们才会使用内部类。

Java内部类创建的一般格式

[public] class 外部类
{
	/*	外部类的成员变量和成员方法	 */
	
	[访问控制符]  [修饰符]  class 内部类名					//内部类定义
	{
		/*	内部类的成员变量和成员方法(定义方法同外部类)	*/
	}
	
	[访问控制符]  [修饰符]  外部类成员方法名 ([形参列表])		
	{
		[访问控制符]  [修饰符]  class 局部内部类			//局部内部类定义
		{
			/*局部内部类的成员变量和成员方法(定义方法同外部类)*/
		}
	}
}

Java内部类的分类

  Java内部类可以分为四种:成员内部类局部内部类静态内部类匿名内部类。下面来逐一介绍。

1.成员内部类(实例内部类)

	定义在一个类里面的类称之为成员内部类。

  这里简单说明下<成员内部类 >的特点  <可以先跳过这部分,看完后面的代码和内部细节之后再来阅读这部分总结>

  1. 不能用static修饰。即前面提到的内部类前面的修饰符不能是static。
  2. .在成员内部类中不允许出现静态变量和静态方法。
  3. 成员内部类可以无限制的访问外部类的所有成员(包括private和static)。
  4. 外部类不能访问内部类的private属性的成员,只能通过内部类的对象去访问。
  5. 外部类外创建成员内部类对象时,必须先创建外部类对象,再由外部类对象创建其成员内部类对象。<稍后的示例代码会具体演示>
	A a= new A();			//先创建外部类对象
	A.B b=  a.new B();		//必须通过a对象来创建其成员内部类对象

  1. 当成员内部类拥有和外部类同名的成员变量或者方法时,会发生隐藏现象,即默认情况下访问的是成员内部类的成员。这时候应该用下面的调用方法:
外部类.this.成员变量
外部类.this.成员方法

————————————————————————————————————————————————————————————

	接下来看一个看比较全面的例子:
	外部类Farm中有一个成员内部类Plant,注意体会上面提到的六点在这个代码里面的应用。
public class Farm 
{
	static String farm_name = "";			//农场的名字
	private double square;					//农场的面积
	private int kinds;						//农场植物数量
	private Plant plant ;					//声明内部类对象
	
	public Farm(String farm_name , double square , int kinds)
	{
		Farm.farm_name = farm_name;
		this.square = square;
		this.kinds = kinds;
	}
	//修改农场的名字
	public void setFarm_Name(String farm_name)
	{
		Farm.farm_name = farm_name;
	}
	//设置农场的面积
	public void setFarm_Square(double square)
	{
		this.square = square;
	}
	//修改农场植物数量
	public void setKinds(int kinds)
	{
		this.kinds = kinds;
	}
	public void Show()
	{
		System.out.println("我是外部类!");
	} 
	
	//定义Farm类的内部类Plant
	class Plant				//这里的内部类是<默认访问权限>,只能在同一个包下访问
	{	
		private String plant_name;			//该农场特有的植物名称
		private double price;				//该植物的单价
		
		public Plant(String Plant_Name , double price)
		{
			this.plant_name = Plant_Name;
			this.price = price;
		}

		public void show()
		{
			System.out.println("我是内部类!");
		}
		
		public void speak()
		{
			System.out.println(Plant.this.plant_name + "是" + Farm.farm_name + "所特有的蔬菜品种" + "价格是" +Plant.this.price); //在内部类使用外部类的成员时, 
		}	
}	
}								

上述例子中,类Plant就是类Farm的内部类,看起来就像是类Farm的一个成员。

创建成员内部类的两种方法<直接贴代码>

先在Farm类中添加一个方法

	//返回内部类对象
	public Plant r_Plant(String Plant_Name , double price)
	{
		return new Plant(Plant_Name,price);
	}

来看看创建成员内部类的两种具体方法

public class Test
{
	public static void main(String[] args) 
	{
		//法一 
		Farm farm = new Farm("天然有机农场" , 19878 , 1000);
		Farm.Plant plant1 =  farm.new Plant("苹果", 7.80);	//必须通过farm对象来创建
		
		//法二
		Farm.Plant plant2 = farm.r_Plant("香蕉苹果", 5.30);

	}

}
  • 内部类可以无限制的访问外部类的所有成员(包括private和static)
  • 外部类不能访问内部类的private属性的成员,只能通过内部类的对象去访问。
    下面来看看一看内部类和外部类之间的相互调用

这里只给出部分代码,其他代码和上面的一样。

外部类调用内部类的成员
public class Farm 
{
	//访问内部类
	public void toShow_In()
	{
		plant = new Plant("白萝卜", 1.20);		//创建内部类对象的引用
		plant.show();							//访问内部类的成员方法
		plant.speak();
		//修改内部类成员变量
		plant.plant_name = "卷心菜";
		plant.price = 1.75;
		System.out.println("修改内部类之后的结果");
		plant.speak();
	}
}

在主方法中测试后的输出结果 <读者可自行尝试>
我是内部类!
白萝卜是天然有机农场所特有的蔬菜品种,价格是1.2
修改内部类之后的结果
卷心菜是天然有机农场所特有的蔬菜品种,价格是1.75

内部类调用外部类成员
	class Plant				
	{	
		//内部类可以访问外部类的所有成员
		public void toShow_Out()
		{
			System.out.println("农场的名字是:" + Farm.farm_name);		//访问static属性的成员变量
			System.out.println("农产的面积为:" + Farm.this.square);	//访问private属性的成员变量
			Farm.farm_name = "有机农场";								//修改外部类的static属性的成员变量
			System.out.println("修改之后结果为:" + Farm.farm_name);
			//这里注意比较两者的输出结果
			Farm.this.Show();
			this.show();
		
		}
	}

在主方法中测试后的输出结果 <读者可自行尝试>
农场的名字是:天然有机农场
农产的面积为:19878.0
修改之后结果为:有机农场
我是外部类!
我是内部类!

  • 成员内部类不能定义static类型的成员(但是静态内部类可以)
class Plant
	{
		//static int m;						//该语句错误,成员内部类不能定义static类型的成员
		private String plant_name;			//该农场特有的蔬菜名称
		private double price;				//该蔬菜的单价
		/*
		public static void to_show()
		{
			/*错误  成员内部类不能定义static方法*/
		}
		*/
	}

成员内部类的访问权限
成员内部类前可加上四种访问修饰符。

private:仅外部类可访问
protected:同包下或继承类可访问
默认访问权限:同包下可访问
public:所有类可访问

1.局部内部类(实例内部类)

定义在类的一个方法或者更小的代码块中。局部内部类使用的情况比较少,而且不在定义类的定义域之内便无法使用,其提供的功能使用匿名内部类都可以实现,而匿名内部类可以写得比它更简洁,因此局部内部类用的比较少

  *局部内部类不能用private或者public修饰。因为局部内部类相当于局部变量,他的作用域在方法体内部。所以只能在方法体内部定义他的对象。
  *同成员内部类,局部内部类可以访问外部类的所有成员,但是他不能访问所在方法的局部变量,除非该局部变量被final修饰
  *局部内部类同样不能用static修饰,也不能有static属性的成员
  *局部内部类对象的创建只能在其所在的方法体或所在的代码块内。
  *外部类不能访问局部内部类,因为局部内部类的作用域只在所在的方法体或者代码块内,但是局部内部类却可以访问外部类的所有成员。

由于局部内部类和成员内部类很类似,所以这里就直接上代码。

public class Out 
{
	private   int x1 = 1;
	protected int x2 = 2;
	int x3 = 3;
	static int x4 = 4;
	
	public Out()
	{
		 System.out.println("创建 " + this.getClass().getSimpleName() + " 对象");
	}
	
	//局部内部类
	public void create_inClass(int a)
	{
		//局部变量
		int y1 = 10;
		class A				//局部内部类A,其作用域只在该方法体内  注意:public/private class A 语句错误
		{
			//static int a2 = 0;		该语句错误  局部内部类不能定义static类型的变量
			private int a1;
			public A()
			{
				A.this.a1 = a;
				System.out.println("创建 " + A.class.getSimpleName() + " 对象");
				System.out.println("类A的成员a1的值为:" + A.this.a1);
				System.out.println("其外部类的 x1 值为: " + Out.this.x1);
                System.out.println("其外部类的 x2 值为: " + Out.this.x2);
                System.out.println("其外部类的 x3 值为: " + Out.this.x3);
                System.out.println("其外部类的 x4 值为: " + Out.x4);	
			
			}
			
			public void toshow()
			{
				System.out.println("局部变量y1的值为:" + y1);
				System.out.println("参数a的值为:" + a);
			}
			
		}
		//创建局部内部类A
		A class_a = new A();
		class_a.toshow();
		
		//在代码块内定义局部内类
		if (true)
		{
			class B
			{
				private int b;
				public B()
				{
					B.this.b = a;
					System.out.println("创建 " + B.class.getSimpleName() + " 对象");
					System.out.println("类B的成员b的值为:" + B.this.b);
					System.out.println("其外部类的 x1 值为: " + Out.this.x1);
	                System.out.println("其外部类的 x2 值为: " + Out.this.x2);
	                System.out.println("其外部类的 x3 值为: " + Out.this.x3);
	                System.out.println("其外部类的 x4 值为: " + Out.x4);	
				
				}
				
				public void toshow()
				{
					System.out.println("局部变量y1的值为:" + y1);
				}
			}
			B b = new B();
			b.toshow();
			
		}
		//B b = new B();			该语句就错误,超出了类B的作用域
	}

}

由上面的例子可以看出,局部内部类的作用于只在他所在的方法体或代码块中.
来看看一看运行结果:

创建 Out 对象
创建 A 对象
类A的成员a1的值为:100
其外部类的 x1 值为: 1
其外部类的 x2 值为: 2
其外部类的 x3 值为: 3
其外部类的 x4 值为: 4
局部变量y1的值为:10
参数a的值为:100
创建 B 对象
类B的成员b的值为:100
其外部类的 x1 值为: 1
其外部类的 x2 值为: 2
其外部类的 x3 值为: 3
其外部类的 x4 值为: 4
局部变量y1的值为:10

这里特别强调一点:

//局部内部类
	public void create_inClass(final int a)		//这里必须加上final 
	{
		//局部变量
		int y1 = 10;
		class A				//局部内部类A,其作用域只在该方法体内  注意:public/private class A 语句错误
		{
			//下面的代码同上
这里必须是final int a才行

3.静态内部类
  有了以上两种类作为铺垫,静态内部类 就很好理解了。
  类的静态成员不依附与某个类的具体对象,它是属于这整个类的。那么静态内部类就同理,可以将它看做是某个类的静态成员,只要在具有访问权限的地方,我们就可以通过 类名.静态成员名 的形式来访问这个静态成员。同时建立他的对象也不需要依赖于外部类的对象。

  • 这里强调一点:静态内部类不能访问外部类的非静态成员。因为外部类的非静态成员是依附于具体对象的,但是局部内部类不依附于具体的对象。

这里就直接贴代码。静态内部类和成员内部类的主要区别就在于前者不需要依赖于外部类对象。

public class Static_Inclass 
{
	private int a = 1;
	protected String s = "我是外部类";
	int b = 100;
	static String s1 = "我是外部类的静态成员";
	
	
	public void toShow()
	{
		System.out.println("创建 " + this.getClass().getSimpleName() + " 对象");
        // 创建静态内部类对象
	}
	static public void show()
	{
		System.out.println("我是外部类");
	}
	
	public void print()
	{
		System.out.println("创建 " + this.getClass().getSimpleName() + " 对象");
        // 创建静态内部类对象
		A a = new A();
		//静态内部类可以访问外部类的所有静态成员
		a.show_out();
		
	}
	//静态内部类A
	static public class A
	{
		private int y = 2;
		protected double m  = 0.12;
		String str = "我是内部类的静态成员";
		static int n = 0;
		
		public A()
		{
			System.out.println("我是内部类");
			System.out.println("外部类的静态成员s1为:" + Static_Inclass.s1);
			//该语句错误  因为静态内部类不能访问外部类的非静态成员
			//System.out.println("外部类的非静态成员a为:" + Static_Inclass.this.a);
		}
		
		public void show_out()
		{
			//访问外部类的所有静态成员 
			System.out.println("静态内部类可以访问外部类所有static成员");
			Static_Inclass.show();
			//Static_Inclass.toshow();  该语句错误
			System.out.println("外部类的静态成员s1为:" + Static_Inclass.s1);
			
		}
		
	}
	public static void main(String[] args) 
	{
		//直接创建内部类,不需要外部类成员
		Static_Inclass.A a = new Static_Inclass.A();
		Static_Inclass b = new Static_Inclass();
		b.print();
		
	}
}

结果如下:

我是内部类
外部类的静态成员s1为:我是外部类的静态成员
创建 Static_Inclass 对象
我是内部类
外部类的静态成员s1为:我是外部类的静态成员
静态内部类可以访问外部类所有static成员
我是外部类
外部类的静态成员s1为:我是外部类的静态成员

4.匿名内部类
  所谓的匿名内部类,字面意思就是没有名字的类,他不能创建对象。
  简单点理解,可以将匿名类看成是某个类的子类或者某个接口的实现类,只不过不是单独的去定义,而是在有需要的时候去定义使用,可以简化编程。

通常情况下,一个类A,我们有的时候需要类A的某个子类所创建的对象,但是这个子类使用的次数不多,我们就没有必要去定义这个子类,这个时候匿名类就派上用场了。

  • 注意:匿名内部类必须继承一个父类或实现一个接口。但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
    *匿名类可以看成是某个类的子类或者实现某一接口的类。
    *匿名类可以继承也可以重写父类的方法。
    *匿名类中不能定义static类型的成员。
    *由于匿名类没有名字,他自己就没有构造方法,所以他必须使用父类的构造方法。
    *匿名类自己的成员变量要放在代码块中初始化。
    *匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效

下面看看具体的例子

abstract  class Animal 
{
	abstract public void speak();			//动物叫声
	abstract public void getName();			//动物的名字
	abstract public void eat();				//动物的食物
	abstract public void show();
}
public class Test
{
	public static void main(String[] args) 
	{
		//创建Animal的匿名类
		Animal animal1 = new Animal() 
		{
			private int age ;					//猫的年龄
			private double weight;				//猫的体重
			//必须在代码块中初始化匿名类变量
			{
				this.age = 3;
				this.weight = 2.3;
				
			}
			 public void speak()			//动物叫声
				 {
					 System.out.println("miaomiao");
				 }
				 public void getName()			//动物的名字
				 {
					 System.out.println("Cat");
				 }
				 public void eat()				//动物的食物
				 {
					 System.out.println("Fish"); 
				 }
				 public void show()
				 {
					 System.out.println("我的年龄是:" + this.age + "我的体重是:" + this.weight);
				 }
		};
		animal1.eat();
		animal1.speak();
		animal1.getName();
		animal1.show();
	}
}

这里要是不用匿名类的话,就得单独创建一个子类Cat,但是使用匿名类的话就显得很方便。

当然了,匿名类还可以实现某个接口,这里就不再重复了,方法大体上类似。而且可以在需要的地方使用,可以使得代码更加简洁。

如果笔者的这篇博客对您有所帮助的话,请老铁给个赞,让更多的人看到~~~一个Java小白,如有不当,还请各位道友指正。

你可能感兴趣的:(Java内部类详解)