内部类对象可以直接访问外围对象的所有成员(包括私有的),而不需要任何特殊条件,就像调用自己的方法与属性成员一样。但外围类不能直接访问内部类中的方法,除非使用内部类的实例来访问(也能访问私有的)。
内部类自动拥有对其外围类所有成员的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象时,此内部对象会有一个指向外围类对象的引用,然后在你访问此外围类的成员时,就是用那个引用来选择外围类的成员,编译器会帮你处理所有的细节。注,这只限于非静态的内部类。
构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器访问不到这个引用就会报错。
静态的内部类也叫嵌套类,接口(类与接口中的接口都是static)叫嵌套接口。
匿名内部类与普通的内部类继承相比是有些受限的,虽然匿名内部类既可以继承类,也可以实现接口,但是不能两者兼备,而且如果实现接口,也只能实现一个接口。
非静态的内部类中不能定义static变量、方法、类,即非静态的内部类里不能定义一切static东西(static final形式的常量定义除外)。因为一个成员类实例必然与一个外部类实例关联,这个static定义完全可以移到其外部类中去。
内部(类中或接口中)接口一定static的。
接口中的内部类一定是public与static,但不一定是final(与数据成员不同),因为省略final时可以被继承。
非静态的内部类里不能定义接口,因为内部接口(嵌套接口)默认为static,是无法改变的,所以内部类里的接口只能定义在静态的内部类里面。
方法与块里定义的内部类只能是非静态的,不能加static,所以局部内部类里只能定义非静态的成员。局部内部类也能直接访问外部内所有成员。
静态的内部类可以定义非静态与静态的东西。
不能在静态内部类中直接(实例化外部类再访问是可以的)访问外部类中的非静态成员与方法。而非静态内部类是可以访问外部类的静态成员。
在方法与作用域内都可定义内部类。如果一个内部类在if条件语句中定义,则不管条件是否成立都会编译成类,但这个类的使用域只限于该if语句中,if外面不能访问。
设计模式总是将变化的事物与保持不变的事物分离开,比如模板方法模式中,模板方法是保持不变的事物,而可覆盖的方法就是变化的事物。
内部类不能被重写:父类中的内部类不能被子类中的同名内部类重写。
为什么加上final后的局部变量就可以在内部类中使用了?因为加上final后,编译器是这样处理内部类的:如果这个外部局部变量是常量,则在内部类代码中直接用这个常量;如果是类的实例,则编译器将产生一个内部类的构造参数,将这个final变量传到内部类里,这样即使外部局部变量无效了,还可以使用,所以调用的实际是自己的属性而不是外部类方法的参数或局部变量。这样理解就很容易得出为什么要用final了,因为两者从外表看起来是同一个东西,实际上却不是这样,如果内部类改掉了这些参数的值也不可能影响到原参数,然而这样却失去了参数的一致性,因为从编程人员的角度来看他们是同一个东西,如果编程人员在程序设计的时候在内部类中改掉参数的值,但是外部调用的时候又发现值其实没有被改掉,这就让人非常的难以理解和接受,为了避免这种尴尬的问题存在,所以编译器设计人员把内部类能够使用的参数设定为必须是final来规避这种莫名其妙错误的存在。
一个类对外提供一个公共接口的实现(接口与实现完全分离,而且隐藏了实现)是内部类的典型应用,以JDK Collection类库为例,每种Collection的实现类必须提供一个与其对应的Iterator实现,以便客户端能以统一的方式(Iterator接口)遍历任一Collection实例。每种Collection类的Iterator实现就被定义为该Collection类的私有的内部类。
内部类作用:
1、内部类方法可以访问该类所在的作用域中的数据,包括私有数据。
2、内部类可以对同一个包中的其他类隐藏起来。
3、当想要定义一个回调函数且不想编写大量代码时,使用匿名内部类比较便捷。
4、实现多继承。
>>>内部类机制<<<
如果有如下内部类:
Java代码
public class Outer {
private boolean b;
private int i;
//内部类
private class Inner {
private boolean b;
Inner(boolean b) {
this.b = b;
}
public void print() {
System.out.println(Outer.this.b & this.b);
}
}
public void f(final String str) {
class Inner {//局部内部类
public void print() {
System.out.println(Outer.this.i);
}
}
}
}
我们来使用Reflection反射外部及内部类,看看内部类是怎样访问外部类成员的:
D:\work\Test\bin>java Reflection Outer
Java代码
class Outer
{
//构造器
public Outer();
//字段
private boolean b;
private int i;
//方法
static boolean access$0(Outer);// 内部类Outer$Inner通过该方法访问外部类b成员
static int access$1(Outer); // 局部类Outer$1Inner通过该方法访问外部类i成员
public void f(java.lang.String);
}
class Outer$Inner
{
//构造器
Outer$Inner(Outer, boolean);// 在编译期会自动传入外部类实例
//字段
private boolean b;
final Outer this$0;//指向外部类实例
//方法
public void print();
}
class Outer$1Inner
{
//构造器
Outer$1Inner(Outer, java.lang.String);//第二个参数是引用的final类型的局部变量,也是通过构造器传入的
//字段
final Outer this$0;
private final java.lang.String val$str;//存储引用的局部final类型变量
//方法
public void print();
}
非静态内部类创建方式:
Java代码
OuterClassName.InnerClassName inner = new OuterClassName().new InnerClassName();
静态内部类创建方式:
Java代码
OuterClassName.InnerClassName inner = new OuterClassName.InnerClassName();
继承内部类语法规则: 请参考 57. 继承内部类
静态内部类里可以使用this(而不像静态方法或块里是不能使用this的),此时的this指向静态内部类,而不是外部类,下面为LinkedList类里的内部类,代表一个节点的实现:
Java代码
private static class Entry {
Object element;
Entry next;
Entry previous;
Entry(Object element, Entry next, Entry previous) {
this.element = element;
this.next = next;
this.previous = previous;
}
}
在非静态的内部类里访问外围类相同属性成员时,需在this前加上外围类型(采用Outer.this.XX 来访问,其中Outer为外围类的类型),一般在访问自己成员时,可以省略this前自身的类型,但默认应该是有的:
Java代码
public class Outer {
private int i = 1;
public void f(){
System.out.println("f Outer.this.i=" + Outer.this.i);//1
}
private /*static*/class Inner {
private int i = 2;
public void p() {
System.out.println("p this.i=" + this.i);//2
System.out.println("p Inner.this.i=" + Inner.this.i);//2
//!!注,如果是静态的内部类时,下面语句不能编译通过
System.out.println("p Outer.this.i=" + Outer.this.i);//1
}
}
public static void main(String[] args) {
Outer outer = new Outer();
outer.f();
Outer.Inner inner = outer.new Inner();
inner.p();
}
}
匿名内部类(方法或块中的内部类一样)使用外部类作用域内的局部变量需定义成final,但这个变量需在匿名内部类中直接使用,如果是作为匿名构造器的参数时不需要:
Java代码
public class Wrapping {
private int i;
public Wrapping() {}
public Wrapping(int x) { i = x; }
public int value() { return i; }
}
public class Parcel {
// 可以直接内部类或匿名的内部类访问,不需要定义成final
private int ii = 1;
/*
* 这里的参数 x 不需要定义成final,因为它只是
* 作为构建匿名对象时传递的一个参数,而没有直接
* 在匿名内部类中使用
*/
public Wrapping wrapping1(int x) {
// 调用匿名内部类的基类的带参构造函数
return new Wrapping(x) { // 传递参数
public int value() {
//调用外部内的域成员时可直接调用,但加this时就需在
//this前加外部类名,因为该内部类没有定义ii
return super.value() * 47 * Parcel.this.ii;
}
};
}
/*
* 注,这里的参数 x 一定要定义成final,因为
* 它被匿名内部类直接使用了
*/
public Wrapping wrapping2( final int x ) {
final int y = 1;
return new Wrapping() {
//不管是在定义时还是方法中使用都需要定义成final
private int i=y;
public int value() {
return i * x * 47;
}
};
}
public static void main(String[] args) {
Wrapping w = new Parcel().wrapping1(10);
w = new Parcel().wrapping2(10);
}
}
匿名类中不可能有命名的构造器,因为它根本没有名字。但通过块初始化,就能够达到为匿名内部类创建一个构造器的效果,当然它受到了限制——你不能重载块方法,这不像普通内部类的构造函数:
Java代码
abstract class Base {
public Base(int i) {
System.out.println("Base constructor, i = " + i);
}
public abstract void f();
}
public class AnonymousConstructor {
public static Base getBase(int i) {
return new Base(i) {
{ //初始化块
System.out.println("Inside instance initializer");
}
public void f() {
System.out.println("In anonymous f()");
}
};
}
public static void main(String[] args) {
Base base = getBase(47);
base.f();
}
} /* Output:
Base constructor, i = 47
Inside instance initializer
In anonymous f()
*///:~
实现接口的匿名内部类:
Java代码
public class Outer {
public Comparable getComp() {
return new Comparable() {// Comparable为比较器接口
//实现接口
public int compareTo(Object o) {
return 0;
}
};
}
但要注意,匿名内部类实现一个接口时,构造时不能带参数:
Java代码
interface InnerI {}
public InnerI getII() {
// 匿名内部内实现一个接口时,构造器不能带参数,
// 因为接口根本就没有构造器,更没有带参的构造器
// !!return new InnerI(int i) {};
}
}
内部类生成的class文件名规则:
Java代码
public class A {//A.class
class B {//A$B.class
class C {
}//A$B$C.class
}
{
class B {
}//A$1B.class
}
B f() {
class D {
}//A$1D.class
return new B() {
};//A$1.class
}
B g() {
class E {//A$1E.class
B h() {
return new B() {
};//A$1E$1.class
}
}
return new B() {
};//A$2.class
}
static class F {
}//A$F.class
public static void main(String[] args) {
A a = new A();
System.out.println(a.f().getClass().getName());
System.out.println(a.g().getClass().getName());
}
}
package com.jelly.innerclass;
public class Sequence {
private Object[] items;
private int next;
public Sequence(int size) {
items = new Object[size];
}
public void add(Object x) {
if (next < items.length) {
items[next++] = x;
}
}
private class SequenceSelector implements Selector {
private int i = 0;
public Object current() {
return items[i];
}
public boolean end() {
return i == items.length;
}
public void next() {
if (i < items.length) {
i++;
}
}
}
public Selector selector() {
return new SequenceSelector();
}
public static void main(String[] args) {
Sequence sequence = new Sequence(10);
for (int i = 0; i < 10; i++) {
sequence.add(Integer.toString(i));
}
Selector selector = sequence.selector();
while(!selector.end()){
System.out.println(selector.current());
selector.next();
}
}
}
分享到:
相关推荐
在使用匿名内部类时,要记住以下几个原则:匿名内部类不能有构造方法、匿名内部类不能是public、protected、private、static、只能创建匿名内部类的一个实例、匿名内部类不能定义任何静态成员、静态方法、一个匿名...
内部类是Java编程语言中的一种特性,它允许我们在一个类的内部定义另一个类。这种设计模式在Android开发中尤其常见,因为它可以有效地管理代码和实现特定的功能。本文将详细探讨内部类、匿名内部类以及内部接口的...
在Java编程语言中,内部类和匿名内部类是两种特殊类型的类,它们为代码的组织和功能实现提供了独特的灵活性。本教程"Java4Android 35_内部类和匿名内部类"深入探讨了这两个概念,旨在帮助开发者更好地理解和运用它们...
内部类分为几种类型,包括成员内部类、局部内部类、匿名内部类以及方法参数内部类。 1. **成员内部类**:成员内部类就像是外部类的一个普通成员,可以是静态或非静态的。非静态内部类拥有对外部类的引用,可以直接...
Java匿名内部类是Java语言中一个独特且强大的特性,它允许我们在不需要定义一个单独的类的情况下创建类的实例。这在处理回调、事件监听、单例模式以及其他需要短时间内定义一个简单类的情况时非常有用。本篇文章将...
内部类可以分为四种:成员内部类、静态嵌套类、方法内部类和匿名内部类。 成员内部类 成员内部类是定义在外部类的成员变量中的一种内部类。它可以访问外部类的所有成员变量和方法,包括私有的变量和方法。成员内部...
本篇文章将深入探讨Java中的四种内部类:实例内部类、局部内部类、匿名类和静态内部类,并通过实例代码进行详细解析。 1. **实例内部类**:这是最常见的内部类形式,它在外部类的实例方法或成员位置定义。实例内部...
Java 基础第七章内部类与异常类 Java 语言支持在一个类中定义另一个类,这样的类称做内部类。内部类和外嵌类之间存在着紧密的关系:内部类可以访问外嵌类的成员变量和方法,而外嵌类也可以使用内部类声明的对象作为...
### Java内部类详解 #### 一、内部类的分类与概念 Java的内部类机制是其强大特性之一,它允许类作为另一个类的成员存在,从而增强了代码的封装性和复用性。根据定义和作用域的不同,Java内部类主要分为四类: 1. ...
然而,不当使用Handler,尤其是结合匿名内部类或非静态内部类,可能导致内存泄漏和Native内存增加,这对应用性能和稳定性造成负面影响。 首先,我们要理解内存泄漏的概念。内存泄漏是指程序中已分配的内存没有被...
根据不同的应用场景和特性,内部类可以分为多种类型:成员内部类、局部内部类、静态内部类、匿名内部类。下面将详细介绍每种类型的内部类及其特点和使用方法。 #### 成员内部类 成员内部类(也称为非静态内部类)...
### 反射私有内部类的例子 #### 一、引言 在Java编程语言中,反射(Reflection)是一项强大的功能,允许程序在运行时检查和修改自身结构与行为。通过反射,可以动态地获取类的信息并操作其字段、方法以及构造器等。...
Java内部类是Java语言的一个独特特性,它允许我们在一个类的内部定义另一个类。这种设计提供了更高级别的封装和组织代码的方式。以下是关于内部类及其相关知识点的详细说明: 1. **内部类基本语法** - **实例内部...
首先,内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。成员内部类就像其他成员变量一样,可以直接访问外部类的所有成员,包括私有成员。局部内部类只存在于某个方法内,它的作用范围更小,...
内部类主要分为四种类型:静态内部类、成员内部类、局部内部类和匿名内部类。 1. 静态内部类(Static Inner Class) 静态内部类与普通的类类似,只是它们定义在外部类中,并且前面带有 `static` 关键字。它们不会...
Java 嵌套类和内部类详解 Java 中的嵌套类和内部类是指在一个类的内部定义另一个类,这种类称为嵌套类(nested classes)。嵌套类有两种类型:静态嵌套类和非静态嵌套类。静态嵌套类使用很少,非静态嵌套类也即被称...
Java内部类主要包括以下几种类型:成员内部类(非静态内部类)、静态内部类(也称为静态嵌套类)、局部内部类和匿名内部类。 - **成员内部类**:这种类型的内部类是定义在外部类的一个成员位置上,它可以访问外部类...
内部类可以分为四类:成员内部类、局部内部类、匿名内部类和静态内部类。在这里,我们重点关注成员内部类和静态内部类。 成员内部类,就像它的名字一样,是类的一个成员,与字段和方法处于同一级别。它可以访问外部...
### Java内部类(DOC)详解 #### 一、概述 Java内部类是Java语言中一个重要的概念,它指的是那些类定义被嵌套在其他类定义中的类。与之相对应的是顶层类,即那些类定义没有被嵌套在其他类中的类。内部类又可以...
内部类可以分为四种类型:静态内部类、成员内部类(非静态内部类)、局部内部类和匿名内部类。 1. **静态内部类**: 静态内部类与普通的成员内部类不同,它不持有对外部类的引用。因此,可以像其他静态成员一样,...