Java学习系列(二十三)Java面向对象之内部类详解

一、前言

内部类也称寄生类,就是把一个类放在类里面(即内部类的上一级程序单元是类)定义,将其作为外部类的成员。内部类主要用几种定义形式:静态(static)内部类,非静态内部类,匿名内部类(也就是没有名字的寄生类)。内部类的好处就是内部类可以直接外部类的(包括私有)成员,反之不能。下面我们通过一些实例来详细讲解一下Java中内部类的使用及几种定义形式的相互调用。

二、实例说明

(1)匿名内部类:当程序创建匿名内部类时,会立即创建匿名内部类(实现类)的实例。

interface IBreathe {
	void breathe();
}

/**
 * 匿名内部类的使用,定义形式如下:
 *
 * new 接口() | 父类构造器<参数>){
 * 		// 类体部分...
 * };
 *
 * @author [*昨日重现*] [email protected]
 * @since version 1.0
 * @datetime 2015年4月29日 下午10:17:40
 */

public class Anonymous {

	// 这里相当于创建了接口IBreathe的匿名实现类,并创建了匿名内部类的实例
	// 将实现类的实例赋值给接口变量 ,属于向上转型
	IBreathe breathe = new IBreathe() {
		// 必须实现接口里的所有抽象方法
		@Override
		public void breathe() {
			System.out.println("呼吸新鲜空气...");
		}
	};

	public static void main(String[] args) {
		Anonymous anonymous = new Anonymous();
		anonymous.breathe.breathe();
	}
}

注意以下几点:

1)只要父类是抽象类或者是一个接口,那么其子类中的方法都可以使用匿名内部类来实现;反过来也就是说使用匿名内部类有个前提:它必须显示地继承一个父类或实现一个接口。

2)匿名内部类必须实现接口或抽象类中所有的抽象方法。

3)匿名内部类适合创建只需一次使用的类。

4)匿名内部类不能有构造器而且程序以后无法再访问它,因为它没有类名。

(2)静态内部类:它属于外部类(宿主类)的静态成员,所以它不能访问外部类的非静态成员(属性、方法)。

/**
 * 外部类(宿主类)中包含静态内部类作为外部类的一个静态成员
 *
 * @author [*昨日重现*] [email protected]
 * @since version 1.0
 * @datetime 2015年4月29日 下午11:00:51
 */

public class Out {
	private static String name = "张三";
	private String sex = "男";

	static class In {
		private static String name = "李四";

		public void info() {
			// 静态内部类不能访问外部类的非静态成员,所以下面这句会编译不通过
			// System.out.println("外部类的sex = " + sex);
			System.out.println("in的info方法被调用,name:" + name);
		}
	}

	public static void main(String[] args) {
		// 打印结果(编译器遵循就近原则):in的info方法被调用,name:李四
		// 这里只需要把外部类当成静态内部类的包就行了
		// 所以In前加不加Out.都是一样的
		new In().info();
		new Out.In().info();
	}
}

如果要在外部类的外面访问静态内部类的成员:Out.In in = new Out.In(); in.info();当然,静态内部类也可以派生子类:class InSub extends Out.In {},编写和调用方式与普通类一样,这里不再赘述。下面看看重点来看看非静态内部类定义和使用。

(3)非静态内部类:在创建非静态内部类的实例前,必须先创建外部类实例,也就是说非静态内部类必须寄生在外部类的实例(Outer.this)里面。所以在创建非静态内部类的实例前,必须先创建外部类实例。 

/**
 * 非静态内部类的使用
 *
 * @author [*昨日重现*] [email protected]
 * @since version 1.0
 * @datetime 2015年4月29日 下午11:26:06
 */

public class Outer {
	int number = 10;

	// 定义非静态内部类
	class Inner {
		int number = 100;

		public void info() {
			int number = 1000;
			System.out.println("Inner内部类的info()方法被调用~");
			System.out.println("number变量的值为:" + number);// 方法的局部变量,所以为1000
			System.out.println("number变量的值为:" + this.number);// 指向寄生类成员,所以为100
			System.out.println("number变量的值为:" + Outer.this.number);// 指向宿主类成员,所以为10
		}
	}

	/**
	 * 通过外部类的方法来访问寄生类的成员(属性、方法)
	 */
	public void info() {
		System.out.println("Outer外部类的info()方法被调用~");
		Inner inner = new Inner();
		inner.info();
		System.out.println(inner.number);
	}

	public static void main(String[] args) {
		new Outer().info();
	}
}

如果在外部类的外面使用内部类,那么在创建非静态内部类的实例前,必须先创建外部类实例。

Outer outer = new Outer();

Outer.Inner in = outer.new Inner();

等价于==》Outer.Inner in2 = new Outer().new Inner();

当然非静态内部类也可以派生子类,如下:

//非静态内部类派生子类
class InnerSub extends Outer.Inner {
	public InnerSub() {
		// 由于Outer.Inner是非静态内部类,因此必须使用"宿主对象"来调用它的构造器
		new Outer().super();
	}}

三、总结

1)有static修饰的内部类属于外部类本身,没有static修饰的内部类属于类实例 。

2)记住方法是谁的,就用谁来调用。

3)没有static修饰的内部类,【必须寄生在“外部类”的实例里】;反之则寄生在外部类本身里。

4)静态内部类是寄生在类本身里面的,所以就不需要程序员理会宿主。-把外部类当成静态内部类的包就行了。

