内部类

一个类内部定义的类称为内部类。

内部类允许把逻辑相关的类组织在一起,并控制内部代码的可视性。

内部类与外部类的结构层次如下。

顶层类:最外层的类

外部类:内部类所在的类

内部类:类内部定义的类

客户类:访问其他类的类

内部类的基本语法

可访问性不同。

顶层类只能处于public和默认访问级别

内部类可以是:public、protected、private和默认

package com.basicjava.innerclass;

class Outer {
// 如果把public改为private就不可见了
public class InnerTool { // 访问级别为public的内部类
public int add(int a, int b) {
return a+b;
}
}
// 内部类的实例作为外部类的成员变量,并且可以直接使用
private InnerTool tool = new InnerTool();
public int add(int a, int b, int c) {
// 调用内部类实例的方法
return tool.add(tool.add(a, b), c);
}
}
public class Tester {
public static void main(String[] args) {
Outer o = new Outer();
System.out.println(o.add(1, 2, 3));
// 要想建内部类的实例先得建一个外部类的对象
// 完整类名是Outer.InnerTool
// 之所以可以这样新建是由于InnerTool是public的
Outer.InnerTool tool = new Outer().new InnerTool();
System.out.println(tool.add(23, 3));
}
}

内部类的完整类名是外部类名.内部类名,并且内部类必须是public才可以直接这样使用。

如果不希望客户程序访问内部类,外部类可以把成员定义为private类型。

成员内部类还可以分为两种:实例内部类和静态内部类,后者使用static修饰。

不论哪种类型的内部类,都不可以与外部类重名。

实例内部类

实例内部类是成员内部类的一种,没有static修饰。实例内部类有以下特点:

(1) 在创建实例内部类的实例时,外部类的实例必须存在。例如

	Outer.InnerTool tool = new Outer().new InnerTool();

以上代码等价于:

	Outer outer = new Outer();
Outer InnerTool tool = outer.new InnerTool();

(2) 实例内部类自动持有外部类的实例的引用。在内部类中,可以直接访问外部类的所有成员,包括成员变量和成员方法。而且在多重嵌套中,内部类可以访问所有外部类的成员。

package com.basicjava.innerclass;
public class TestClassA {
private int a1;
public int a2;
static int a3; public TestClassA(int a1, int a2) {
this.a1=a1;
this.a2=a2;
} protected int methodA() {
return a1 + a2;
} class B {
// B可以直接访问A的成员!
int b1 = a1;
int b2 = a2;
int b3 = a3;
int b4 = new TestClassA(3,4).a1;
int b5 = methodA();
public void printOuter() {
// 还可以这样访问A的成员,B存在的前提是A已经存在了
System.out.println("a1 = " + TestClassA.this.a2);
}
} public static void main(String[] args) {
TestClassA.B b = new TestClassA(1,2).new B();
System.out.println("b.b1 = " + b.b1);
b.printOuter();
}
}

(3) 外部类实例与内部类实例是一对多的关系,一个内部类只会引用一个外部类的实例,而一个外部类对应零个或者多个内部类实例。在外部类中不能直接访问内部类的成员,必须通过内部类实例自己去访问。外部类可以直接通过this.new B()来创建内部类的实例,新建的实例会引用当前实例。

(4) 实例内部类不能定义静态成员变量,而只能定义实例成员。为什么呢?

(5) 实例内部类B与外部类A包含同名的成员变量var那么在类B中,通过this.var访问B类的成员,A.this.var表示类A的成员。

静态内部类

静态内部类是成员内部类的一种,用static修饰。

(1) 静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时不需要创建外部类的实例。

(2) 静态类可以直接访问外部类的静态成员,如果访问外部类的实例成员需要通过外部类的实例去访问。

(3) 静态内部类中可以定义静态成员和实例成员。(静态内部类也可以定义实例成员?)

(4) 客户类可以直接通过完整的类名直接访问静态内部类的静态成员。

局部内部类

局部内部类是在一个方法中定义的内部类,可见范围是当前方法。

和局部变量一样,局部内部类不能用访问控制修饰符(public、private和protected)及static修饰。

(1) 局部内部类只能在当前方法中使用

(2) 局部内部类和实例内部类一样不能包含静态成员

(3) 在局部内部类中定义的内部类也不能用访问控制修饰符(public、private和protected)及static修饰。

(4) 局部内部类和实例内部类一样可以访问外部类的所有成员。

内部类的继承

