五. 面向对象高级特性2. 内部类的分类

内部类可以是静态(static)的,可以使用 public、protected 和 private 访问控制符,而外部类只能使用 public,或者默认。

成员式内部类

在外部类内部直接定义(不在方法内部或代码块内部)的类就是成员式内部类,它可以直接使用外部类的所有变量和方法,即使是 private 的。外部类要想访问内部类的成员变量和方法,则需要通过内部类的对象来获取。

请看下面的代码:

  1. public class Outer{
  2. private int size;
  3. public class Inner {
  4. public void dostuff() {
  5. size++;
  6. }
  7. }
  8. public void testTheInner() {
  9. Inner in = new Inner();
  10. in.dostuff();
  11. }
  12. }

成员式内部类如同外部类的一个普通成员。

成员式内部类可以使用各种修饰符,包括 public、protected、private、static、final 和 abstract,也可以不写。

若有 static 修饰符,就为类级,否则为对象级。类级可以通过外部类直接访问,对象级需要先生成外部的对象后才能访问。

非静态内部类中不能声明任何 static 成员。

内部类可以相互调用,例如:

  1. class A {
  2. // B、C 间可以互相调用
  3. class B {}
  4. class C {}
  5. }

成员式内部类的访问

内部类的对象以成员变量的方式记录其所依赖的外层类对象的引用,因而可以找到该外层类对象并访问其成员。该成员变量是系统自动为非 static 的内部类添加的,名称约定为“outClassName.this”。

1) 使用内部类中定义的非静态变量和方法时,要先创建外部类的对象,再由“outObjectName.new”操作符创建内部类的对象,再调用内部类的方法,如下所示:

  1. public class Demo{
  2. public static void main(String[] args) {
  3. Outer outer = new Outer();
  4. Outer.Inner inner = outer.new Inner();
  5. inner.dostuff();
  6. }
  7. }
  8. class Outer{
  9. private int size;
  10. class Inner{
  11. public void dostuff() {
  12. size++;
  13. }
  14. }
  15. }

2) static 内部类相当于其外部类的 static 成员,它的对象与外部类对象间不存在依赖关系,因此可直接创建。示例如下:

  1. public class Demo{
  2. public static void main(String[] args) {
  3. Outer.Inner inner = new Outer.Inner();
  4. inner.dostuff();
  5. }
  6. }
  7. class Outer{
  8. private static int size;
  9. static class Inner {
  10. public void dostuff() {
  11. size++;
  12. System.out.println("size=" + size);
  13. }
  14. }
  15. }

运行结果:
size=1

3) 由于内部类可以直接访问其外部类的成分,因此当内部类与其外部类中存在同名属性或方法时,也将导致命名冲突。所以在多层调用时要指明,如下所示:

  1. public class Outer{
  2. private int size;
  3. public class Inner{
  4. private int size;
  5. public void dostuff(int size){
  6. size++; // 局部变量 size;
  7. this.size; // 内部类的 size
  8. Outer.this.size++; // 外部类的 size
  9. }
  10. }
  11. }

局部内部类

局部内部类(Local class)是定义在代码块中的类。它们只在定义它们的代码块中是可见的。

局部类有几个重要特性:

  1. 仅在定义了它们的代码块中是可见的;
  2. 可以使用定义它们的代码块中的任何局部 final 变量;
  3. 局部类不可以是 static 的,里边也不能定义 static 成员;
  4. 局部类不可以用 public、private、protected 修饰,只能使用缺省的;
  5. 局部类可以是 abstract 的。

请看下面的代码:

  1. public class Outer {
  2. public static final int TOTAL_NUMBER = 5;
  3. public int id = 123;
  4. public void func() {
  5. final int age = 15;
  6. String str = "http://www.weixueyuan.net";
  7. class Inner {
  8. public void innerTest() {
  9. System.out.println(TOTAL_NUMBER);
  10. System.out.println(id);
  11. // System.out.println(str);不合法,只能访问本地方法的final变量
  12. System.out.println(age);
  13. }
  14. }
  15. new Inner().innerTest();
  16. }
  17. public static void main(String[] args) {
  18. Outer outer = new Outer();
  19. outer.func();
  20. }
  21. }

运行结果:
5
123
15

匿名内部类

匿名内部类是局部内部类的一种特殊形式,也就是没有变量名指向这个类的实例,而且具体的类实现会写在这个内部类里面。

注意:匿名类必须继承一个父类或实现一个接口。

不使用匿名内部类来实现抽象方法:

  1. abstract class Person {
  2. public abstract void eat();
  3. }
  4. class Child extends Person {
  5. public void eat() {
  6. System.out.println("eat something");
  7. }
  8. }
  9. public class Demo {
  10. public static void main(String[] args) {
  11. Person p = new Child();
  12. p.eat();
  13. }
  14. }

运行结果:
eat something

可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用。但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?

这个时候就引入了匿名内部类。使用匿名内部类实现:

复制纯文本新窗口
  1. abstract class Person {
  2. public abstract void eat www.xyseo.net ();
  3. }
  4. public class Demo {
  5. public static void main(String[] args){
  6. // 继承 Person 类
  7. new Person() {
  8. public void eat() {
  9. System.out.println("eat something");
  10. }
  11. }.eat();
  12. }
  13. }

可以看到,匿名类继承了 Person 类并在大括号中实现了抽象类的方法。

