`
喻红叶
  • 浏览: 41088 次
  • 性别: Icon_minigender_1
  • 来自: 哈尔滨
社区版块
存档分类
最新评论

Java中的内部类

 
阅读更多

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

平凡内部类

平凡内部类就是最普通的内部类,没有static修饰类名,就像这样的类

public class  Outer{
     class Inner {}
}
普通内部类能访问其外部类的所有成员,拥有所有成员的访问权,而不需要任何特殊条件。这是如何做到的呢?弄白这一点很重要,普通内部类的很多特性都是由此而来。来看一段代码
class Outer {
	//内部类
	class Inner {
		public void f() {
			//查看此内部类的所有属性
			Field[] fields = Inner.class.getDeclaredFields();
			for(Field f : fields) {
				System.out.println(f.getName());
			}
		}
	}
}
Inner.f()方法是输出Inner类的所有属性名称,但是在Inner类中没有定义任何属性,那么执行f()方法的结果是什么呢?结果会打印:

this$0

也就是说在Inner类里有一个this$0的属性,通过名字就可以看出这是Java自动给Inner类添加的属性,使用javap反编译Inner.class,果然发现了一个final的this$0域


这就是问题的答案,内部类就是通过this$0来访问其外部类的成员,this$0就是用来保存创建该内部类对象的外部类对象。也就是说,当某个外部类对象创建了一个内部类对象时,内部类对象会拥有那个外部类对象的引用,就是this$0,在访问外部类的成员时,就是使用this$0实现的。所有的这一切都由编译器来处理。由此我们发现,内部类的对象必须依附某个外部类对象,于是平凡内部类的几个特性均可由此而得到解释:

(1)在内部类里面需要外部类的引用时,可以使用.thi语法,.this就是this$0属性,也就是创建该对象的外部类对象,如

public Outer outer {
      return Outer.this;
}
(2)在外部类的非静态方法中可以直接创建内部类,但是在外部类的静态方法中则不行,如
//在外部类的非静态方法中可以直接创建
//因为必须要通过外围类的对象才可以调用非静态方法,内部类对象正是由这个外围类对象创建
	public Inner getInner() {
		Inner in = new Inner();
		return in;
	}
	
//错误,因为不需要外围类对象调用静态方法,没有外围类对象就不能创建内部类
	public static Inner sgetInner() {
		return new Inner();
	}
只有外部类的对象才能创建平凡内部类的对象,这句话我们一定要记住。

(3)在外部类的静态方法或者其他类里面,需要使用外围类对象.new创建内部类对象,如

//需要外部类的对象调用.new语法来创建内部类对象,在其他类中也是如此
	public static Inner sgetInner(Outer outer) {
		Inner in = outer.new Inner();
		return in;
 	}
(4)在平凡内部类不能有static修饰的东西,因为内部类需要依赖外部类对象。

static内部类(嵌套类)

使用static修饰的内部类叫做嵌套类,嵌套类的对象与外部类的对象之间没有联系,它的内部也不会保存对外部类对象的引用。嵌套类和普通的类没有什么分别,它只是置于外部类的命名空间。但是它到底是在外部类的内部,所以还是可以访问外部类的所有成员的,只不过需要一个显式的外部类对象

class Outer {
	private String s;
        //拥有外部类的私有成员的访问权限
	static class SIn {
		public void f(Outer outer) {
			String ss = outer.s;
		}
	}
}
内部类可以作为接口的一部分,放在接口的内部类自动都是public static的,它可以作为所有实现该接口的公共代码,甚至可以在内部类实现外围接口
interface A{	
	//自动是public static 
	class B implements A{
		公共代码
	}
}
普通的Java类不可以使用private和pretected修饰,但是内部类可以。在其他类里使用某个类的内部类时,必须显式的使用外部类.内部类这种形式:Outer.Inner。

局部内部类

内部类不仅可以在类里面,还可以定义在方法和任意作用域内。这样做的理由:

(1)方法可以返回某接口,可以在方法内部定义一个类,该类实现了要返回的接口,创建该类的实例,并返回,这样对就对外界完全屏蔽了。

(2)为了解决一个复杂的问题,想创建一个类来辅助你的解决方案,但是又不希望这个类是公共可用的。

这些内部类的作用域跟普通变量一样,都是属于块作用域,出了作用域,它就没有意义了。

{
    class Inner {}
    //可以在这里创建
   Inner in = new Inner();
}
//这里已经出了作用域了
Inner in = new Inner();//错误
关于匿名内部类

a.匿名内部类被自动转型为父类的引用,所以里面创建的方法如果超出了父类的接口,那是无法访问的,包括属性。匿名内部类可以看成是父类的“无名”子类,所以在创建匿名内部类的对象时,首先还是要创建父类的对象,根据父类构造器中参数的不同,来调用不同的父类构造器,当然了,父类的成员定义处的初始化,语句块的执行也是肯定会有的。

//父类 
class Base { 
	{ 
		System.out.println("父类的语句块");
	} 
	
	Base(int x) { 
		System.out.println("调用执行父类的构造器:" + x); 
	} 
	
	public Base getBase(int x) { 
	//匿名内部类,自动调用父类的构造器 
		return new Base(x) { 
		//匿名内部类的语句块
		{
			System.out.println("匿名内部类的语句块");
		}
		
		//匿名内部类实现的自己的方法,根本没有任何用处
		public void anoyMethod() {
			System.out.println("匿名内部类实现的方法");
		}
	};
}
如果调用Base的getBase(1),则执行结果是:

父类的语句块

调用执行父类的构造器:1

匿名内部类的语句块

超出父类接口的anoyMethod()没有任何机会得到执行。

b.匿名内部类是没有名字呢,怎么创建它的构造器呢?
通过上面的示例,我们可以看到,通过非静态语句块可以达到这个效果,非静态语句块就是匿名内部类的构造器,只是语句块不能重载。

c.传递到匿名内部类的参数和局部变量,必须得是final的;回顾一下:非静态内部类,必须要保存一个外部类的引用。匿名内部类也是内部类,也可以无条件的访问外部类的成员变量,也可以使用.this语句,所以在匿名内部类中使用外部类的成员属性是没有任何限制的,外部类的成员属性不需要是final的。

class Outer { 
	private String name = "cxy"; 
	
	//注意label和age都是final,而name则无所谓 
	public Base getBase(final String label) { 
		final int age = 25; 
		return new Base() { 
			{ 
			System.out.println("label: " + label + ",name: " + name + ",age: " + age); 
			//使用.this语法 
			System.out.println(Outer.this.getClass().getName()); 
			} 
		} ;
	} 
} 
d.匿名内部类和工厂方法结合,会产生非常优美的代码,不需要为每个子类额外的添加一个工厂类,而是在子类内部使用一个匿名内部类代替
//业务接口
interface Service { 
	定义业务方法
}
//工厂接口,返回逻辑类的实例
interface ServiceFactory {
	Service getService();
}

//看看使用了匿名内部类的工厂方法
class ServiceImp implements Service {
	实现逻辑
	
	//使用内部类完全就不需要对应的工厂类了,这让类的接口瞬间清晰了很多
	public static ServiceFactor factory = new ServiceFactory() {
		public Service getService() {
			return new ServiceImp();
		}
	};
}
使用匿名内部类确实可以让工厂方法变得相当优雅,可以减少一半的类

内部类的命名规则

内部类也会生成.class文件,即使是匿名内部类。内部类有自己的一套命名规则,有时候在看反编译出来的代码时或许会用到。最基本的是在外部类的后面加上$,然后紧接内部类的名称。一例胜千言

public class NamedInnderClass {
	//静态内部类:NamedInnderClass$StaticInner
	static class StaticInner { 
		
	//嵌套在内部类中:NamedInnderClass$StaticInner$StaticInnerInner
		static class StaticInnerInner {}
	}
	
	//普通内部类:NamedInnderClass$InnerClass
	class InnerClass { }
	
	//方法内部的类
	public void f() {
		//NamedInnderClass$1MethodInnder,注意加上了一个数字,数字是递增的
		class MethodInner { }
		
		//NamedInnderClass$1,匿名内部类,直接加数字,数字递增
		new NamedInnderClass() { };
	}
}

内部类还是有些复杂,基本的使用方法上面都做了介绍,但是为什么要使用内部类呢?使用内部类最吸引人的原因是:每个内部类都能独立地继承一个实现(类或者接口),不管外部类是否继承了某个实现,对内部类都不会影响。从这个角度看,内部类使得多重继承的解决方案更加完整。

class A{}
abstract class B{}
class C extends A {
	//使用内部类实现"多重继承"
	B makeB() {
		return new B() {};
	}
}

转载请注明出处:喻红叶《Java中的内部类》

分享到:
评论

相关推荐

    Java中内部类的实例化

    Java 内部类 实例化 在Outer类的静态方法中实例化内部类 在同一个包的其它类中实例化Outer类中的内部类

    java中内部类的分类及用法

    在java语言中,有一种类叫做内部类(inner class),也称为嵌入类(nested class),它是定义在其他类的内部。

    java中内部类的分类及用法.pdf

    根据不同的定义位置和作用域,Java内部类可以分为四类:成员内部类、局部内部类、匿名内部类和静态内部类。下面将详细介绍这些内部类的定义和使用方法。 成员内部类 成员内部类是最常见的内部类形式,它定义在外部...

    java中内部类的使用.doc

    成员内部类是指在另一个类中定义但没有使用 `static` 关键字的类。它的定义格式如下: ```java public class 外部类 { ... class 成员内部类 { ... } } ``` **特点** - **访问权限**:成员内部类可以访问外部...

    java中内部类与外部类的学习资料.docx

    Java中的内部类与外部类是Java面向对象编程中一个重要的特性,它允许我们在一个类的内部定义另一个类。这种设计模式提供了更高级别的封装,并且能够实现一些特殊的功能,如匿名内部类、事件处理等。以下是对内部类与...

    讲述java中内部类的研究

    JAVA从JDK1.1开始引入了内部类,可以参见代码,感觉好处就是设计类的时候可以偷懒,呵呵。主要是可以引用类的内部其他元素,差不多是把这个内部类当成原类的元素。还有可以隐藏类的一些设计细节,好处还是很多的。

    java 匿名内部类的使用规范

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

    Java中内部类使用方法实战案例分析

    Java 中内部类使用方法实战案例分析 Java 中内部类的使用方法是一个非常重要的知识点,它们可以帮助开发者更好地组织代码、提高代码的可读性和维护性。在本文中,我们将通过实战案例来分析 Java 中内部类的使用方法...

    14.java局部内部类(方法中类).zip

    14.java局部内部类(方法中类).zip14.java局部内部类(方法中类).zip14.java局部内部类(方法中类).zip14.java局部内部类(方法中类).zip14.java局部内部类(方法中类).zip14.java局部内部类(方法中类).zip14...

    java内部类的讲解

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

    java内部类详解

    在内部类中访问外部类的成员可以使用 `Outerclass.this` 来指定。 3. 局部内部类(Local Inner Class) 局部内部类定义在方法或代码块内,其作用域仅限于该方法或代码块。它们通常用于实现特定方法的功能,且只能...

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

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

    Java语法总结 - 内部类

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

    Java内部类总结

    ### Java内部类总结 在Java编程语言中,内部类是一个重要的概念,它允许开发者在一个类的内部定义另一个类。这种特性极大地增强了代码的封装性和复用性,同时也为解决特定问题提供了灵活的方法。本文将围绕Java内部...

    java静态内部类(嵌套类)

    5. **静态方法调用**:在静态内部类中可以直接访问外部类的静态方法和变量,但是无法直接访问非静态成员。 6. **非静态方法调用限制**:如果需要访问外部类的非静态方法或变量,则必须通过外部类的对象引用来进行...

    16.java匿名内部类.zip

    16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名内部类.zip16.java匿名...

    有关JAVA的内部类的好东西

    Java内部类是Java语言中一个独特且强大的特性,它允许在一个类的定义内部定义另一个类。内部类可以访问外部类的所有成员,包括私有成员,这使得内部类在实现某些特定设计模式时非常有用。本篇文章将深入探讨Java内部...

    java 成员内部类的使用规范

    成员内部类的使用在Java编程中具有独特的价值,它能够帮助我们更好地封装代码,提高代码的组织性和可读性。以下是关于Java成员内部类的一些关键知识点: 1. **分类**:成员内部类分为两种,静态内部类(Static ...

Global site tag (gtag.js) - Google Analytics