package com.basicjava.innerclass;
class Outer {
private int a;
public Outer(int a) {
this.a = a;
} class Inner {
public Inner() { }
public void print() {
System.out.println("a = " + a);
}
}
}
public class Sample extends Outer.Inner {
public Sample(Outer o) {
o.super(); // 还是不能理解为什么要这么做,毕竟Sample是继承Inner的啊
// 难道继承内部类的Sample一样像成员变量一样,注意这个地方
} public static void main(String[] args) {
Outer outer1 = new Outer(1);
Outer outer2 = new Outer(2);
Outer.Inner in = outer1.new Inner();
in.print();
// outer1和s1关联,outer2和s2关联
Sample s1 = new Sample(outer1);
Sample s2 = new Sample(outer2);
s1.print();
s2.print();
}
}

子类与父类的内部类重名

内部类并不存在覆盖的概念,假如子类中的内部类和父类中的内部类重名了,那么这两个内部类也会分别在不同的命名空间中,不会发生冲突。java不会检查子类中的Inner类是否缩小了父类中的Inner类的访问权限。

package com.basicjava.innerclass;
class Outer2 {
Inner in;
Outer2() {
in = new Inner();
}
public class Inner {
public Inner() {
System.out.println("inner of Outer");
}
}
} public class SubOuter extends Outer2 {
class Inner {
public Inner() {
System.out.println("inner of SubOuter");
}
}
public static void main(String[] args) {
// 新建SubOuter实例会调用父类Outer对象的构造方法
SubOuter.Inner in1 = new SubOuter().new Inner();
System.out.println("============");
Outer2.Inner in2 = new Outer2().new Inner();
}
}

匿名类

匿名类是一种特殊的内部类,这种类没有名字。

(1) 匿名类本身没有构造方法,但是可以调用父类的构造方法

(2) 匿名类中没有构造方法但是可以在匿名类中提供一段实例初始化代码,java虚拟机在调用了父类的构造函数之后会执行这段代码。

(3) 除了在外部类的方法中定义匿名类之外还可以声明一个成员变量

package com.basicjava.innerclass;

public abstract class TestA {
TestA a = new TestA() {
void method() {
System.out.println("from inner");
}
}; abstract void method();
}

(4) 匿名类除了可以继承类以外还可以实现接口

package com.basicjava.innerclass;
public class SampleInterface {
public static void main(String[] args) {
Thread t = new Thread(new Runnable() { @Override
public void run() {
for (int i=0; i<1000; i++) {
System.out.println(i);
} }
});
t.start();
for (int i=0; i<1000; i++) {
System.out.println("from main " + i);
}
}
}

(5) 匿名类和局部内部类一样,可以访问外部类的所有成员,如果一个匿名类位于一个方法中,还能访问所在方法的final类型的变量和参数。

(6) 局部类和匿名类一样,可以起到封装类型名字的作用,不同之处是

匿名类的程序比较短

一个局部内部类可以有多个重载的构造方法,而匿名类只能创建一次实例

内部接口及接口中的内部类

一个类中也可以定义内部接口,还可以匿名内部类实现这一接口

接口中可以定义静态的内部类,此时静态内部类位于接口的命名空间中。

内部类的用途

(1) 封装类型

私有内部类可以用来封装类型

(2) 直接访问外部成员

如果某个类的成员变量需要修改,而只能由特定的进行修改,那么这个特定的类可以写成内部类

(3) 回调

package com.basicjava.innerclass;

interface Adjustable {
public void adjust(int temperature);
} class Base {
private int speed;
// 调节速度
public void adjust(int speed) {
this.speed = speed;
System.out.println("速度改变了哦");
}
} public class Sub extends Base implements Adjustable {
// 这个类里面并没有显示出现adjust方法,但是Base有adjust方法
// 相当于实现了接口Adjustable;
private int temperature; private void adjustTemperature(int temperature) {
this.temperature = temperature;
System.out.println("温度改变了哦");
}
// 感觉这个回调有点绕
private class Closure implements Adjustable {
public void adjust(int temperature) {
adjustTemperature(temperature);
}
} public Adjustable getCallBackReference() {
return new Closure();
} public static void main(String[] args) {
Sub sub = new Sub();
Adjustable ad = sub.getCallBackReference();
sub.adjust(12);
ad.adjust(23); Sub.Closure sc = sub.new Closure() {
public void adjust(int temperature) {
System.out.println("外部的回调方法");
System.out.println("传过来的温度为 " + temperature); }
};
// 回调屌屌的
Adjustable ad1 = sc;
ad1.adjust(12); } public void printTemperature() {
System.out.println(temperature);
}
} class TestInterface implements Adjustable {
private int temperature;
private int speed;
private class Hehe implements Adjustable {
public void adjust(int temperature) {
TestInterface.this.temperature = temperature;
}
} public void adjust(int speed) {
this.speed = speed;
}

}

