Java知多少(37)静态内部类、匿名内部类、成员式内部类和局部内部类
成员式内部类
在外部类内部直接定义(不在方法内部或代码块内部)的类就是成员式内部类,它可以直接使用外部类的所有变量和方法,即使是 private 的。外部类要想访问内部类的成员变量和方法,则需要通过内部类的对象来获取。
请看下面的代码:
public class Outer{
private int size;
public class Inner {
public void dostuff() {
size++;
}
}
public void testTheInner() {
Inner in = new Inner();
in.dostuff();
}
}
成员式内部类如同外部类的一个普通成员。
成员式内部类可以使用各种修饰符,包括 public、protected、private、static、final 和 abstract,也可以不写。
若有 static 修饰符,就为类级,否则为对象级。类级可以通过外部类直接访问,对象级需要先生成外部的对象后才能访问。
非静态内部类中不能声明任何 static 成员。
内部类可以相互调用,例如:
成员式内部类的访问
class A {
// B、C 间可以互相调用
class B {}
class C {}
}
内部类的对象以成员变量的方式记录其所依赖的外层类对象的引用,因而可以找到该外层类对象并访问其成员。该成员变量是系统自动为非 static 的内部类添加的,名称约定为“outClassName.this”。
1) 使用内部类中定义的非静态变量和方法时,要先创建外部类的对象,再由“outObjectName.new”操作符创建内部类的对象,再调用内部类的方法,如下所示:
public class Demo{
public static void main(String[] args) {
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.dostuff();
}
}
class Outer{
private int size;
class Inner{
public void dostuff() {
size++;
}
}
}
2) static 内部类相当于其外部类的 static 成员,它的对象与外部类对象间不存在依赖关系,因此可直接创建。示例如下:
public class Demo{
public static void main(String[] args) {
Outer.Inner inner = new Outer.Inner();
inner.dostuff();
}
}
class Outer{
private static int size;
static class Inner {
public void dostuff() {
size++;
System.out.println("size=" + size);
}
}
}
运行结果:
size=1
3) 由于内部类可以直接访问其外部类的成分,因此当内部类与其外部类中存在同名属性或方法时,也将导致命名冲突。所以在多层调用时要指明,如下所示:
public class Outer{
private int size;
public class Inner{
private int size;
public void dostuff(int size){
size++; // 局部变量 size;
this.size; // 内部类的 size
Outer.this.size++; // 外部类的 size
}
}
}
局部内部类
局部内部类(Local class)是定义在代码块中的类。它们只在定义它们的代码块中是可见的。
局部类有几个重要特性:
- 仅在定义了它们的代码块中是可见的;
- 可以使用定义它们的代码块中的任何局部 final 变量;
- 局部类不可以是 static 的,里边也不能定义 static 成员;
- 局部类不可以用 public、private、protected 修饰,只能使用缺省的;
- 局部类可以是 abstract 的。
请看下面的代码:
public class Outer {
public static final int TOTAL_NUMBER = 5;
public int id = 123;
public void func() {
final int age = 15;
String str = "http://www.weixueyuan.net";
class Inner {
public void innerTest() {
System.out.println(TOTAL_NUMBER);
System.out.println(id);
// System.out.println(str);不合法,只能访问本地方法的final变量
System.out.println(age);
}
}
new Inner().innerTest();
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.func();
}
}
运行结果:
5
123
15
匿名内部类
匿名内部类是局部内部类的一种特殊形式,也就是没有变量名指向这个类的实例,而且具体的类实现会写在这个内部类里面。
注意:匿名类必须继承一个父类或实现一个接口。
不使用匿名内部类来实现抽象方法:
abstract class Person {
public abstract void eat();
}
class Child extends Person {
public void eat() {
System.out.println("eat something");
}
}
public class Demo {
public static void main(String[] args) {
Person p = new Child();
p.eat();
}
}
运行结果:
eat something
可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用。但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?
这个时候就引入了匿名内部类。使用匿名内部类实现:
abstract class Person {
public abstract void eat();
}
public class Demo {
public static void main(String[] args){ // 继承 Person 类
new Person() {
public void eat() {
System.out.println("eat something");
}
}.eat();
}
}
可以看到,匿名类继承了 Person 类并在大括号中实现了抽象类的方法。
内部类的语法比较复杂,实际开发中也较少用到,本教程不打算进行深入讲解,各位读者也不应该将内部类作为学习Java的重点。
Java知多少(37)静态内部类、匿名内部类、成员式内部类和局部内部类的更多相关文章
- 《Java基础知识》Java静态内部类、匿名内部类、成员式内部类和局部内部类
内部类可以是静态(static)的,可以使用 public.protected 和 private 访问控制符,而外部类只能使用 public,或者默认. 成员式内部类 在外部类内部直接定义(不在方法 ...
- 匿名内部类和局部内部类只能访问final变量的原因
以下是从各大网站找来的解释,我在这里摘抄一些从其他地方搬过来的大致思想,可能会比较乱, 详细解释 http://blog.csdn.net/salahg/article/details/7529091 ...
- 为什么匿名内部类和局部内部类只能访问final变量
因为虽然匿名内部类在方法的内部,但实际编译的时候,内部类编译成Outer.Inner,这说明内部类所处的位置和外部类中的方法处在同一个等级上,外部类中的方法中的变量或参数只是方法的局部变量,这些变量或 ...
- Java知多少(完结篇)
Java知多少(1)语言概述 Java知多少(2)虚拟机(JVM)以及跨平台原理 Java知多少(3) 就业方向 Java知多少(4)J2SE.J2EE.J2ME的区别 Java知多少(5) Java ...
- Java知多少(上)
Java知多少(1)语言概述 Java知多少(2)虚拟机(JVM)以及跨平台原理 Java知多少(3) 就业方向 Java知多少(4)J2SE.J2EE.J2ME的区别 Java知多少(5) Java ...
- java 面向对象(二十五):内部类:类的第五个成员
内部类:类的第五个成员 1.定义: Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类.2.内部类的分类:成员内部类(静态.非静态 ) vs 局部内部类(方法内.代码块内.构 ...
- java:内部类与外部类的区别和联系
注意事项一:在内部类中可以随意使用外部类的成员方法以及成员变量. 众所周知,在定义成员方法或者成员变量的时候,可以给其加上一些权限的修饰词,以防止其他类的访问.如在成员变量或者成员方法前面,加上Pri ...
- Java知多少(19)访问修饰符(访问控制符)
Java 通过修饰符来控制类.属性和方法的访问权限和其他功能,通常放在语句的最前端.例如: 1 public class className { 2 // body of class 3 } 4 pr ...
- Java知多少(18)类的定义及其实例化
类必须先定义才能使用.类是创建对象的模板,创建对象也叫类的实例化. 下面通过一个简单的例子来理解Java中类的定义: public class Dog{ String name; int age; v ...
随机推荐
- git 详细教程和常用操作指令
git 内部工作原理图 如上图,git 一般可以分为三个区:工作区.暂存区.版本库,通常类似 git add等命令都是与index 暂存区的交互,git commit指令则是 index 与版本库的交 ...
- java中线程安全的map是ConcurrentHashMap
原理:http://www.cnblogs.com/ITtangtang/p/3948786.html 与hashtable的区别: http://blog.csdn.net/songfeihu08 ...
- AppleScript脚本学习记录《一》
tell命令块 tell application "Finder" display dialog "Hello World" end tell 声明变量 set ...
- 偷懒啦!button多了,这样写既简洁又高效
在日常的项目中,我最喜欢用button了,但是button多了,写起来又枯燥又费时,今天学到一方法,绝对简单高效! 看看以前: 看吧,这还只是声明,接下来还有: 等等……,是不是很麻烦?现在找到新方法 ...
- Windows下的搜索神器 —— everything
介绍一款Windows下的神奇 -- everything,软件很小巧,但是搜索速度非常快,比Windows自带的搜索功能更强大.更快.掌握它的基本用法,在查找文件时能提升很高的效率 1.下载 2.基 ...
- 递归与迭代的联系以及优缺点(以c++为例)
1.递归的定义: 程序直接或间接的调用自身的方法. 递归算法的特点:(1) 递归就是在过程或函数里调用自身.(2) 在使用递归策略时,必须有一个明确的递归结束条件,称为递归出口.(3) 递归算法解题通 ...
- 17、python对内存的使用
python对内存的使用 浅拷贝和深拷贝 所谓浅拷贝就是对引用的拷贝(只拷贝父对象) 所谓深拷贝就是对对象的资源的拷贝 解释一个例子: import copy a = [1,2,3,['a','b', ...
- Newtonsoft.Json2.0下面序列化和反序列化
序列化 string xml = JavaScriptConvert.SerializeObject(dataTable); 反序列化 JavaScriptConvert.DeserializeObj ...
- 浅谈java构建工具的选择
在学校的时候还总是自己用eclipse自带的jar导出工具,然后人工来给项目打包,那是相当的原始. 而后工作了,项目中都是用ant,慢慢的开始学会使用这个工具.感觉就和脚本一样,很容易读懂,做项目构建 ...
- ORA-00054: resource busy and acquire with NOWAIT specified or timeout expired
开发说测试环境在删除表的时候,报了如下错误: SQL> drop table tke purge; drop table tke purge * ERROR at line 1: ORA-000 ...