可以将一个类的定义放在另一个类的定义内部,这就是内部类。

内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二)。

第一次见面

内部类我们从外面看是非常容易理解的,无非就是在一个类的内部在定义一个类。

public class OuterClass {
private String name ;
private int age; public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} class InnerClass{
public InnerClass(){
name = "chenssy";
age = 23;
}
}
}

在这里InnerClass就是内部类,对于初学者来说内部类实在是使用的不多,鄙人菜鸟一个同样没有怎么使用过(貌似仅仅只在做swing 注册事件中使用过),但是随着编程能力的提高,我们会领悟到它的魅力所在,它可以使用能够更加优雅的设计我们的程序结构。在使用内部类之间我们需要明白为什么要使用内部类,内部类能够为我们带来什么样的好处。

一、为什么要使用内部类

为什么要使用内部类?在《Think in java》中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能独立地继承一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

在我们程序设计中有时候会存在一些使用接口很难解决的问题,这个时候我们可以利用内部类提供的、可以继承多个具体的或者抽象的类的能力来解决这些程序设计问题。可以这样说,接口只是解决了部分问题,而内部类使得多重继承的解决方案变得更加完整。

public interface Father {

}

public interface Mother {

}

public class Son implements Father, Mother {

}

public class Daughter implements Father{

    class Mother_ implements Mother{

    }
}

其实对于这个实例我们确实是看不出来使用内部类存在何种优点,但是如果Father、Mother不是接口,而是抽象类或者具体类呢?这个时候我们就只能使用内部类才能实现多重继承了。

其实使用内部类最大的优点就在于它能够非常好的解决多重继承的问题,但是如果我们不需要解决多重继承问题,那么我们自然可以使用其他的编码方式,但是使用内部类还能够为我们带来如下特性(摘自《Think in java》):

  1、内部类可以用多个实例,每个实例都有自己的状态信息,并且与其他外围对象的信息相互独立。

2、在单个外围类中,可以让多个内部类以不同的方式实现同一个接口,或者继承同一个类。

3、创建内部类对象的时刻并不依赖于外围类对象的创建。

4、内部类并没有令人迷惑的“is-a”关系,他就是一个独立的实体。

5、内部类提供了更好的封装,除了该外围类,其他类都不能访问。

二、内部类基础

在这个部分主要介绍内部类如何使用外部类的属性和方法,以及使用.this与.new。

当我们在创建一个内部类的时候,它无形中就与外围类有了一种联系,依赖于这种联系,它可以无限制地访问外围类的元素。

public class OuterClass {
private String name ;
private int age; /**省略getter和setter方法**/ public class InnerClass{
public InnerClass(){
name = "chenssy";
age = 23;
} public void display(){
System.out.println("name:" + getName() +" ;age:" + getAge());
}
} public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.display();
}
}
--------------
Output:
name:chenssy ;age:23

在这个应用程序中,我们可以看到内部了InnerClass可以对外围类OuterClass的属性进行无缝的访问,尽管它是private修饰的。这是因为当我们在创建某个外围类的内部类对象时,此时内部类对象必定会捕获一个指向那个外围类对象的引用,只要我们在访问外围类的成员时,就会用这个引用来选择外围类的成员。

其实在这个应用程序中我们还看到了如何来引用内部类:引用内部类我们需要指明这个对象的类型:OuterClasName.InnerClassName。同时如果我们需要创建某个内部类对象,必须要利用外部类的对象通过.new来创建内部类: OuterClass.InnerClass innerClass = outerClass.new InnerClass();。

同时如果我们需要生成对外部类对象的引用,可以使用OuterClassName.this,这样就能够产生一个正确引用外部类的引用了。当然这点实在编译期就知晓了,没有任何运行时的成本。

public class OuterClass {
public void display(){
System.out.println("OuterClass...");
} public class InnerClass{
public OuterClass getOuterClass(){
return OuterClass.this;
}
} public static void main(String[] args) {
OuterClass outerClass = new OuterClass();
OuterClass.InnerClass innerClass = outerClass.new InnerClass();
innerClass.getOuterClass().display();
}
}
-------------
Output:
OuterClass...

到这里了我们需要明确一点,内部类是个编译时的概念,一旦编译成功后,它就与外围类属于两个完全不同的类(当然他们之间还是有联系的)。对于一个名为OuterClass的外围类和一个名为InnerClass的内部类,在编译成功后,会出现这样两个class文件:OuterClass.class和OuterClass$InnerClass.class。

在Java中内部类主要分为成员内部类、局部内部类、匿名内部类、静态内部类。

三、成员内部类

成员内部类也是最普通的内部类,它是外围类的一个成员,所以他是可以无限制的访问外围类的所有 成员属性和方法,尽管是private的,但是外围类要访问内部类的成员属性和方法则需要通过内部类实例来访问。