内部类的语法比较复杂,实际开发中也较少用到,本教程不打算进行深入讲解,各位读者也不应该将内部类作为学习Java的重点。

时间: 2024-07-30 20:52:53

五. 面向对象高级特性2. 内部类的分类的相关文章

五. 面向对象高级特性1. Java内部类及其实例化

在 Java 中,允许在一个类(或方法.语句块)的内部定义另一个类,称为内部类(Inner Class),有时也称为嵌套类(Nested Class). 内部类和外层封装它的类之间存在逻辑上的所属关系,一般只用在定义它的类或语句块之内,实现一些没有通用意义的功能逻辑,在外部引用它时必须给出完整的名称. 使用内部类的主要原因有: 内部类可以访问外部类中的数据,包括私有的数据. 内部类可以对同一个包中的其他类隐藏起来. 当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类

五. 面向对象高级特性6. Java 泛型

我们知道,使用变量之前要定义,定义一个变量时必须要指明它的数据类型,什么样的数据类型赋给什么样的值. 假如我们现在要定义一个类来表示坐标,要求坐标的数据类型可以是整数.小数和字符串,例如: x = 10.y = 10 x = 12.88.y = 129.65 x = "东京180度".y = "北纬210度" 针对不同的数据类型,除了借助方法重载,还可以借助自动装箱和向上转型.我们知道,基本数据类型可以自动装箱,被转换成对应的包装类:Object 是所有类的祖先类,

五. 面向对象高级特性5. 接口和抽象类的区别

类是对象的模板,抽象类和接口可以看做是具体的类的模板. 由于从某种角度讲,接口是一种特殊的抽象类,它们的渊源颇深,有很大的相似之处,所以在选择使用谁的问题上很容易迷糊.我们首先分析它们具有的相同点. 都代表类树形结构的抽象层.在使用引用变量时,尽量使用类结构的抽象层,使方法的定义和实现分离,这样做对于代码有松散耦合的好处. 都不能被实例化. 都能包含抽象方法.抽象方法用来描述系统提供哪些功能,而不必关心具体的实现. 下面说一下抽象类和接口的主要区别. 1) 抽象类可以为部分方法提供实现,避免了在

python学习之面向对象高级特性

类属性与实例属性类属性就是类对象所拥有的属性,它被所有类对象的实例对象所共有,在内存中只存在一个副本.在前面的例子中我们接触到的就是实例属性(对象属性),它不被所有类对象的实例对象所共有,在内存中的副本个数取决于对象个数. 05_类属性鱼实例属性.py import random class Turtle(object): # power是类属性. power = 100 def __init__(self): # x,y:实例属性. self.x = random.randint(0, 10)

【IOS 开发】Object - C 面向对象高级特性 - 包装类 | 类处理 | 类别 | 扩展 | 协议 | 委托 | 异常处理 | 反射

一. Object-C 对象简单处理 1. 包装类 (1) 包装类简介 NSValue 和 NSNumber : -- 通用包装类 NSValue : NSValue 包装单个 short, int, long, float, char, id, 指针 等数据; -- NSNumber 包装类 : 用于包装 C 语言数据类型; NSNumber 方法 : -- "+ numberWithXxx :" : 将特定类型的值包装成 NSNumber; -- "- initWithX

JS面向对象高级特性

本篇是通过学习视频<一头扎进javascirpt高级篇>整理的一些相关知识,大致包括下面几个方面: 1 对象的创建方法 2 对象的对象属性.私有属性.类属性 3 对象的对象方法.私有方法.类方法 4 javascirpt的继承.封装.与多态 对象的创建方法: 对象的创建可以通过两种方式,第一种通过对象初始化的方法: var person={ name:"xingoo", age:26, say:function(){ console.log("say someth

Python面向对象编程高级特性

***这里还是根据网上资料,主要是廖雪峰老师的教程学习的笔记,主要介绍python面向对象的高级特性,笔记不全,只是记录自己觉得容易出错的地方*** 1.python作为一种动态语言,他的动态绑定机制允许在运行过程中动态的给class或者对象实例添加方法和属性,这个在静态语言中比如java是很难做到的: 1)动态绑定属性: 2)动态绑定方法 给一个实例绑定的方法对于其他实例和类都是不可见的:(这里也说明给一个实例动态绑定方法必须用MethodType(func, instance)) 但是给类绑

JSP简明教程(五):高级特性

JSP过滤器 过滤器的作用是给web请求增加额外的逻辑,每个页面可以被多个过滤器进行处理.过滤器需要在web.xml文件中进行定义,语法如下.过滤器的执行顺序与filter-mapping的定义顺序相同. <filter> <filter-name>FilterName</filter-name> <filter-class>TestFilter</filter-name> <init-param> <param-name>

Boolan C++面向对象高级编程学习第五周

本周C++面向对象高级编程编程主要是讲三个方面 1.虚表和虚指针 虚指针:如果类(包括父类)中有虚函数,就一定会有虚指针,虚指针是指向虚函数的虚表. 虚表:虚指针指向的一种类的表,表上存有类里面虚函数的实现的指针 这里虚函数和虚表一般是和类的多太性结合在一起来使用的,子类调用虚函数是通过调用虚指针来调用虚函数表里面的指针再来实现函数特性 这种调用的方式叫做动态绑定,是一种通过指针类型自动来判断调用的对象,在实现中可以不用区分哪个对象从而调用对应的函数 我们普通的调用类里面的函数叫做静态绑定 2.