`

内部类

 
阅读更多
内部类对象可以直接访问外围对象的所有成员(包括私有的),而不需要任何特殊条件,就像调用自己的方法与属性成员一样。但外围类不能直接访问内部类中的方法,除非使用内部类的实例来访问(也能访问私有的)。

内部类自动拥有对其外围类所有成员的访问权。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象时,此内部对象会有一个指向外围类对象的引用,然后在你访问此外围类的成员时,就是用那个引用来选择外围类的成员,编译器会帮你处理所有的细节。注,这只限于非静态的内部类。

构建内部类对象时,需要一个指向其外围类对象的引用,如果编译器访问不到这个引用就会报错。

静态的内部类也叫嵌套类,接口(类与接口中的接口都是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开发中尤其常见,因为它可以有效地管理代码和实现特定的功能。本文将详细探讨内部类、匿名内部类以及内部接口的...

    Java4Android 35_内部类和匿名内部类

    在Java编程语言中,内部类和匿名内部类是两种特殊类型的类,它们为代码的组织和功能实现提供了独特的灵活性。本教程"Java4Android 35_内部类和匿名内部类"深入探讨了这两个概念,旨在帮助开发者更好地理解和运用它们...

    java 内部类使用(内部匿名类)

    内部类分为几种类型,包括成员内部类、局部内部类、匿名内部类以及方法参数内部类。 1. **成员内部类**:成员内部类就像是外部类的一个普通成员,可以是静态或非静态的。非静态内部类拥有对外部类的引用,可以直接...

    java 匿名内部类的使用规范

    Java匿名内部类是Java语言中一个独特且强大的特性,它允许我们在不需要定义一个单独的类的情况下创建类的实例。这在处理回调、事件监听、单例模式以及其他需要短时间内定义一个简单类的情况时非常有用。本篇文章将...

    Java语法总结 - 内部类

    内部类可以分为四种:成员内部类、静态嵌套类、方法内部类和匿名内部类。 成员内部类 成员内部类是定义在外部类的成员变量中的一种内部类。它可以访问外部类的所有成员变量和方法,包括私有的变量和方法。成员内部...

    java 内部类 局部内部类 匿名类 实例代码

    本篇文章将深入探讨Java中的四种内部类:实例内部类、局部内部类、匿名类和静态内部类,并通过实例代码进行详细解析。 1. **实例内部类**:这是最常见的内部类形式,它在外部类的实例方法或成员位置定义。实例内部...

    java基础第七章内部类与异常类.doc

    Java 基础第七章内部类与异常类 Java 语言支持在一个类中定义另一个类,这样的类称做内部类。内部类和外嵌类之间存在着紧密的关系:内部类可以访问外嵌类的成员变量和方法,而外嵌类也可以使用内部类声明的对象作为...

    java内部类的讲解

    ### Java内部类详解 #### 一、内部类的分类与概念 Java的内部类机制是其强大特性之一,它允许类作为另一个类的成员存在,从而增强了代码的封装性和复用性。根据定义和作用域的不同,Java内部类主要分为四类: 1. ...

    Handler对象中使用匿名内部类或非静态内部类正确地释放消息避免内存泄漏或增加Native内存

    然而,不当使用Handler,尤其是结合匿名内部类或非静态内部类,可能导致内存泄漏和Native内存增加,这对应用性能和稳定性造成负面影响。 首先,我们要理解内存泄漏的概念。内存泄漏是指程序中已分配的内存没有被...

    内部类的分类及各自用法

    根据不同的应用场景和特性,内部类可以分为多种类型:成员内部类、局部内部类、静态内部类、匿名内部类。下面将详细介绍每种类型的内部类及其特点和使用方法。 #### 成员内部类 成员内部类(也称为非静态内部类)...

    反射私有内部类的例子

    ### 反射私有内部类的例子 #### 一、引言 在Java编程语言中,反射(Reflection)是一项强大的功能,允许程序在运行时检查和修改自身结构与行为。通过反射,可以动态地获取类的信息并操作其字段、方法以及构造器等。...

    JAVA 内部类 PPT

    Java内部类是Java语言的一个独特特性,它允许我们在一个类的内部定义另一个类。这种设计提供了更高级别的封装和组织代码的方式。以下是关于内部类及其相关知识点的详细说明: 1. **内部类基本语法** - **实例内部...

    内部类的使用

    首先,内部类分为四种类型:成员内部类、局部内部类、匿名内部类和静态内部类。成员内部类就像其他成员变量一样,可以直接访问外部类的所有成员,包括私有成员。局部内部类只存在于某个方法内,它的作用范围更小,...

    java内部类详解

    内部类主要分为四种类型:静态内部类、成员内部类、局部内部类和匿名内部类。 1. 静态内部类(Static Inner Class) 静态内部类与普通的类类似,只是它们定义在外部类中,并且前面带有 `static` 关键字。它们不会...

    Java 深入理解嵌套类和内部类

    Java 嵌套类和内部类详解 Java 中的嵌套类和内部类是指在一个类的内部定义另一个类,这种类称为嵌套类(nested classes)。嵌套类有两种类型:静态嵌套类和非静态嵌套类。静态嵌套类使用很少,非静态嵌套类也即被称...

    Java内部类总结

    Java内部类主要包括以下几种类型:成员内部类(非静态内部类)、静态内部类(也称为静态嵌套类)、局部内部类和匿名内部类。 - **成员内部类**:这种类型的内部类是定义在外部类的一个成员位置上,它可以访问外部类...

    浅谈内部类与静态内部类的应用

    内部类可以分为四类:成员内部类、局部内部类、匿名内部类和静态内部类。在这里,我们重点关注成员内部类和静态内部类。 成员内部类,就像它的名字一样,是类的一个成员,与字段和方法处于同一级别。它可以访问外部...

    Java内部类(DOC)

    ### Java内部类(DOC)详解 #### 一、概述 Java内部类是Java语言中一个重要的概念,它指的是那些类定义被嵌套在其他类定义中的类。与之相对应的是顶层类,即那些类定义没有被嵌套在其他类中的类。内部类又可以...

    java代码笔记2010-06-01:Java内部类 静态内部类 局部内部类 明明内部类;StringBuffer reverse的使用;

    内部类可以分为四种类型:静态内部类、成员内部类(非静态内部类)、局部内部类和匿名内部类。 1. **静态内部类**: 静态内部类与普通的成员内部类不同,它不持有对外部类的引用。因此,可以像其他静态成员一样,...

Global site tag (gtag.js) - Google Analytics