5)非静态内部类派生子类:由于子类的构造器必须调用父类构造器一次,因此必须在子类构造器中使用宿主对象来调用它的构造器。

四、结束语

关于Java中的内部类的定义和使用基本内容就这些,后面会陆续更新包括:正则表达式、Java性能优化、学习JVM等等,敬请关注。

时间: 2024-10-13 23:43:12

Java学习系列(二十三)Java面向对象之内部类详解的相关文章

Java学习系列(二十一)Java面向对象之注解详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45295947 一.前言 Java中的注解Annotation运用到很多方面,比如之前讲的单元测试中的@Test.Spring.SpringMVC还有其他框架等等.Java本身自带的注解也有一些,比如:@Override(子类要重写/覆写父类的对应方法).@Deprecated(表示方法不建议被使用).@SuppressWarnings(抑制警告)等等.当然,我们也可以自定义一些自己需要的

Java学习系列(二十)Java面向对象之反射详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45289391 前言 今天讲讲Java中的反射.我们常见的反射多用于JDBC中的加载驱动程序Class.forName("com.mysql.jdbc.Driver");.Struts的MVC.Hibernate中的ORM.Spring中的IOC还有一些其他框架等等.那它有什么好处呢?它的好处就是能够动态的创建对象和编译且能够访问某个类中的所有(包括私有)属性方法及对象的属性方法

Java学习系列(二十四)Java正则表达式详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45501777 前言 正则表达式可以说是用来处理字符串的一把利器,它是一个专门匹配n个字符串的字符串模板,本质是查找和替换.在实例演示之前先了解一下Pattern.Matcher这两个工具类,Pattern:编译好的带匹配的模板(如:Pattern.compile("[a-z]{2}");/ / 取2个小写字母):Matcher:匹配目标字符串后产生的结果(如:pattern.m

Java基础学习笔记二十三 Java核心语法之反射

类加载器 类的加载 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,链接,初始化三步来实现对这个类进行初始化. 加载就是指将class文件读入内存,并为之创建一个Class对象.任何类被使用时系统都会建立一个Class对象. 链接指的是将Java类的二进制代码合并到JVM的运行状态之中的过程.在链接之前,这个类必须被成功加载.类的链接包括验证.准备和解析等几个步骤. 验证:是否有正确的内部结构,并和其他类协调一致. 准备:负责为类的静态成员分配内存,并设置默认初始化值 解析:

java学习系列1--初识java

1. java三大版本 Java se:java的标准版本,定位在客户端,主要用于桌面应用软件的变成 Java ee:企业级版本,定位在服务器端,主要用于分布式网络程序的开发,如电子商务网站 Java me:主要应用于嵌入式系统开发,如手机和PDA的编程 2. java特点 java是跨平台的:java程序的字节码文件可以在任何具有java虚拟机的计算机或者电子设备上运行,java虚拟机中的java解释器负责将字节码文件解释成为特定的机器码进行执行. java是简单的:没有#include和#d

java集合(二)List集合之Stack详解

Stack简介 Stack是栈.它的特性是:先进后出(FILO, First In Last Out). java工具包中的Stack是继承于Vector(矢量队列)的,由于Vector是通过数组实现的,这就意味着,Stack也是通过数组实现的,而非链表.当然,我们也可以将LinkedList当作栈来使用!在“Java 集合系列06之 Vector详细介绍(源码解析)和使用示例”中,已经详细介绍过Vector的数据结构,这里就不再对Stack的数据结构进行说明了. Stack的继承关系 java

java集合(二)List集合之Vector详解

简介Vector的内部实现类似于ArrayList,Vector也是基于一个容量能够动态增长的数组来实现的,该类是JDK1.0版本添加的类,它的很多实现方法都加入了同步语句,因此是线程安全的(但Vector其实也只是相对安全,有些时候还是要加入同步语句来保证线程的安全,我们后面会有例子来说明这一点). Vector类声明如下 public class Vector<E> extends AbstractList<E> implements List<E>, Random

大数据学习系列之四 ----- Hadoop+Hive环境搭建图文详解(单机)

引言 在大数据学习系列之一 ----- Hadoop环境搭建(单机) 成功的搭建了Hadoop的环境,在大数据学习系列之二 ----- HBase环境搭建(单机)成功搭建了HBase的环境以及相关使用介绍.本文主要讲解如何搭建Hadoop+Hive的环境. 一.环境准备 1,服务器选择 本地虚拟机 操作系统:linux CentOS 7 Cpu:2核 内存:2G 硬盘:40G 说明:因为使用阿里云服务器每次都要重新配置,而且还要考虑网络传输问题,于是自己在本地便搭建了一个虚拟机,方便文件的传输以

Java学习系列(二十二)Java面向对象之枚举详解

转载请注明出处:http://blog.csdn.net/lhy_ycu/article/details/45332565 一.前言 今天我们来讲讲枚举,希望通过这篇博客大家能对枚举有个更全面的了解.枚举是一种实例(大写)数固定的类(不能再创建实例),多用于确定的状态数(如:鼠标上下左右.IM消息已读未读).类型数(如:系统.聊天.添加好友消息,我的他的).模式数(回复.评论模式,刷选.全部模式)等等.枚举和类一样,同样有抽象类.可以实现接口.可含内部类.初始化块,值得注意的是:枚举的构造器无论