李兴华Java8笔记19:内部类详解

1.基本概念

内部类就是指,在已经定义了一个类的基础之上,再其内部又定义了一个或多个类。从开发的角度,内部类,能少用就少用,优先考虑普通类。下面是一个内部类的代码实例:

class Outer{
	private String msg = "hello world";
	class Inner{
		public void fun(){
			System.out.println(msg);
		}
	}
	public void fun(){
		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){
		Outer out = new Outer();
		out.fun();	//输出hello world
	}
}

使用内部类虽然牺牲了结构的简洁性,但是达到了一个很好的目的。为了凸显内部类的特点,我们将内部类拿到外面来,并实现与之前一样的功能。

class Outer{
	private String msg = "hello world";
	
	public String getMsg(){
		return this.msg;
	}

	public void fun(){
		new Inner().fun();
	}
}

class Inner{
	public void fun(){
		System.out.println(new Outer().getMsg());
	}
}

public class Hello{
	public static void main(String[] args){
		Outer out = new Outer();
		out.fun();	//输出hello world
	}
}

将内部类拿出来之后,为了能够使得内部类能够访问外部类的属性,我们做了如下两个改变:

  • 在外部类定义一个getter方法
  • 内部类使用外部类的属性的时候,先实例化一个外部类对象

虽然说结果上达到了将内部类放在外部类里面的一样的效果,但是我们发现,程序中实例化了两个outer对象,这是我们不想看到的结果。

因此,内部类的一大优势就是能够轻松访问外部类中的私有操作。当然,内部类的好处不止这一个:虽然内部类可以轻松访问外部类的私有操作,反之,外部类也可以访问内部类的私有操作。

class Outer{
	private String msg = "hello world";
	
	public String getMsg(){
		return this.msg;
	}

	class Inner{
		private String info = "世界,你好!";
	}

	public void fun(){
		Inner in = new Inner();
		System.out.println(in.info);
	}
}

public class Hello{
	public static void main(String[] args){
		Outer out = new Outer();
		out.fun();	//输出世界你好
	}
}

内部类的使用,使得私有属性的操作变得很方便,但是新的问题出现了,在内部类之中访问外部类属性的时候,直接写了属性的名,但是之前我们说的,只要类中访问属性,就应该用this关键字,但是如果再内部类中使用this调用外部类的属性,就会报错,因为this指的是当前对象,此时的当前对象就是内部类,但是内部类中没有外部类的属性,所以就会报错,但是解决办法也很简单:Outer.this.mag。

class Outer{
	private String msg = "hello world";
	class Inner{
		public void fun(){
			System.out.println(Outer.this.msg);
		}
	}
	public void fun(){
		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){
		Outer out = new Outer();
		out.fun();	//输出hello world
	}
}

上面代码编译后,我们文件目录查看*.class的文件,会发现除了Hello.class、Outer.class之外,还有一个Outer$Inner.class,也就是说,内部类也会被编译成一个class文件,并且这里的$在程序中就是.的意思。那我们能不能像实例化一个没有内部类的对象一样,仅仅实例化一个内部类对象呢?当然可以,语法如下:

外部类.内部类 对象名 = new 外部类().new 内部类()
class Outer{
	private String msg = "hello world";
	class Inner{
		public void fun(){
			System.out.println(Outer.this.msg);
		}
	}
	public void fun(){
		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){
		Outer.Inner in = new Outer().new Inner();
		in.fun();
	}
}

内部类不可能离开外部类的实例化对象,所以应该首先实例化外部类。

如果希望一个内部类只允许外部类调用,而不允许外面调用,那么可以用private关键词对内部类进行修饰。那么此时内部类就不可能在外部进行直接实例化对象,下面的程序就会出错。

class Outer{
	private String msg = "hello world";
	private class Inner{
		public void fun(){
			System.out.println(Outer.this.msg);
		}
	}
	public void fun(){
		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){
		Outer.Inner in = new Outer().new Inner();
		in.fun();
	}
}

错误信息如下:

Hello.java:14: 错误: Outer.Inner 在 Outer 中是 private 访问控制
		Outer.Inner in = new Outer().new Inner();
		     ^

2. 使用static定义内部类

使用static定义的属性或方法,不受类的实例化对象的控制。所以如果用static定义了一个内部类,那么它就不会受到外部类的实例化对象的控制。

如果一个内部类由static定义,那么这个类就变成了一个外部类。并且只能够访问外部类中用static方法或者属性。这就相当于static定义的方法不能调用非static定义的属性和方法。

