一. 概念

大部分时候,类被定义成一个独立的程序单元。有时候把一个类放在另一个类内部定义,这个类被称为内部类,包含内部类的类也被称为外部类。

内部类的主要作用:

  • 内部类提供良好的封装,可以把内部类隐藏在外部类之内,不允许同一个包中的其他类访问该类。
  • 内部类成员可以直接访问外部类的私有数据,因为内部类被当成外部类成员,通一个类的成员之间可以互相访问。但是外部类不能访问内部类的实现细节,例如内部类的成员变量。
  • 匿名内部类适合用于创建哪些仅需要一次使用的类。

内部类与普通外部类的区别

  • 内部类比外部类可以多使用三个修饰符:private、protected、static,外部类不可以使用这三个修饰符
  • 非静态内部类不能拥有静态成员

定义内部类非常简单,只要把一个类放在另一个类内部定义即可。这里的类内部包括类中的任何位置,甚至方法中也可以定义内部类(方法中定义的内部类被称为局部内部类)。

内部类作为外部类的成员,可以使用任意访问权限修饰符,如private,protected,public。外部类只有包访问权限和公开访问权限。

编译有n个内部类的Java源文件时,文件所在的路径会生成多个 (.class)文件,分别是一个OuterClassName.class和n个OuterClassName$InnerClassName.calss文件

1.1 非静态内部类

成员内部类分为两种,静态内部类和非静态内部类,静态内部类使用static修饰 。

非静态内部类里不能有静态方法,静态成员变量,静态初始化块,静态声明会引发错误

当在非静态内部类的方法内访问某个变量时,系统优先在方法的局部变量,所在内部类的全局变量,再到外部类的查找。如果都找不到则会编译出错

如果外部类的成员变量与内部类的成员变量重名,则使用this和OuterClassName.this作为限定来区分

非静态内部类的成员可以访问外部类的private成员,但反过来就不成立了。非静态内部类的成员只在非静态内部类范围是可知的。并不能被外部类直接使用。如果外部类需要访问非静态内部类

的成员包括private修饰的成员,则必须显式创建非静态内部类对象来调用访问其实例变量 。

根据静态成员不能访问非静态成员的规则,外部类的静态方法,静态代码块不能访问非静态内部类。包括不能使用静态内部类定义变量、创建实例等。

/**
*
*/
package com.gdut.innerclass.test; /**
* @author 12539
*
*/
public class Outer { private int outProp = 9; class Inner
{
private int intProp = 5;
public void accessOutProp() {
//非静态内部类可以直接访问外部类的private成员变量
System.out.println("外部类的Prop的值:"+outProp);
}
} private void accessInnerProp() {
//System.out.println("内部类的Prop的值:"+intProp);
Inner inner = new Inner();//需要访问内部类的实例变量必须显式创建内部类对象才能访问
System.out.println("内部类的Prop的值:"+inner.intProp);
} /**
* @param args
*/
public static void main(String[] args) {
Outer outer = new Outer();
outer.accessInnerProp(); } }

输出:内部类的Prop的值:5

1.2 静态内部类

静态内部类使用static修饰属于外部类本身,不属于外部类对象。

静态内部类可以包含静态成员也可以包含非静态成员。根据静态成员不能访问非静态成员的原则,静态内部类不能访问外部类的实例成员,只能访问外部类的类成员。

外部类依然不能直接访问静态内部类的成员,可以使用静态内部类的类名作为调用者访问内部静态成员,可以使用静态内部类的对象作为调用者访问内部非静态成员。

Java允许在接口里定义内部类,接口定义的内部类默认使用public static修饰,接口内部类只能是静态内部类。

1.3 使用内部类

1.3.1 在外部类内部使用内部类

从前面程序可以看出,在外部类内部使用内部类跟平时使用没有太大的区别。唯一区别就是外部类的静态成员不能使用非静态内部类

1.3.2 在外部类以外使用非静态内部类

private修饰的内部类只能在外部类内部使用。

在外部类以外的地方定义内部类变量的语法格式

OuterClass.InnerClass varName

在外部类以外的地方创建非静态内部类的实例语法如下:

OuterInstance.new InnerConstrutor()

