一、内部类的定义
可以将一个类的定义放在另一个类的定义内部,这就是内部类
public class OutterClass{ private class InnerClass{ } }
二、创建内部类
以下在Test类中定义了一个InnerClass内部类,然后在Test中的useInnerClass方法中使用
public class Test { public void useInnerClass(String name){ // 使用内部类 InnerClass inner = new InnerClass(name); System.out.println("Name:" + inner.getName()); } public static void main(String[] args){ Test t = new Test(); t.useInnerClass("张三"); } // 定义一个内部类 class InnerClass{ private String name; InnerClass(String name){ this.name = name; } String getName(){ return this.name; } } } /* 输出结果: Name:张三 但是更典型的情况是,外部类将有一个方法,该方法返回指向内部类的引用。 如下面Test类的getInnerClass方法 */ public class Test { public void useInnerClass(String name){ // 使用内部类 InnerClass inner = new InnerClass(name); System.out.println("Name:" + inner.getName()); } // 通过一个公共的方法返回内部类的实例 public InnerClass getInnerClass(String str){ return new InnerClass(str); } public static void main(String[] args){ Test t = new Test(); /* 如果想在外部类的非静态方法之外的任意位置创建某个内部类的对象, 那么,必须使用:"外部类.内部类"的方式指明这个对象的类型 如:Test.InnerClass */ Test.InnerClass innerC = t.getInnerClass("张三"); System.out.println("Name:" + innerC.getName()); } // 定义一个内部类 class InnerClass{ private String name; InnerClass(String name){ this.name = name; } String getName(){ return this.name; } } } /* 输出结果: Name:张三 */
三、连接到外部类
当生成一个内部类的对象时,此对象与制造它的外围对象之间就有一种联系,所所以它能
访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有外围类的所有元素
的访问权。
public class Test { // Test的成员属性 private String name="张三"; public static void main(String[] args){ Test t = new Test(); Test.InnerClass inner = t.new InnerClass(); // 创建内部类 System.out.println("Name:" + inner.getName()); // Name:张三 } // 定义一个内部类 class InnerClass{ String getName(){ return name; // 访问Test外围类的name属性 } } }
四、使用.this和.new
如果你需要生成对外部类对象的引用,可以使用"外部类.this"的形式获取。这样产生
的引用自动地具有正确的类型,这一点在编译期就被知晓并受到检查,因此没有任何运行
时开销。
public class Test { // 定义一个显示指定str的方法 private void print(String str){ System.out.println("我是外部类输出的:" + str); } public static void main(String[] args){ // 创建内部类的一个引用 Test.InnerClass innerClass = new Test().new InnerClass(); innerClass.getTestObject().print("我来自外部类"); } // 定义一个内部类 class InnerClass{ public Test getTestObject(){ // Test.this return Test.this; // 返回外部类的引用 } } }
有时你可能想要告知某些其他对象,去创建其某个内部类对象。要实现此目的,你
必须在new表达式中提供对其他外部类对象的引用,这是需要使用.new语法。如下:
方式一:
Test test = new Test(); Test.InnerClass innerClass = test.new InnerClass();
方式二:
Test.InnerClass innerClass = new Test().new InnerClass();
注意:在创建内部类对象时,你不能想你想象的那样使用外部类的类名而是使用外部类
对象的引用去创建。
在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗
地连接到创建它的外部类对象身上。但是,如果你创建的是嵌套类(静态内部类),
那么就不需要外部类对象的引用。
public class Test { public static void main(String[] args){ // 创建内部类的一个引用 InnerClass innerClass = new InnerClass(); innerClass.print(); } // 定义一个嵌套内部类(静态内部类) static class InnerClass{ public void print(){ System.out.println("内部类的输出信息..."); } } }
五、内部类与向上转型
当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就非
常有用了。因为此类部类能够完全不可见
public class Test { public static void main(String[] args){ // 创建OuterClass,并利用该对象的引用创建InnerClass对象 OuterClass outer = new OuterClass(); Inner inner = outer.getInnerClass(); // 内部类对象 // 无法访问OuterClass内部的private属性InnerClass // OuterClass.InnerClass inner = outer.getInnerClass(); inner.print(); } } class OuterClass{ // 返回内部类InnerClass的对象 public Inner getInnerClass(){ return new InnerClass(); } // 定义一个内部类,实现了Inner接口 // 该内部类隐藏了Inner接口实现的所有细节 private class InnerClass implements Inner{ @Override public void print(){ System.out.println("内部类的输出信息..."); } } } interface Inner{ void print(); }
六、在方法和作用域内的内部类
在方法内部定义一个完整的类,这被成为局部内部类。InnerClass标识
符可以在同一个目录下任意定义,而不会产生命名冲突
public class Test { public Inner getInner(){ // 局部内部类 class InnerClass implements Inner{ @Override public void print(){ System.out.println("我是内部类"); } } return new InnerClass(); // 返回局部内部类的引用 } public static void main(String[] args){ Test test = new Test(); Inner inner = test.getInner(); inner.print(); } } interface Inner{ void print(); } // 展示如何在作用域中定义内部类 public class Test { public Inner getInner(boolean flag){ if(flag){ // 定义局部内部类 class InnerClass implements Inner{ @Override public void print(){ System.out.println("我是内部类"); } } return new InnerClass(); } // System.out.println(new InnerClass()); // 访问不到InnerClass局部内部类 System.out.println("内部类没有被创建"); return null; } public static void main(String[] args){ Test test = new Test(); Inner inner = test.getInner(true); inner.print(); } } interface Inner{ void print(); }
注意:InnerClass类被嵌入在if语句的作用域内,并不是说该类(InnerClass)的创建是有
条件的,它其实与别的类一起编译过了。
七、匿名内部类
public class Test { public Inner getInner(){ return new Inner(){ // 创建一个继承自Inner的匿名内部类 @Override public void print(){ System.out.println("我是匿名内部类"); } }; } /* // 等价与上面的getInner方法 class MyInner implements Inner{ @Override public void print(){ System.out.println("我是匿名内部类"); } } public Inner getInner(){ return new MyInner(); } */ public static void main(String[] args){ Test test = new Test(); Inner inner = test.getInner(); inner.print(); } } interface Inner{ void print(); } // 怎样向有参数的匿名类构造参数 public class Test { public Wrapping getInner(int a){ // 尽管Wrapping只是一个普通类,但还是被它的导出类当作公共“接口”来使用 return new Wrapping(a){ public int value(){ return super.value() * 2; } }; } public static void main(String[] args){ Test test = new Test(); Wrapping inner = test.getInner(12); System.out.println("value: " + inner.value()); } } class Wrapping{ private int i; public Wrapping(int x){ i = x; } public int value(){ return i; } } // 在匿名内部类中定义字段时,还能够对其初始化操作: public class Test { public Inner getInner(String str){ return new Inner(){ // 匿名类实现接口;不能有参数 // 从内部类中访问局部变量 str;需要被声明为最终类型 private String label = str; @Override public void print(){ System.out.println(label); } }; } public static void main(String[] args){ Test test = new Test(); Inner inner = test.getInner("有参数的匿名内部类"); inner.print(); } } interface Inner{ public void print(); }
注意:如果定义一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么
编译器会要求其参数引用是final的,就像在getInner方法中一样。如果只是简
单地给一个字段赋值,那么上面的例子是很好的。但是,要想做一些类似构造
器的行为,该怎么办?在匿名函数中不可能有命名构造器(因为他根本没有名字),
但是通过实例初始化,就你能够达到为匿名内部类创建一个构造器的效果,如下:
public class Test { 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 = Test.getBase(12); base.f(); // Base constructor, i=12 // Inside instance initializer // In anonymous f() } } abstract class Base{ public Base(int i){ System.out.println("Base constructor, i=" + i); } public abstract void f(); }
注意:在上面例子中,不要求变量i一定是final的。因为i被传递给匿名类的基类的
构造器,它并不会在匿名内部类内部直接使用。下面的例子是带实例初始化的形式。
public class Test { public static Inner getInner(final String username, final int age){ return new Inner(){ private int ageTemp; private String nameTemp = username; // 为每个对象的实例初始化, { ageTemp = age; if(ageTemp > 18){ System.out.println("成年人"); } else { System.out.println("未成年人"); } } public void print(){ System.out.println("名称: " + nameTemp); } }; } public static void main(String[] args){ Inner inner = Test.getInner("张三", 12); inner.print(); } } interface Inner{ public void print(); } // 注意:是不合法的 public class Test{ public Inner getInner(){ return new Inner() extends Other{} // return new Inner() implements Other{} } }
八、嵌套类
如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。
这通常成为“嵌套类”。要想了解static应用与内部类的含义,就必须记住,普通内部类对
象隐式的保存了一个指向外围类对象的引用。然而,使用static定义内部类时,情况就不
同了。
1、要创建嵌套内部类的对象,并不需要其外围类的对象。如下:
public class Test { private static class MyInner implements Inner{ @Override public void print(){ System.out.println("我来自内部类"); } } public static void main(String[] args){ MyInner inner = new MyInner(); inner.print(); } } interface Inner{ public void print(); }
2、不能从嵌套类的对象中访问非静态的外围类对象。如下:
public class Test { private String name1 = "张三"; private static String name2 = "李四"; private static class MyInner implements Inner{ @Override public void print(){ // 无法从静态上下文中引用非静态 变量 name1 // System.out.println("name1: " + name1); System.out.println("name2: " + name2); // OK } } public static void main(String[] args){ MyInner inner = new MyInner(); inner.print(); } } interface Inner{ public void print(); }
3、嵌套类与普通内部类还有一个区别。普通内部类的字段与方法,只能放在类的外部层次上,
所以普通内部类不能拥有static数据和static字段,也不能包含嵌套类。但是嵌套类可以。
public class Test { // 普通内部类 private class MyInner{ // private static String name = "zhangsan"; // 内部类不能有静态声明 private String name = "zhangsan"; // 输出: zhangsan // private static class MyInnerInner{} // 此处不允许使用修饰符 static public String getName(){ return name; } } // 嵌套内部类 private static class MyStaticInner{ private static String name = "zhangsan"; public String getName(){ return name; } } public static void main(String[] args){ // 普通内部类 Test.MyInner inner = new Test().new MyInner(); System.out.println("Name: " + inner.getName()); // 嵌套内部类 MyStaticInner staticInner = new MyStaticInner(); System.out.println("Name: " + staticInner.getName()); } }
九、接口内部类
在正常情况下,不能在接口内部放置任何代码,但是嵌套类可以作为接口的一部分。
你放到接口中的任何类都自动地是public 和static的。因为类是static的,只是将嵌套
类置于接口的命名空间内,这并不违反接口的规则。甚至可以在内部类中实现其外围接
口。如下:
public interface Test { void show(); class MyTest implements Test{ // 该类是public static的 public void show(){ System.out.println("hi! java"); } public static void main(String[] args){ new MyTest().show(); } } }
运行方式:java Test$MyTest
如果你想要创建某些公共代码,提供给某个接口的所有实现类使用,那么在接口内部的嵌套类
会显得很方便。如下:
public class Test { public static void main(String[] args){ MyInner1 inner1 = new MyInner1(); inner1.print(); MyInner2 inner2 = new MyInner2(); inner2.print(); } } // 定义一个接口 interface Inner{ void print(); // 定义一个嵌套类,作为Inner接口的所有实现类的公共类 class MyInterfaceInner{ public void show(String str){ System.out.println(str); } } } class MyInner1 implements Inner{ public void print(){ // 调用接口中的嵌套类 new MyInterfaceInner().show("Inner实现类一"); } } class MyInner2 implements Inner{ public void print(){ // 调用接口中的嵌套类 new MyInterfaceInner().show("Inner实现类二"); } } // 一个内部类被嵌套多少层并不重要,他能透明地访问所有外围类的所有成员。如下: public class Test { public static void main(String[] args){ Outter outer = new Outter(); Outter.Inner inner = outer.new Inner(); Outter.Inner.InnerIn in = inner.new InnerIn(); in.h(); } } class Outter{ private void f(){ System.out.println("Outter class"); } // 内部类 class Inner{ private void g(){ System.out.println("Inner class"); } // 内部类中内部类 public class InnerIn{ public void h(){ f(); g(); System.out.println("InnerIn"); } } } }
十、为什么需要内部类
一般来说,内部类继承自某个类或实现某个接口,内部类的代码可以很方便的操作
外围类的对象。所以可以认为内部类提供了某种进入其外围类的窗口。使用内部类最吸
引人的地方:
每个内部类都能独立的继承自一个(接口)实现,所以无论外围类是否已经继承了
某个(接口的)实现,对于内部类都没有影响。如下:
public class Test implements Inner{ @Override public void print(){ System.out.println("Test Class"); } private class MyInner implements Inner{ @Override public void print(){ System.out.println("MyInner Class"); } } public static void main(String[] args){ Test t = new Test(); t.print(); Test.MyInner inner = t.new MyInner(); inner.print(); } } interface Inner{ public void print(); }
如果没有内部类提供的可以继承多个具体或抽象类的能力,一些涉及与编程问题
就很难解决。从这个角度看,内部类使得多继承的解决方案变得完整,接口只解决了
一部分问题。一个类要实现两个接口,则有两种方式
方式一
public class Test implements A, B { }
方式二
public class Test implements A{ private B getB(){ return new B(){ }; } }
// 一个类继承两个具体或抽象的类,则只能使用内部类
public class Test extends A{ private B getB(){ return new B(){ }; } }
使用内部类获得的特性:
1、内部类可以有多个实例,每个实例都有自己的状态信息,并且与其外围对象的信息向独立。
2、在单个外围类中,可以让多个内部类一不同的方式实现同一个接口或继承同一个类。
3、创建内部类对象的时刻并不依赖于外围对象的创建。
4、内部类并没有令人迷惑的“is-a”关系,它是一个独立的实体。
public class Test{ public static void main(String[] args){ Callee1 c1 = new Callee1(); Callee2 c2 = new Callee2(); MyIncrement.f(c2); Caller caller1 = new Caller(c1); Caller caller2 = new Caller(c2.getCallbackReference()); caller1.go(); caller1.go(); caller2.go(); caller2.go(); } } interface Incrementable{ void increment(); } class Callee1 implements Incrementable{ private int i = 0; public void increment(){ i++; System.out.println(i); } } class MyIncrement{ public void increment(){ System.out.println("other operation"); } static void f(MyIncrement mi){ mi.increment(); } } class Callee2 extends MyIncrement{ private int i = 0; public void increment(){ super.increment(); i++; System.out.println(i); } private class Closure implements Incrementable{ public void increment(){ Callee2.this.increment(); } } Incrementable getCallbackReference(){ return new Closure(); } } class Caller{ private Incrementable callbackReference; Caller(Incrementable cbh){ callbackReference = cbh; } void go(){ callbackReference.increment(); } }
注意:在创建一个内部类时,并没有在外围类的接口中添加东西,也没有修改外围类的接口。
十一、内部类的继承
因为内部类的构造器必须连接到指向外围类对象的引用,所有在继承内部类时很复杂。
问题在于,指向外围类对象的引用必须被初始化,而在导出类中不再存在可连接的默认对
象。要解决这个问题,必须使用特殊的语法来明确他们之间的关联。如下:
public class Test extends Outer.Inner{ // 使用默认构造器构造继承自内部类的类时会产生编译错误 // public Test(){} // 需要包含 Outter.Inner 的封闭实例 // 解决办法 public Test(Outer outer){ outer.super(); } public static void main(String[] args){ // Test test = new Test(); Outer outer = new Outer(); Test test = new Test(outer); } } class Outer{ class Inner{ public void show(){ System.out.println("内部类"); } } }
十二、内部类可以被覆盖吗?
不能被覆盖。如:
public class Test extends OutterClass{ public class InnerClass{ public InnerClass(){ System.out.println("Test().InnerClass()"); } } public static void main(String[] args){ new Test(); } } class OutterClass { private InnerClass inner; protected class InnerClass{ public InnerClass(){ System.out.println("InnerClass()"); } } public OutterClass(){ System.out.println("OutterClass()"); inner = new InnerClass(); } }
输出结果:
OutterClass()
InnerClass()
也可以明确继承某个内部类,如下:
public class Test extends OutterClass{ // 试着覆盖内部类 public class InnerClass extends OutterClass.InnerClass{ public InnerClass(){ System.out.println("Test().InnerClass"); } public void f(){ System.out.println("Test().InnerClass f()"); } } public Test(){ // 将新的InnerClass设置到Outter中 insertInnerClass(new InnerClass()); } public static void main(String[] args){ OutterClass outter = new Test(); outter.g(); } } // 外部类 class OutterClass { // 内部类 protected class InnerClass{ public InnerClass(){ System.out.println("InnerClass"); } public void f(){ System.out.println("InnerClass f()"); } } private InnerClass inner = new InnerClass(); public void insertInnerClass(InnerClass inner){ this.inner = inner; } public void g(){ inner.f(); } public OutterClass(){ System.out.println("OutterClass"); } }
输出结果:
InnerClass
OutterClass
InnerClass
Test().InnerClass
Test().InnerClass f()
十三、局部内部类
前面介绍过局部内部类是定义在代码块中的内部类。局部内部类不能访问说明符,
因为它不是外围类的一部分;但是它可以访问当前代码块内的常量,以及此外围类的
所有成员。如下:
public class Test { // 在外围类中定义一个成员变量 private String name = "hello world"; public void getInner(boolean flag){ if(flag){ // 该内部类只能在if代码块中访问 /* private */ class MyInner{ // 非法的表达式开始,此处不能使用修饰符(private) public void print(){ System.out.println("Name: " + name); // 在局部内部类中访问外围类中的使用成员 OK } } new MyInner().print(); } // MyInner inner = new MyInner(); // 找不到符号 // inner.print(); } public static void main(String[] args){ Test test = new Test(); test.getInner(true); } }
十四、内部类标识符
由于每个类都会产生一个.class文件,其中包含了创建该类型对象的全部信息。
而内部类的.class名称有严格的规则:
1、匿名内部类的名字:外围类名$数字.class 如:Outer$1.class
2、普通内部类:外围类名$内部类名.class 如:Outer$Inner.class
相关推荐
Java 内部类详解 Java 内部类是一种高级特性,允许在一个类的定义内部创建另一个类。这种设计模式提供了更灵活的代码组织方式,同时还可以实现特定的封装和访问控制。内部类主要分为四种类型:静态内部类、成员内部...
### Java内部类总结 在Java编程语言中,内部类是一个重要的概念,它允许开发者在一个类的内部定义另一个类。这种特性极大地增强了代码的封装性和复用性,同时也为解决特定问题提供了灵活的方法。本文将围绕Java内部...
### Java内部类详解 #### 一、内部类的分类与概念 Java的内部类机制是其强大特性之一,它允许类作为另一个类的成员存在,从而增强了代码的封装性和复用性。根据定义和作用域的不同,Java内部类主要分为四类: 1. ...
### Java内部类应用详解 #### 一、引言 自Java 1.1引入内部类这一概念以来,它一直是开发者们热烈讨论的话题。作为一种强大的语言特性,内部类为Java编程带来了许多灵活性,但也可能导致代码复杂度增加。正确理解...
Java 内部类是Java语言特性中的一个重要组成部分,它允许我们在一个类的内部定义另一个类。内部类可以访问外部类的所有成员,包括私有成员,这使得内部类在实现复杂逻辑和封装上具有很大的灵活性。下面我们将详细...
### Java内部类的应用场景 #### 场景一:当某个类除了它的外部类,不再被其他的类使用时 内部类的使用场景之一是当某个类仅需被其外部类使用时。这种情况下,将此类定义为内部类可以提高代码的封装性和可维护性。 ...
Java内部类是Java语言提供的一种独特特性,它允许我们在一个类的定义内部定义另一个类。这种内部类可以是成员内部类、局部内部类、匿名内部类或静态内部类,每种都有其特定的用途和使用场景。在这个"java内部类使用...
12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类.zip12.java内部类...
Java内部类是Java语言的一个特色特性,它允许我们在一个类的内部定义另一个类。这种设计模式在处理一些特定情况时非常有用,例如实现匿名回调、封装特定逻辑或创建与外部类有紧密关系的类。本篇文章将深入探讨Java...
Java内部类是Java语言的一个独特特性,它允许我们在一个类的内部定义另一个类。这种设计提供了更高级别的封装和组织代码的方式。以下是关于内部类及其相关知识点的详细说明: 1. **内部类基本语法** - **实例内部...
### JAVA内部类总结 在Java编程语言中,内部类(Inner Classes)是一种非常重要的特性,它允许我们在一个类的内部定义另一个类。这种结构不仅能够提高代码的组织性,还能帮助我们更好地处理类与类之间的关系。根据...
Java内部类是Java语言提供的一种独特机制,它允许在一个类的内部定义另一个类。这种设计模式使得代码结构更紧凑,可以更好地封装和隐藏实现细节,同时也增强了代码的复用性。内部类分为几种类型,包括成员内部类、...
Java 内部类总结 Java 内部类是指在一个外部类的内部再定义一个类。内部类作为外部类的一个成员,并且依附于外部类而存在的。内部类可为静态,可用 protected 和 private 修饰(而外部类只能使用 public 和缺省的包...
Java内部类是Java语言特性中一个独特而强大的部分,它允许在一个类的内部定义另一个类。内部类可以访问外部类的所有成员,包括私有成员,这使得内部类在实现某些特定设计模式时非常有用。本篇文章将深入探讨Java中的...
Java内部类详解 Java内部类是Java语言中的一种特殊类别,它是指定义在另外一个类内部的类。内部类可以访问外部类的所有成员变量和方法,包括私有的变量和方法。内部类可以分为四种:成员内部类、静态嵌套类、方法...
谈Java内部类的四个应用场景
Java内部类是Java语言中一个独特且强大的特性,它允许我们在一个类的内部定义另一个类。内部类提供了增强封装的能力,使得内部类可以被隐藏在外部类中,仅对外部类可见,从而增加了代码的隐私性和安全性。同时,内部...
### Java内部类的作用 #### 一、定义及概念 内部类,顾名思义,指的是一个定义在另一个类内部的类。这样的结构让内部类能够访问外部类的成员(包括私有成员),并且允许内部类拥有不同的访问级别,如`private`、`...
Java内部类是Java语言的一个重要特性,它允许我们在一个类的内部定义另一个类。这种设计模式使得代码结构更加紧凑,同时也提供了更高级的封装和抽象。内部类主要有两种类型:成员内部类和局部内部类。 1. 成员内部...