class Outer{
	private static String msg = "hello world";
	//static修饰的内部类
	static class Inner{
		public void fun(){
			//这里会报错,因为static定义的类不能访问,非static属性
			System.out.println(msg);	
		}
	}
	public void fun(){
		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){

	}
}

要想修复这个bug,只需要用static修饰外部类中的msg变量。

此时,如果想实例化一个内部类的对象该如何做?下面是语法

外部类.内部类 对象名 = new 外部类.内部类()
class Outer{
	private static String msg = "hello world";
	//static修饰的内部类
	static class Inner{
		public void fun(){
			//这里会报错,因为static定义的类不能访问,非static属性
			System.out.println(msg);	
		}
	}
	public void fun(){
		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){
		Outer.Inner in  = new Outer.Inner();
		in.fun();
	}
}

以后看到可以直接之力华“类.类.类”的形式,知道这是在实例化有static定义的内部类就行了

3.在方法中定义内部类

内部类可以再类中、代码块中、方法中定义,其中在方法内定义内部类是最常用形式。

class Outer{
	private String msg = "hello world";

	public void fun(){
		//方法内定义的内部类
		class Inner{
			public void fun(){
				//这里会报错,因为static定义的类不能访问,非static属性
				System.out.println(msg);	
			}
		}

		new Inner().fun();
	}
}

public class Hello{
	public static void main(String[] args){
		Outer out = new Outer();
		out.fun();	//输出hello world
	}
}

除了可以访问外部类的属性,在方法中定义的内部类还可以访问方法中的参数和变量

class Outer{
	private String msg = "hello world";
    
	public void fun(int num){
		Double score = 99.9;
		//方法内定义的内部类
		class Inner{
			public void fun(){
				//这里会报错,因为static定义的类不能访问,非static属性
				System.out.println("外部类属性是:"+Outer.this.msg);	
				System.out.println("方法参数是:"+num);	
				System.out.println("方法属性是:"+score);	
			}
		}

		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){
		Outer out = new Outer();
		out.fun(100);	
	}
}

但这种操作只支持jdk1.8以后,1.8之前要想访问的话,需要在参数或变量前加上final:

class Outer{
	private String msg = "hello world";
    
	public void fun(final int num){
		final Double score = 99.9;
		//方法内定义的内部类
		class Inner{
			public void fun(){
				//这里会报错,因为static定义的类不能访问,非static属性
				System.out.println("外部类属性是:"+Outer.this.msg);	
				System.out.println("方法参数是:"+num);	
				System.out.println("方法属性是:"+score);	
			}
		}

		new Inner().fun();
	}
}
public class Hello{
	public static void main(String[] args){
		Outer out = new Outer();
		out.fun(100);	
	}
}

4.总结

  • 内部类可以与外部类互相进行私有属性的访问。
  • 内部类可以使用private关键字进行修饰,而后无法在外部实例化内部类的实例化对象,要想定义使用下面的语法结构:
    • 外部类.内部类 实例化对象 = new 外部类().new 内部类()
  • 内部类可以使用static关键字进行修饰,而后可以脱离外部实例化对象的限制。此时直接实例化内部类对象的形式为
    • 外部类.内部类 实例化对象 = new 外部类.内部类()
  • 内部类可以在方法中定义,这是在开发中用的比较多的。