如果需要在外部类以外的地方创建非静态内部类的子类。尤其要注意非静态内部类的构造器必须通过外部类对象调用

public class SubClass extends Outer.Inner{

    public SubClass(Outer outer) {
outer.super();//通过outer对象显式调用Inner构造器
} }

1.3.3 在外部类以外使用静态内部类

因为静态外部类是类相关的,因此创建静态内部类对象无需创建外部类对象。语法格式如下:

new OuterClass.InnerConStrutor()

下面程序示范了实例

package com.gdut.innerclass.test;

class StaticOut{
static class StaticIn{
public StaticIn() {
System.out.println("静态内部类的构造器");
}
}
}
public class CreateStaticInnerInstance { public static void main(String[] args) { StaticOut.StaticIn in = new StaticOut.StaticIn();
} }

1.4 局部内部类

在方法里定义内部类,这个内部类就是局部内部类,局部内部类只在该方法里有效,不能使用访问控制修饰符和static修饰

如果需要用局部内部类定义变量、创建实例或派生子类,那都只能在局部内部类所在的方法内进行

package com.gdut.innerclass.test;

public class LocalInnerClass {

    public static void main(String[] args) {
class InnerBase{
int a;
}
class SubClass extends InnerBase{
int b;
} SubClass subClass = new SubClass();
subClass.a = 5;
subClass.b = 3;
System.out.println("SubClass对象的a和b实例变量是"+subClass.a+","+subClass.b); } }

1.5 Java8改进的匿名内部类

匿名内部类适合那种只需要一次使用的类,创建匿名内部类时会立即创建一个该类的实例,这个类定义立即消失。匿名内部类不能重复使用,语法格式

new 实现接口()|父类构造器(实参列表){

//匿名内部类类体部份

}
  • 匿名内部类必须且只能继承一个父类或实现一个接口。
  • 匿名内部类不能是抽象类,因为系统在创建匿名内部类时,会立即创建匿名内部类的对象。匿名内部类不能定义构造器。因为它没有类名,但是它可以定义初始化块,可以通过初始化块完成构造器完成的事情
  • package com.gdut.innerclass.test;
    interface Product{
    public double getPrice();
    public String getName();
    } public class Anonymous {
    public void test(Product p) {
    System.out.println("买了一个"+p.getName()+",花掉了"+p.getPrice()+"元。");
    } public static void main(String[] args) {
    Anonymous an = new Anonymous();
    an.test(new Product() { @Override
    public double getPrice() {
    return 5.78;
    } @Override
    public String getName() {
    return "牙膏";
    }
    }); } }

    输出:买了一个牙膏,花掉了5.78元。

    通过实现接口来创建匿名内部类时,匿名内部类不能显式创建构造器,他只有一个隐式的无参数构造器。故new接口名后的括号里不能传入参数值。

如果通过继承父类创建匿名内部类时,匿名内部类将拥有和父类相似的构造器,此处的相似指拥有相同的形参列表。

当创建匿名内部类时,必须实现接口或抽象父类里的所有抽象方法。如果有需要也可以重写父类的普通方法。

JDK8以前,Java要求被局部内部类,匿名内部类访问的局部变量必须使用final修饰,从Java8开始,这个限制被取消了,Java8更加智能:如果局部变量被匿名内部类访问,那么该局部变量相当于自动使用了final修饰