怎么说呢,回调就好像开了一个后门一样。

内部类文件的命名

对于每个内部类来说,java编译器会生成独立的.class文件。这些类的命名规则如下:

成员内部类:外部类的名字\(内部类的名字
局部内部类:外部类的名字\)数字\(内部类的名字
匿名类:外部类的名字\)数字

Think in java中还有不少好例子,暂时没搬上来

java内部类以及匿名类的更多相关文章

  1. Java 内部类和匿名类 实现JButton动作 ActionListener类

    import javax.swing.*; import java.awt.*; import java.awt.event.*; public class ControlCircle2 extend ...

  2. java内部类和异常类的概念

    1.内部类的外嵌类的成员变量在内部类中任然有效,内部类中的方法也可以调用外嵌类中的 方法,内部类中不可以声明类的变量和方法,外嵌的类体可以用内部类声明对象,作为外嵌类的成员.内部类仅供他的外嵌类使用. ...

  3. (转)Java基础——嵌套类、内部类、匿名类

    本文内容分转自博客:http://www.cnblogs.com/mengdd/archive/2013/02/08/2909307.html 将相关的类组织在一起,从而降低了命名空间的混乱. 一个内 ...

  4. Java中的内部类、匿名类的使用

    代码(test.java): interface ie{ public void print(); } class outer{} public class test{ public class in ...

  5. 【java】TreeSet、Comparable、Comparator、内部类、匿名类

    package com.tn.treeSet; public class Student { private String name; private int age; public Student( ...

  6. 【转】Java中的内部类和匿名类

       Java内部类(Inner Class),类似的概念在C++里也有,那就是嵌套类(Nested Class),乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的 ...

  7. [改善Java代码]使用匿名类的构造函数

    建议39: 使用匿名类的构造函数 阅读如下代码,看看是否可以编译: public class Client { public static void main(String[] args) { Lis ...

  8. Java 中的 匿名类

    什么是内部类? 在一个类中定义另一个类,这样定义的类称为内部类.包含内部类的类称为内部类的外部类. 如果想要通过一个类来使用另一个类,可以定义为内部类. 内部类的外部类的成员变量在内部类仍然有效,内部 ...

  9. Java中的匿名类

    我们知道接口一般用于定义一种规范或操作协议,然后子类实现接口的所有功能.如下面的简单代码: 定义IMessage接口 package org.lyk.entities; public interfac ...

随机推荐

  1. Windows下如何安装Python的第三方库

    有下面几个办法: 1. 通过http://www.lfd.uci.edu/~gohlke/pythonlibs/这个网站, 下载whl文件, 解压之后会有三个文件夹, 将最短名字的那个文件夹复制到C: ...

  2. 1CSS与文档

    层叠样式表(Cascading Style Sheet,CSS)的功能十分强大,可以影响一个或一组文档的表现. 为什么结构化对HTML来说很重要:1.非结构化页面使得建立内容索引极为困难.2.缺乏结构 ...

  3. switch多分支语句

    1.switch多分支语句的语法 switch(表达式){ case 常量值:要执行的语句; break; case 常量值:要执行的语句; break; case 常量值:要执行的语句; break ...

  4. AngularJS 实现简单购物车

    使用AngularJS实现一个简单的购物车,主要感受强大的双向绑定和只关注对象不关注界面特性. 先看看界面: 点击+-操作和删除: 这些全部只需要操作数据源就行,不需要关注界面. 实现过程: 一.使用 ...

  5. Nodejs开发(2.连接MongoDB)

    一.先配置MongoDB Win10下下载那个安装版,zip版的会报却各种DLL,安装在你希望的路径,实在安装错了,就剪切过来也行(本例E:\mongodb). 然后是配置启动脚本,就是写一个bat文 ...

  6. Install MySQL on Mac by Homebrew

    1.  安装mysql brew update brew install mysql 2. 启动mysql mysql.server start 3. 登录mysql mysql -uroot -p ...

  7. ExtJs 使用点滴 十三 在FormPanel 嵌入按钮

    Ext.onReady(function () { //初始化标签中的Ext:Qtip属性. Ext.QuickTips.init(); Ext.form.Field.prototype.msgTar ...

  8. php连接和操作mysql数据库

    <?php //数据库连接文件:link.php $link = mysql_connect("localhost", "root", "&qu ...

  9. java math library

    https://github.com/jroyalty/jglm https://github.com/JOML-CI/JOML

  10. resin or tomcat .war e.g. note

    经常想在后台找WEB对应文件,做个记录 jar cvf step1.war . 命令将jsp(内含有html等数据局),等编译成war包目录下的文件有index.jps,eg.css -------- ...