第1章 JAVA WEB开发简介 1.1、WEB发展历程 1.2、企业开发架构 1.3、JAVA EE架构 1.4、JAVA EE核心设计模式 1.5、Struts开发框架 1.6、本章摘要 1.7、开发实战讲解 第2章 HTML、JavaScript简介 2.1、服务器与浏览器 2.2、HTML简介 2.2.1、HTML元素概览 2.2.2、创建显示WEB页 2.2.3、创建表单WEB页 2.3、JavaScript简介 2.3.1、JavaScript的基本语法 2.3.2、事件处理 2.3.3、window对象 2.4、本章摘要 2.5、开发实战讲解 第3章 XML简介 3.1、认识XML 3.2、XML解析 3.2.1、DOM解析操作 3.2.2、SAX解析操作 3.2.3、XML解析的好帮手:JDOM 3.2.4、最出色的解析工具:DOM4J 3.3、使用JavaScript操作DOM 3.4、开发实战讲解(基于Oracle数据库) 第4章 Tomcat服务器的安装及配置 4.1、Web容器简介 4.2、Tomcat简介 4.3、Tomcat服务器的下载及配置 4.3.1、Tomcat下载 4.3.2、Tomcat安装 4.3.3、服务器配置 4.4、编写第一个jsp文件 4.5、交互性 4.6、本章摘要 4.7、开发实战讲解 第5章 JSP基础语法 5.1、JSP注释 5.2、Scriptlet 5.2.1、第一种Scriptlet: 5.2.2、第二种Scriptlet: 5.2.3、第三种Scriptlet: 5.3、Scriptlet标签 5.4、page指令 5.4.1、设置页面的MIME 5.4.2、设置文件编码 5.4.3、错误页的设置 5.4.4、数据库连接操作 5.5、包含指令 5.5.1、静态包含 5.5.2、动态包含 5.6、跳转指令 5.7、实例操作:用户登陆程序实现(JSP + JDBC实现) 5.7.1、创建数据库表 5.7.2、程序实现思路 5.7.3、程序实现 5.8、本章摘要 5.9、开发实战讲解(基于Oracle数据库) 第6章 JSP内置对象 6.1、JSP内置对象概览 6.2、四种属性范围 6.2.1、page属性范围(pageContext范围) 6.2.2、request属性范围 6.2.3、session属性范围 6.2.4、application属性范围 6.2.5、深入研究page属性范围 6.3、request对象 6.3.1、乱码解决 6.3.2、接收请求参数 6.3.3、显示全部的头信息 6.3.4、角色验证 6.3.5、其他操作 6.4、response对象 6.4.1、设置头信息 6.4.2、页面跳转 6.4.3、操作Cookie 6.5、session对象 6.5.1、取得Session Id 6.5.2、登陆及注销 6.5.3、判断新用户 6.5.4、取得用户的操作时间 6.6、application对象 6.6.1、取得虚拟目录对应的绝对路径 6.6.2、范例讲解:网站计数器 6.6.3、查看application范围的属性 6.7、WEB安全性及config对象 6.7.1、WEB安全性 6.7.2、config对象 6.8、out对象 6.9、pageContext对象 6.10、本章摘要 6.11、开发实战讲解(基于Oracle数据库) 第7章 JavaBean 7.1、JavaBean简介 7.2、在JSP中使用JavaBean 7.2.1、WEB开发的标准目录结构 7.2.2、使用JSP的page指令导入所需要的JavaBean 7.2.3、使用指令 7.3、JavaBean与表单 7.4、设置属性: 7.4.1、设置指定的属性 7.4.2、指定设置属性的参数 7.4.3、为属性设置具体内容 7.5、取得属性: 7.6、JavaBean的保存范围 7.6.1、page范围的JavaBean 7.6.2、request范围的JavaBean 7.6.3、session范围的JavaBean 7.6.4、application范围的JavaBean 7.7、JavaBean的删除 7.8、实例操作:注册验证 7.9、DAO设计模式 7.9.1、DAO设计模式简介 7.9.2、DAO开发 7.9.3、JSP调用DAO 7.10、本章摘要 7.11、开发实战讲解(基于Oracle数据库) 第8章 文件上传 8.1、smartupload上传组件 8.1.1、上传单个文件 8.1.2、混合表单 8.1.3、为上传文件自动命名 8.1.4、批量上传 8.2、FileUpload 8.2.1、使用FileUpload接收上传内容 8.2.2、保存上传内容 8.2.3、开发FileUpload组件的专属操作类 8.3、本章摘要 8.4、开发实战讲解(基于Oracle数据库) 第9章 Servlet程序开发 9.1、Servlet简介 9.2、永远的“HelloWorld”:第一个Servlet程序 9.3、Servlet与表单 9.4、Servlet生命周期 9.5、取得初始化配置信息 9.6、取得其他内置对象 9.6.1、取得HttpSession实例 9.6.2、取得ServletContext实例 9.7、Servlet跳转 9.7.1、客户端跳转 9.7.2、服务器端跳转 9.8、WEB开发模式:Mode I与Mode II 9.8.1、Mode I 9.8.2、Mode II:Model-View-Controller 9.9、实例操作:MVC设计模式应用 9.10、过滤器 9.10.1、过滤器的基本概念 9.10.2、实现过滤器 9.10.3、过滤器的应用 9.11、监听器 9.11.1、对application监听 9.11.2、对session监听 9.11.3、对request监听 9.11.4、监听器实例 —— 在线人员统计 9.12、本章摘要 9.13、开发实战讲解(基于Oracle数据库) 第10章 表达式语言 10.1、表达式语言简介 10.2、表达式语言的内置对象 10.2.1、访问四种属性范围的内容 10.2.2、调用内置对象操作 10.2.3、接收请求参数 10.3、集合操作 10.4、在MVC中应用表达式语言 10.5、运算符 10.6、本章摘要 10.7、开发实战讲解(基于Oracle数据库) 第11章 Tomcat数据源 11.1、数据源操作原理 11.2、在Tomcat中使用数据库连接池 11.3、查找数据源 11.4、本章摘要 第12章 JSP标签编程 12.1、标签编程简介 12.2、定义一个简单的标签 —— 空标签 12.3、定义有属性的标签 12.4、TagSupport类 12.5、定义有标签体的标签库 12.6、开发迭代标签 12.7、BodyTagSupport类 12.8、TagExtraInfo类和VariableInfo类 12.9、使用BodyTagSupport开发迭代输出 12.10、简单标签 12.11、DynamicAttributes接口 12.12、本章摘要 第13章 标准标签库(JSTL) 13.1、JSTL简介 13.2、安装JSTL 1.2 13.3、核心标签库 13.3.1、标签 13.3.2、标签 13.3.3、标签 13.3.4、标签 13.3.5、标签 13.3.6、、、标签 13.3.7、标签 13.3.8、标签 13.3.9、标签 13.3.10、标签 13.3.11、标签 13.4、国际化标签库 13.4.1、标签 13.4.2、标签 13.4.3、读取资源文件 13.4.4、数字格式化标签 13.4.5、日期时间格式化标签 13.4.6、设置时区 13.5、SQL标签库 13.5.1、 13.5.2、数据库操作标签 13.5.3、事务处理 13.6、XML标签库 13.6.1、XPath简介 13.6.2、标签 13.6.3、标签 13.6.4、标签 13.6.5、标签 13.6.6、、、标签 13.6.7、标签 13.7、函数标签库 13.8、本章摘要 13.9、开发实战讲解(基于Oracle数据库) 第14章 AJAX开发技术 14.1、AJAX技术简介 14.2、XMLHttpRequest对象 14.3、第一个AJAX程序 14.4、异步验证 14.5、返回XML数据 14.6、本章摘要 14.7、开发实战讲解(基于Oracle数据库) 第15章 Struts基础开发 15.1、Struts简介 15.2、配置Struts开发环境 15.3、开发第一个Struts程序 15.4、Struts工作原理 15.5、深入Struts应用 15.6、本章摘要 15.7、开发实战讲解(基于Oracle数据库) 第16章 Struts常用标签库 16.1、Struts标签库简介 16.2、Bean标签 16.2.1、标签 16.2.2、标签 16.2.3、资源访问标签 16.2.4、标签 16.2.5、标签 16.2.6、标签 16.2.7、国际化与标签 16.3、Logic标签 16.3.1、标签和标签 16.3.2、标签和标签 16.3.3、关系运算标签 16.3.4、标签 16.3.5、重定向标签: 16.4、Html标签 16.4.1、<html:form>标签 16.4.2、<html:text>与<html:password>标签 16.4.3、<html:radio>标签 16.4.5、<html:textarea>标签 16.4.6、<html:hidden>标签 16.4.7、按钮标签 16.4.8、实例:编写基本表单 16.4.9、复选框标签 16.4.10、下拉列表框 16.5、本章摘要 16.6、开发实战讲解(JSP + Oracle) 第17章 Struts高级开发 17.1、Struts多人开发 17.2、Token 17.3、文件上传 17.4、动态ActionForm 17.5、Action深入 17.5.1、ForwardAction 17.5.2、IncludeAction 17.5.3、DispatchAction 17.6、验证框架 附录A:实用工具 18.1、JavaMail 18.1.1、James邮件服务器的下载及配置 18.1.2、JavaMail简介及配置 18.1.3、发送普通邮件 18.1.4、发送带附件的HTML风格邮件 18.2、操作Excel文件 18.2.1、JExcelAPI简介 18.2.2、创建一个Excel文件 18.2.3、读取Excel文件 18.2.4、格式化文本 18.3、本章摘要 附录B:MyEclipse开发工具 19.1、MyEclipse简介 19.2、MyEclipse的安装 19.3、MyEclipse的使用 19.4、配置Tomcat服务器 19.5、MyEclipse卸载 19.6、本章摘要 附录C:HTTP状态码及头信息 20.1、HTTP状态码 20.2、HTTP头信息
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值