Java面向对象进阶篇(内部类)的更多相关文章

  1. Java面向对象进阶篇(包装类,不可变类)

    一. Java 8的包装类 Java中的8种基本数据类型不支持面向对象的变成机制,也不具备对象的特性:没有成员变量,方法可以调用.为此,Java为这8 种基本数据类型分别提供了对应的 包装类(Byte ...

  2. Java面向对象进阶篇(抽象类和接口)

    一.抽象类 在某些情况下,父类知道其子类应该包含哪些方法,但是无法确定这些子类如何实现这些方法.这种有方法签名但是没有具体实现细节的方法就是抽象方法.有抽象方法的类只能被定义成抽象类,抽象方法和抽象类 ...

  3. Python开发【第七篇】:面向对象 和 python面向对象进阶篇(下)

    Python开发[第七篇]:面向对象   详见:<Python之路[第五篇]:面向对象及相关> python 面向对象(进阶篇)   上一篇<Python 面向对象(初级篇)> ...

  4. Java面向对象 Object类 内部类

     Java面向对象 Object类    内部类 知识概要:                 一:Object类                 二:内部类 匿名内部类的写法 1.Object O ...

  5. ☕Java 面向对象进阶内容

    目录 == 和 equals 方法 封装 多态 抽象类和抽象方法 抽象方法 抽象类 抽象类的使用要点 接口 接口使用 内部类 String 字符串常量拼接时的优化 String Pool String ...

  6. Python 面向对象 (进阶篇)

    <Python 面向对象(初级篇)>文章介绍了面向对象基本知识: 面向对象是一种编程方式,此编程方式的实现是基于对 类 和 对象 的使用 类 是一个模板,模板中包装了多个“函数”供使用(可 ...

  7. java基础进阶篇(四)_HashMap------【java源码栈】

    目录 一.前言 二.特点和常见问题 二.接口定义 三.初始化构造函数 四.HashMap内部结构 五.HashMap的存储分析 六.HashMap的读取分析 七.常用方法 八.HashMap 的jav ...

  8. python之路 面向对象进阶篇

    一.字段 字段包括:普通字段和静态字段,他们在定义和使用中有所区别,而最本质的区别是内存中保存的位置不同, 普通字段属于对象 静态字段属于类 class Province: # 静态字段 countr ...

  9. java基础进阶篇(二)_Arraylist ------【java源码栈】

    前言 ArrayList 在开发中用到的频率很高,其中原生态提供的方法有一些很好用的重载版本,其中有的坑该跳得跳啊. 一.ArrayList的6种初始化方法1.构造方法 参数为空2.构造方法 参数为L ...

随机推荐

  1. URI记录

    URI:统一资源标识符(Uniform Resource Identifier,或URI)是一个用于标识某一互联网资源名称的字符串.该种标识允许用户对网络中(一般指万维网)的资源通过特定的协议进行交互 ...

  2. PKU 3468 A Simple Problem with Integers

    题目大意: 有N,M两个数 Q 表示查询, 后面两个数a b,表示查询从a 到b计算它们的和 C 表示增加   后面三个数a,b,c 表示从a开始,一直到b,每个数都增加c 除了查询要进行输出,增加不 ...

  3. 理解WebKit和Chromium: 硬件加速之RenderLayer树到合成树

    转载请注明原文地址:http://blog.csdn.net/milado_nju ## 概述 在前面的章节中,笔者介绍了WebKit渲染引擎是如何有HTML网页构建DOM树.RenderObject ...

  4. (NO.00001)iOS游戏SpeedBoy Lite成形记(七)

    因为我们之前在GameScene中建立的2个数组,分别为player和label的数组.大家可以注意到其中每个元素是一一对应的. 知道了这层关系,我们尝试来更新matchRun方法: CCAction ...

  5. C#数据库连接操作大全

    一:数据库连接代码: SqlConnection objSqlConnection = new SqlConnection ("server = 127.0.0.1;uid = sa; pw ...

  6. UML之部署图

    部署图,英文名曰:Deployment Diagram,通常也称配置图,她是用来显示系统中软件和硬件的物理结构,从部署图中,我们可以了解到软件和硬件组件之间的物理关系以及处理节点的组件分布情况,使用部 ...

  7. Media Player Classic - HC 源代码分析 7:详细信息选项卡(CPPageFileInfoDetails)

    ===================================================== Media Player Classic - HC 源代码分析系列文章列表: Media P ...

  8. Netflix Recommendations

    by Xavier Amatriain and Justin Basilico (Personalization Science and Engineering) In part one of thi ...

  9. Android Studio相关资料链接

     AndroidStudio中文社区:http://www.android-studio.org/index.php Android studio删除工程项目:http://www.linuxid ...

  10. android应用资源预编译,编译和打包全解析

    我们知道,在一个APK文件中,除了有代码文件之外,还有很多资源文件.这些资源文件是通过Android资源打包工具aapt(Android Asset Package Tool)打包到APK文件里面的. ...