在成员内部类中要注意两点,第一:成员内部类中不能存在任何static的变量和方法;第二:成员内部类是依附于外围类的,所以只有先创建了外围类才能够创建内部类。

public class OuterClass {
private String str; public void outerDisplay(){
System.out.println("outerClass...");
} public class InnerClass{
public void innerDisplay(){
//使用外围内的属性
str = "chenssy...";
System.out.println(str);
//使用外围内的方法
outerDisplay();
}
} /*推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 */
public InnerClass getInnerClass(){
return new InnerClass();
} public static void main(String[] args) {
OuterClass outer = new OuterClass();
OuterClass.InnerClass inner = outer.getInnerClass();
inner.innerDisplay();
}
}
--------------------
chenssy...
outerClass...

推荐使用getxxx()来获取成员内部类,尤其是该内部类的构造函数无参数时 。

四、局部内部类

有这样一种内部类,它是嵌套在方法和作用于内的,对于这个类的使用主要是应用与解决比较复杂的问题,想创建一个类来辅助我们的解决方案,到那时又不希望这个类是公共可用的,所以就产生了局部内部类,局部内部类和成员内部类一样被编译,只是它的作用域发生了改变,它只能在该方法和属性中被使用,出了该方法和属性就会失效。

对于局部内部类实在是想不出什么好例子,所以就引用《Think in java》中的经典例子了。

定义在方法里:

public class Parcel5 {
public Destionation destionation(String str){
class PDestionation implements Destionation{
private String label;
private PDestionation(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestionation(str);
} public static void main(String[] args) {
Parcel5 parcel5 = new Parcel5();
Destionation d = parcel5.destionation("chenssy");
}
}

定义在作用域内:

public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String s) {
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip("chenssy");
String string = ts.getSlip();
}
} public void track(){
internalTracking(true);
} public static void main(String[] args) {
Parcel6 parcel6 = new Parcel6();
parcel6.track();
}
}

五、匿名内部类

在做Swing编程中,我们经常使用这种方式来绑定事件

button2.addActionListener(
new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.out.println("你按了按钮二");
}
});

我们咋一看可能觉得非常奇怪,因为这个内部类是没有名字的,在看如下这个例子:

public class OuterClass {
public InnerClass getInnerClass(final int num,String str2){
return new InnerClass(){
int number = num + 3;
public int getNumber(){
return number;
}
}; /* 注意:分号不能省 */
} public static void main(String[] args) {
OuterClass out = new OuterClass();
InnerClass inner = out.getInnerClass(2, "chenssy");
System.out.println(inner.getNumber());
}
} interface InnerClass {
int getNumber();
} ----------------
Output:
5

这里我们就需要看清几个地方

1、 匿名内部类是没有访问修饰符的。

  2、 new 匿名内部类,这个类首先是要存在的。如果我们将那个InnerClass接口注释掉,就会出现编译出错。

3、 注意getInnerClass()方法的形参,第一个形参是用final修饰的,而第二个却没有。同时我们也发现第二个形参在匿名内部类中没有使用过,所以当所在方法的形参需要被匿名内部类使用,那么这个形参就必须为final。

4、 匿名内部类是没有构造方法的。因为它连名字都没有何来构造方法。

六、静态内部类

在java提高篇-----关键字static中提到Static可以修饰成员变量、方法、代码块,其他它还可以修饰内部类,使用static修饰的内部类我们称之为静态内部类,不过我们更喜欢称之为嵌套内部类。静态内部类与非静态内部类之间存在一个最大的区别,我们知道非静态内部类在编译完成之后会隐含地保存着一个引用,该引用是指向创建它的外围内,但是静态内部类却没有。没有这个引用就意味着:

1、 它的创建是不需要依赖于外围类的。

2、 它不能使用任何外围类的非static成员变量和方法。

public class OuterClass {
private String sex;
public static String name = "chenssy"; /**
*静态内部类
*/
static class InnerClass1{
/* 在静态内部类中可以存在静态成员 */
public static String _name1 = "chenssy_static"; public void display(){
/*
* 静态内部类只能访问外围类的静态成员变量和方法
* 不能访问外围类的非静态成员变量和方法
*/
System.out.println("OutClass name :" + name);
}
} /**
* 非静态内部类
*/
class InnerClass2{
/* 非静态内部类中不能存在静态成员 */
public String _name2 = "chenssy_inner";
/* 非静态内部类中可以调用外围类的任何成员,不管是静态的还是非静态的 */
public void display(){
System.out.println("OuterClass name:" + name);
}
} /**
* @desc 外围类方法
* @author chenssy
* @data 2013-10-25
* @return void
*/
public void display(){
/* 外围类访问静态内部类:内部类. */
System.out.println(InnerClass1._name1);
/* 静态内部类 可以直接创建实例不需要依赖于外围类 */
new InnerClass1().display(); /* 非静态内部的创建需要依赖于外围类 */
OuterClass.InnerClass2 inner2 = new OuterClass().new InnerClass2();
/* 方位非静态内部类的成员需要使用非静态内部类的实例 */
System.out.println(inner2._name2);
inner2.display();
} public static void main(String[] args) {
OuterClass outer = new OuterClass();
outer.display();
}
}
----------------
Output:
chenssy_static
OutClass name :chenssy
chenssy_inner
OuterClass name:chenssy

