黑马程序员——Java基础——内部类

------<a href="http://www.itheima.com" target="blank">Java培训、Android培训、iOS培训、.Net培训</a>、期待与您交流! -------


什么是内部类,简单来说就是一个外部类的内部又定义了一个类,那为什么需要内部类呢?

因为内部类可以直接访问外部类中的成员,包括私有。用现实的例子描述就是一个人是由大脑、肢体、器官等身体结果组成,而内部类相当于其中的某个器官之一,例如心脏,它也有自己的属性和行为(血液、跳动),心脏可以直接访问身体的血液,而不是通过医生来抽血,这时不能用属性或者方法表示一个心脏,而是用一个类

内部类可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式 外部类名.this

外部类要访问内部类,必须建立内部类对象

内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。所以内部类的成员变量/方法名可以和外部类的相同。

1.成员内部类

就是将内部类定义在外部类的成员位置,而且非私有,可以在外部其他类直接建立内部类对象。格式:

外部类名.内部类名  变量名 = 外部类对象.内部类对象;
 Outer.Inner in = new Outer().new Inner();

开头的Outer是为了标明需要生成的内部类对象在哪个外部类当中。必须先有外部类的对象才能生成内部类的对象,因为内部类的作用就是为了访问外部类中的成员变量。

//定义外部类
class Outer
{
	//定义内部类
	class Inner
	{
		void show()
		{
			System.out.println("内部类运行...");
		}
	}
}


public class InnerClassDemo {

	public static void main(String[] args) {
		
		//在外部其他类建立内部类对象
		Outer.Inner in = new Outer().new Inner();
		in.show();
	}

}


当内部类在成员位置上,就可以被成员修饰符所修饰。
private:将内部类在外部类中进行封装。如同是,我的心脏只能由我的身体控制,其他人无法直接访问它

static:内部类就具备static的特性。当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。

在外部其他类中,如何直接访问static内部类的非静态成员呢?
new Outer.Inner().function();

在外部其他类中,如何直接访问static内部类的静态成员呢?
Outer.Inner.function();

 注意:当内部类中定义了静态成员,该内部类必须是static的。
       当外部类中的静态方法访问内部类时,内部类也必须是static的。

//定义外部类
class Outer
{
	//内部类被static修饰后,只能直接访问外部类中的static成员
	private static int num = 2;
	static class Inner
	{
		static void show()
		{
			System.out.println("内部类运行..."+num);
		}
	}
}




public class InnerClassDemo {

	public static void main(String[] args) {
		Outer.Inner.show();
	}

}


2.局部内部类

内部类定义在外部类中的某个方法中,创建了这个类型的对象时,且仅使用了一次,那么可在这个方法中定义局部类。

不可以被成员修饰符修饰,如public、private、static等修饰符修饰。它的作用域被限定在了声明这个局部类的代码块中

可以直接访问外部类中的成员,因为还持有外部类中的引用。

但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。为什么呢?

因为局部内部类对象和局部变量的生命周期不同,内部类需要复制局部变量为内部类的一个成员变量,为了保证局部变量和该副本的值的一致性,所以要将修饰符设为final。

//定义外部类
class Outer
{
	//局部内部类访问局部变量必须用final修饰
	void show(final int num)
	{	
		//内部类定义在外部类方法内
		class Inner
		{
			void show()
			{
				System.out.println("内部类运行..."+num);
			}
		}
		//访问语句必须在定义类局部内部类之后
		new Inner().show();
	}
}


public class InnerClassDemo {

	public static void main(String[] args) {
		
		Outer out = new Outer();
		out.show(3);//内部类运行...3
		out.show(4);//内部类运行...4

	}

}


3.匿名内部类

没有名字的内部类。就是内部类的简化形式。一般只用一次就可以用这种形式简化书写。

定义匿名内部类的前提:内部类必须是继承一个类或者实现接口。
匿名内部类的格式:  new 父类或者接口(){定义子类的内容}
其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。 可以理解为带内容的对象。
匿名内部类中定义的方法最好不要超过3个。

public class InnerClassDemo {

	public static void main(String[] args) {
		
		//编译通过,运行
		new Object(){
			void show(){
				System.out.println("show run");				
			}
		}.show();
		
		//编译失败,因为匿名内部类是一个子类对象,当用Object的obj引用指向时,
		//就被提升为了Object类型,而编译时检查Object类中是否有show方法

		Object obj = new Object(){
			void show(){
				System.out.println("show run");
			}
		};
		obj.show();
	}

}

从上面这个例子可以看出,匿名内部类就是参照多态的表达形式,用父类引用接收一个子类对象,编译运行参照多态的规则。

4.匿名内部类的扩展

可以通过匿名内部类的方式实现多重继承

//创建一个使用继承的类
abstract class Normal
{
	abstract void methodNomal();
}
//创建一个使用匿名内部类的类
abstract class Outer
{
	abstract void methodOuter();
}

//创建实现多重继承的类
class Multi extends Normal
{

	//复写父类的方法
	@Override
	void methodNomal() {
		System.out.println("normal method ...");
		
	}
	
	//创建返回匿名内部类对象的方法
	public Outer getOuter(){
		
		return new Outer(){

			@Override
			void methodOuter() {
				
				System.out.println("Outer method...");
			}
			
		};
	}
}

public class InnerClassDemo {

	public static void main(String[] args) {
		 
		//实现一个类的多重继承,调用方法
		Multi m = new Multi();
		m.methodNomal();
		m.getOuter().methodOuter();
	}
}


5.继承内部类

在学习了内部类的基础知识后,产生了一个疑问,既然内部类也是一个类,那它能不能被继承呢

//定义外部类
class Outer
{
	//定义内部类
	class Inner
	{
		Inner()
		{
			System.out.println("内部类运行...");
		}
	}
}
//继承时需要指定外部类名称
class ExtendsClass extends Outer.Inner
{
	//ExtendsClass();无法通过编译
	//构造函数需要传递外部类对象
	ExtendsClass(Outer out)
	{
		//调用内部类的构造函数
		out.super();
	}
}

public class InnerClassDemo {

	public static void main(String[] args) {
		 
		//创建外部类对象,并传入继承类的构造函数,完成初始化
		Outer out = new Outer();
		ExtendsClass ex = new ExtendsClass(out);
	}
}


上面就是继承内部类的代码,为什么要这样写?

继承内部类后,需要调用内部类的默认构造函数,但是加载内部类必须先加载外部类,所以要给继承类的构造函数传入外部类的对象,然后通过外部类.super()来调用内部类的默认构造函数完成初始化。









评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值