上面这个例子充分展现了静态内部类和非静态内部类的区别。

java详解内部类的更多相关文章

  1. Java 详解 JVM 工作原理和流程

    Java 详解 JVM 工作原理和流程 作为一名Java使用者,掌握JVM的体系结构也是必须的.说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成:Java ...

  2. java提高篇(八)----详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  3. java基础之:详解内部类(转载)

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  4. java提高篇(七)-----详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  5. java提高篇之详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

  6. 逆向工程生成的Mapper.xml以及*Example.java详解

    逆向工程生成的接口中的方法详解 在我上一篇的博客中讲解了如何使用Mybayis逆向工程针对单表自动生成mapper.java.mapper.xml.实体类,今天我们先针对mapper.java接口中的 ...

  7. java基础(十三)-----详解内部类——Java高级开发必须懂的

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 为什么要使用内部类 为什么要使用内部类?在<Think in java>中有这样一句话:使用内部类最吸引人的原因是:每个内部类都能 ...

  8. java内部类深入详解 内部类的分类 特点 定义方式 使用

    本文关键词: java内部类 内部类的分类 特点  定义方式 使用   外部类调用内部类 多层嵌套内部类  内部类访问外部类属性  接口中的内部类  内部类的继承  内部类的覆盖  局部内部类 成员内 ...

  9. Java:详解内部类

    可以将一个类的定义放在另一个类的定义内部,这就是内部类. 内部类是一个非常有用的特性但又比较难理解使用的特性(鄙人到现在都没有怎么使用过内部类,对内部类也只是略知一二). 第一次见面 内部类我们从外面 ...

随机推荐

  1. XDCTF网络安全大赛——Web100

    打开网址 http://game1.xdctf.com:8083/f16c3b1ed800fc78e605/index.php 网页中显示了一张图片,图片名为hackkey.png: 还有一段文字: ...

  2. MySQ数据表设计

    数据表概念 数据表是数据库中的基本对象元素,以记录(行)和字段(列)组成的二维结构用于存储数据.数据表由表结构和表内容两部分组成,先建立表结构,然后才能输入数据.数据表结构设计主要包括字段名称.字段类 ...

  3. bzoj3733 [Pa2013]Iloczyn 搜索

    正解:搜索 解题报告: 先放下传送门QwQ umm其实并不难,,,最近在复建基础姿势点所以都写的是些小水题QAQ 首先考虑如果能构造出来一定是因数凑起来鸭,所以先把因数都拆出来,然后就爆搜 几个常见的 ...

  4. MSSQL2008 部署及开启远程连接

    最近不少用户在windows2003 server 32位操作系统上安装SQL Server2008总是失败,出现大量错误.今天经过通过我反复测试安装,找出了一个便捷的安装方法,节省大家宝贵时间,具体 ...

  5. 敏捷开发之Scrum扫盲篇(转)

    现在敏捷开发是越来越火了,人人都在谈敏捷,人人都在学习Scrum和XP... 为了不落后于他人,我也开始学习Scrum.今天主要是对我最近阅读的相关资料,根据自己的理解,用自己的语言来描述Scrum中 ...

  6. WARNING: firstResult/maxResults specified with collection fetch; applying in memory!

    QueryTranslatorImpl @Override public List list(SessionImplementor session, QueryParameters queryPara ...

  7. weblogic学习教程(一)

    一.简介 WebLogic是美国Oracle公司出品的一个application server,确切的说是一个基于JAVAEE架构的中间件,WebLogic是用于开发.集成.部署和管理大型分布式Web ...

  8. finecms在任意页面调用栏目名称和地址等

    finecms如何调用栏目名称和地址呢?在任意页面.我们有时需要在不同的页面调用某个栏目名,怎么调用比较快呢?ytkah整理了一些快速调用语句方便查找 栏目名称:{dr_cat_value(栏目id, ...

  9. RN animated缩放动画

    效果图: 代码: import React, {Component} from 'react'; import { AppRegistry, StyleSheet, Text, Animated, T ...

  10. 误删除innodb ibdata数据文件 文件句柄 文件描述符 proc fd

    误删除innodb ibdata数据文件  文件句柄  文件描述符  proc  fd http://www.cnblogs.com/gomysql/p/3702216.html 提示:如果不小心通过 ...