2013年6月23日 星期日 16时50分56秒
- 内部类对象能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其他外围类的所有元素的访问权限。
- 必须使用外部类的对象来创建内部类对象, 但是如果你创建的是嵌套类(静态内部类),那么它就不需
当内部类为static时,嵌套类意味着:
1)要创建嵌套类的对象,并不需要外围类的对象
2)不能从嵌套类的对象中访问非静态的外围类对象
DotNew dn=new DotNew(); DotNew.Inner n=dn.new Inner(); //注意.new的用法
- .this 和 .new
public class Outter{ class Inner{ public DotThis outer(){ return DotThis.this; //注意:this的使用 } } }
- 使用内部类的原因:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没用影响。
- 内部类的文件也必须是以.class文件格式,而且内部类的文件命名有严格的规则:外围类的名字,加上“$”再加上内部类的名字。例如
LocalInnerClass$1LocalCounter.class
- 局部内部类和匿名内部类 : 上例中我们分别使用局部内部类和匿名内部类实现了同样的功能,他们具有相同的行为和能力。既然局部内部类的名字在方法外是不可见的,那为什么我们仍然使用局部内部类 而不是匿名内部类呢?唯一的理由是:我们需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。
第十章 内部类
可以将一个类的定义放在另一个类的定义内部,这就是内部类。
内部类允许你把一些逻辑相关的类组织在一起,并控制位于内部类的可见性。 内部类与组合不同。
10.1 创建内部类
创建内部类的方式就如你想的一样----把类的定义置于外围类的里面。
package chapter10;
/*@name RandomDoubles.java
* @describe 10.1 创建内部类
* @since 2013-06-23 16:59
* @author 张彪
*/
public class Parcel1 {
class Contents{
private int i=11;
public int value(){return i;}
}
class Desination{
private String label;
Desination(String label){this.label=label;}
String readLabel(){return label;}
}
public void ship(String dest){
Contents c=new Contents();
Desination d=new Desination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args){
Parcel1 p=new Parcel1();
p.ship("Tasmania");
}
}
//当我们在ship()方法里面使用内部类的时候,与使用不同类没什么区别。在这里,实际的区别只是内部类的名字嵌套在Parel1里面的。更典型的情况是,外部类将有一个方法,方法返回一个指向内部类的引用,就像在to和contents()方法中看到的那样。
package chapter10;
/*@name RandomDoubles.java
* @describe 10.1 创建内部类
* @since 2013-06-23 16:59
* @author 张彪
*/
public class Parcel2 {
class Contents{
private int i=11;
public int value(){return i;}
}
class Desination{
private String label;
Desination(String label){
this.label=label;
}
String readLabel(){
return label;
}
}
public Desination to(String s){
return new Desination(s);
}
public Contents contents(){
return new Contents();
}
public void ship(String dest){
Contents c=new Contents();
Desination d=new Desination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args){
Parcel2 p=new Parcel2();
p.ship("Tasmania");
Parcel2.Contents c=p.contents();
Parcel2.Desination d= p.to("Boring");
}
}
//如果想在外部类的非静态方法中之外的任何位置创建某个内部类的对象。那么必须在main()方法中那样,具体地指明这个对象的类型。OuterClassName.InnerClassName.
10.2 链接到外部类
到目前为止,内部类似乎还只是一种名字隐藏和组织代码的模式。这些是很有用,但还不是最引人注目的。当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联 系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其他外围类的所有元素的访问权限。(这与C++嵌套类的设计非常不同,在C++中只是单纯的名字隐藏 机制,与外围对象没有联系)
package chapter10;
/*@name Sequence.java
* @describe 10.2 链接到外部类
* @since 2013-06-23 17:48
* @author 张彪
*/
interface Selector{
boolean end();
Object current();
void next();
}
public class Sequence {
private Object[] items;
private int next=0;
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 boolean end(){return i==items.length;}
public Object current(){return items[i];}
public void next(){if(i<items.length){i++;}}
}
public Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args){
Sequence s=new Sequence(10);
for(int i=0;i<10;i++){
s.add(Integer.toString(i));
}
Selector selector=s.selector();
while(!selector.end()){
System.out.println(selector.current());
selector.next();
}
}
}
注意:内部类自动拥有对外围类所有成员的访问权限。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象是,此内部类对象必定会秘密地捕获一个指向那个外围类的引用。
10.3 使用.this和.new
10.3.1 .this的用法
如果你需要生成对外边对象的引用,可以使用外边类的名字后面紧跟圆点和this。这样产生的引用自动地具有正确的类型。
package chapter10;
/*@name DotThis.java
* @describe 10.3 使用.this和.new
* @since 2013-06-23 17:48
* @author 张彪
*/
public class DotThis {
void f(){System.out.println("DotThis.f()");}
public class Inner{
public DotThis outer(){
return DotThis.this; //注意:this的使用
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args){
DotThis d=new DotThis();
DotThis.Inner n= d.inner();
n.outer().f();
}
}
10.3.2 .new的用法
有时你可能要告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在new表达式中提供对其他外部对象的引用,这是需要使用.new语法。例如:
package chapter10;
/*@name DotNew.java
* @describe 10.3 使用.this和.new
* @since 2013-06-23 18:48
* @author 张彪
*/
public class DotNew {
public class Inner{}
public static void main(String[] args){
DotNew dn=new DotNew();
DotNew.Inner n=dn.new Inner(); //注意.new的用法
//dn.new DotNew.Inner(); 不能这样声明
//Inner r=new Inner(); 也不能这样声明
}
}
要想直接创建内部类的对象,必须使用外部类的对象来创建内部类对象。这样解决了内部类名字作用域的问题。因此你不必声明(实际上你不能声明)dn.new DotNew.Inner()
10.3.4 嵌套类(静态内部类)
在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地链接到创建它的外部类对象上。但是如果你创建的是嵌套类(静态内部类),那么它就不需 要对外部类对象的引用。
package chapter10;
/*@name DotNew.java
* @describe 10.3 嵌套类(静态内部类)
* @since 2013-06-23 19:11
* @author 张彪
*/
public class Pracel3 {
class Contents{
private int i=11;
public int value(){return i;}
}
class Destination{
private String label;
Destination(String whereTo){this.label=whereTo;}
String readLabel(){return label;}
}
public static void main(String[] args){
//Must use instance of outer class to create an instance of the inner class
Pracel3.Contents c=(new Pracel3()).new Contents();
Pracel3.Destination d=(new Pracel3()).new Destination("Tasmania");
}
}
10.4 内部类和向上转型
当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。(从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效 果是一样的。)这是因为此内部类--某个接口的实现--能够完全不可见,并且不可用。所得到的只是指向基类或接口的引用,所以能够很方便地隐藏实现的细节。
我们可以创建前一个示例的接口:
package chapter10;
import chapter10.Contents;
import chapter10.Destination;
public class Pracel4 {
private class PContents implements Contents{
private int i=11;
public int value(){return i;}
}
protected class PDestination implements Destination{
private String label;
private PDestination(String label){this.label=label;}
public String readLabel(){return label;}
}
public Destination destination(String s){
return new PDestination(s);
}
public Contents contents(){
return new PContents();
}
public static void main(String[] args){
Pracel4 p=new Pracel4();
Destination pd= p.destination("Tasmania");
Contents c=p.contents();
Pracel4.PContents pc= p.new PContents(); //在同一个类就可以这样访问;若在不同类中,则不能访问私有类。
}
}
10.5 在方法和作用域内的内部类
到目前为止,所见的都是“平凡的”内部类,简单而且容易理解。然而,内部类的语法覆盖了大量的其他的更加难以理解的技术。例如。可以在一个方法里面或者在任意作用域内定义 内部类。这么做有两个理由:
1)如前所示,你实现了某类型的接口,于是可以创建并返回对其引用。
2)你要解决一个复杂的问题,想创建一个类用来辅助你的解决方案,但又不希望这个类是公共可用的。
下面的例子,先前的代码将被修改,以用于实现:
1)一个定义在方法中的类
2)一个定义在作用域中的类,此作用域在方法的内部
3)一个实现了接口的匿名类
4)一个匿名类,它扩展了有非默认构造器的类
5)一个匿名类,它执行字段初始化
6)一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)
下面这个例子展示了在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类。这称为局部内部类。
package chapter10;
import chapter10.Pracel4.PDestination;
/*@name DotNew.java
* @describe 10.5 在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类。这称为局部内部类。
* @since 2013-06-23 22:49
* @author 张彪
*/
public class Parcel5 {
public Destination destination(String s){
class PDestination implements Destination{
private String label;
private PDestination(String whereTo){this.label=whereTo;}
public String readLabel(){return label;}
}
return new PDestination(s);
}
public static void main(String[] args){
Parcel5 p=new Parcel5();
Destination d= p.destination("Tasmania");
System.out.println(d.readLabel());
}
}
10.5.1 在任意的作用域内嵌入一个内部类
package chapter10;
/*@name DotNew.java
* @describe 10.5 如何在任意的作用域内嵌入一个内部类
* @since 2013-06-23 22:49
* @author 张彪
*/
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String id){this.id=id;}
String getSlip(){return id;}
}
TrackingSlip ts=new TrackingSlip("slip");
String s=ts.getSlip();
}
}
public void track(){internalTracking(true);}
public static void main(String[] args){
Parcel6 p=new Parcel6();
p.track();
}
}
TrackingSlip类被嵌入在if语句的作用域内,这并不是说该类的创建是有条件的,它其实与别的类一起编译过了。
10.6 匿名内部类
看下面的这个例子看起来有点奇怪哦:
package chapter10;
/*@name DotNew.java
* @describe 10.7 匿名内部类
* @since 2013-06-24 9:00
* @author 张彪
*/
public class Parcel7 {
public Contents contents(){
return new Contents(){ //insert a class definition
private int i=11;
public int value(){return i;}
};
}
public static void main(String[] args){
Parcel7 p=new Parcel7();
Contents s =p.contents();
System.out.print(s.value());
}
}
contents()方法将返回值的生成与表示这个返回值的类的定义结合在一起!另外这个类是匿名的,它没有名字,更糟的是,看起来似乎是你正要创建一个Contents对象。但是然后你却说:"等一等,我想在这里插入一个类的定义。"
这种奇怪的语法指的是:“创建一个继承自Contents的匿名类的对象。”通过new表达式返回的引用被自动向上转型为对Contents的引用。
上述匿名内部类的语法是下述形式的简化形式:
package chapter10;
public class Parcel7b {
class MyContents implements Contents{
private int i=11;
public int value(){return i;}
}
public Contents contents(){
return new MyContents();
}
public static void main(String[] args){
Parcel7b p=new Parcel7b();
Contents s =p.contents();
System.out.print(s.value());
}
}
在匿名内部类中定义字段并执行初始化操作:
package chapter10;
/*@name DotNew.java
* @describe 10.6 匿名内部类中定义字段并执行初始化操作
* @since 2013-06-24 9:00
* @author 张彪
*/
public class Parcel9 {
public Destination destination(final String dest){
return new Destination(){
private String label=dest;
public String readLabel(){return dest;}
};
}
public static void main(String[] args){
Parcel9 p=new Parcel9();
Destination d=p.destination("Timanis");
System.out.println(d.readLabel());
}
}
注意:如果定义了一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译会要求其参数引用的是final的。如上例destination()方法,否则编译器会报错。
package chapter10;
public class Parcel10 {
public Destination destination(final String dest, final float price){
return new Destination(){
private int cost;
{
cost=Math.round(price);
if(cost>100){System.out.println("Over bugget!");}
}
private String label=dest;
public String readLabel(){return label;}
};
}
public static void main(String[] args){
Parcel10 p=new Parcel10();
Destination d=p.destination("Tamanis", 120);
}
}
匿名内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备。而且是如果实现了接口,也只能实现一个接口。
10.6.1 再访工厂方法
看看在使用内部类时,Factory实例变得多么美妙呀:
package chapter10;
/*@name DotNew.java
* @describe 10.6.1 再访工厂方法
* @since 2013-06-24 14:52
* @author 张彪
*/
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
private Implementation1(){}
public void method1(){System.out.println("Implementation1.method1()");}
public void method2(){System.out.println("Implementation1.method2()");}
public static ServiceFactory factory=new ServiceFactory(){
public Service getService(){
return new Implementation1();
}
};
}
class Implementation2 implements Service{
private Implementation2(){}
public void method1(){System.out.println("Implementation2.method1()");}
public void method2(){System.out.println("Implementation2.method2()");}
public static ServiceFactory factory=new ServiceFactory(){
public Service getService(){
return new Implementation2();
}
};
}
public class Factories {
public static void serviceConsumer(ServiceFactory factory){
Service s=factory.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
serviceConsumer(Implementation1.factory);
serviceConsumer(Implementation2.factory);
}
}
现在用于Implementation1和Implementation2的构造器都可以是private的,并且没有必要去创建作为工厂的具体名。另外,你经常只需要单一的工厂对象,因此在本历中它 被创建为Service实现中的一个static域。
10.7 嵌套类
如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。这通常称为嵌套类。想要理解static应用于内部类时的含义,就必须记住,普通的内部类对象隐式的保 存了一个引用,指向创建它的外围类对象。然后,当内部类为static时,就不是这样了,
当内部类为static时,嵌套类意味着:
1)要创建嵌套类的对象,并不需要外围类的对象
2)不能从嵌套类的对象中访问非静态的外围类对象
普通内部类和嵌套类的另一个区别为:普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。但是嵌套类可 以包含所有这些东西。
package chapter10.innerclass;
import chapter10.Contents;
import chapter10.Destination;
public class Parcel11 {
private static class ParcelContents implements Contents{
private int i=11;
public int value(){return i;}
}
protected static class ParcelDestination implements Destination{
private String label;
public ParcelDestination(String label){this.label=label;}
public String readLabel(){return label;}
public static void f(){}
static int x=10;
static class AnotherLevel{
public static void f(){}
static int x=10;
}
}
public static Destination destination(String s){return new ParcelDestination(s);}
public static Contents contents(){return new ParcelContents();}
public static void main(String[] args){
Contents c=contents();
Destination d=destination("Tasmania");
d.readLabel();
}
}
在一个普通(非static)的内部类中,通过一个特殊的this引用可以连接到外围类的对象。嵌套类中没有这个特殊的this引用,这使得它类似于一个static方法。
10.7.1 接口内部的类
正常情况下,不能在内部类中放置任何代码,但嵌套类可以作为接口的一部分。你放到接口中的任何类型都自动地是public和static的。只是将嵌套类置于接口的命名空间内,这并 不违反接口的规则。你甚至可以在内部类中实现其外围接口。如下:
package chapter10.innerclass;
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface{
public void howdy(){
System.out.println("-------");
}
public static void main(String[] args){
new Test().howdy();
}
}
}
如果你想创建公共代码,使得他们可以被某个接口的所有不同实现所共用,那么使用内部的嵌套类会显得很方便。
10.7.2 从多层嵌套中访问外部类的成员
一个内部类被嵌套多少层并不重要------它能透明地访问所有它所嵌入的外围类的所以成员。 如下所示:
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.7.2 从多层嵌套中访问外部类的成员
* @since 2013-06-24 16:14
* @author 张彪
*/
class MNA{
private void f(){}
class A{
private void g(){}
public class B{
void h(){
g();
f();
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args){
MNA m=new MNA();
MNA.A mnaa=m.new A(); //使用外部类.new来创建内部类对象
MNA.A.B mnab=mnaa.new B(); //使用外部类.new来创建内部类对象
mnab.h();
}
}
10.8 为什么需要内部类
使用内部类的原因:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没用影响。
10.5.1 闭包与回调
闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含外围类对象的信 息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括Private成员。
Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制。以允许回调。
package chapter10.innerclass;
interface Incrementable{ void increment();}
class Callee1 implements Incrementable{
private int i=0;
public void increment(){
i++;
System.out.println();
}
}
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){this.CallbackReference=cbh;}
void go(){CallbackReference.increment();}
}
public class Callbacks {
public static void main(String[] args){
Callee1 c1=new Callee1();
Callee2 c2=new Callee2();
MyIncrement.f(c2);
Caller call1=new Caller(c1);
Caller call2=new Caller(c2.getCallbackReference());
call1.go();
call2.go();
}
}
上面这个例子展示了外围类实现一个接口与内部类实现接口直接的区别。就代码而言,Callee1是简单的解决方法,Callee2继承MyIncrement类,并用内部类实现了Incrementable接口。
10.5.2 内部类与控制框架
在将要介绍的控制框架中(control framework)中,可以看到更多使用内部类的具体例子。
应用程序框架(application framework)就是被设计用于解决某类特定问题的一个类或一组类。
详见类chapter10\greenhouse\GreenHouseControllers.java
有关命令设计模式见类chapter10\greenhouse\GreenHouseController.java
10.9 内部类的继承
因为内部类的构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候,事情会变得有点复杂。问题在于,哪个执行外围类对象的“秘密的”引用必须被初始化,而在导出类中 不再存在可连接的默认对象。要解决这个问题,必须使用特殊的语法来说明他们之间的关系。
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.9 内部类的继承
* @since 2013-06-24 19:23
* @author 张彪
*/
class WithInner{
class Inner{}
}
public class InheritInner extends WithInner.Inner{
InheritInner(WithInner wi){
wi.super();
}
public static void main(String[] args){
WithInner w=new WithInner();
InheritInner h=new InheritInner(w);
}
}
可以 InheritInner类只是基础内部类,而不是外围类。但是当要生成一个构造器时,默认的构造器并不算好,而且不能只是传递一个指向外围类对象的引用 而已。此外,必须在构造器内部使用如下语法:
enclosingClassReference.super();
10.10 内部类可以被覆盖吗
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.10 内部类可以被覆盖吗
* @since 2013-06-24 19:34
* @author 张彪
*/
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){System.out.println("Egg.Yolk()");}
}
public Egg(){
System.out.println("New.Yolk()");
y=new Yolk();
}
}
public class BigEgg extends Egg{
public class Yolk{
public Yolk(){System.out.println("BigEgg.Yolk()");}
}
public static void main(String[] args){
BigEgg b=new BigEgg();
Yolk y=b.new Yolk();
}
}
/*New.Yolk()
Egg.Yolk()
BigEgg.Yolk()*/
注意:从输出的结果来看,符合程序的处理思维,个人认为是正常,但是好像书本上将的。。。。。。。有点晕。
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.10 明确继承某个内部类
* @since 2013-06-24 19:34
* @author 张彪
*/
class Egg2{
protected class Yolk{
public Yolk(){System.out.println("Egg2.Yolk()");}
public void f(){System.out.println("Egg2.Yolk.f()");}
}
private Yolk y=new Yolk();
public Egg2(){
System.out.println("New Egg2()");
}
public void insertYolk(Yolk yy){this.y=yy;}
public void g(){y.f();}
}
public class BigEgg2 extends Egg2{
public class Yolk extends Egg2.Yolk{ //明确地继承某个内部类
public Yolk(){System.out.println("BigEgg2.Yolk()");}
public void f(){System.out.println("BigEgg2.Yolk.f()");}
}
public BigEgg2(){
insertYolk(new Yolk());
}
public static void main(String[] args){
Egg2 e=new BigEgg2();
e.g();
}
}
/*Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()*/
P:上面这个例子的输出结果看的有点晕乎。。。。。。。
10.11 局部内部类
可以在代码块中创建内部类,典型的方式是在一个方法体的里面创建。局部内部类不能有访问说明符,因为它不是外部类的一部分;但是它可以访问当前代码块中的常量以及此外围类的所有成员。
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.11 局部类
* @since 2013-06-24 20:09
* @author 张彪
*/
interface Counter{
int next();
}
public class LocalInnerClass {
private int count=0;
Counter getCounter1(final String name){
//a local inner class
class LocalCounter implements Counter{
public LocalCounter(){
//local inner class can hava a constructor
System.out.print("LocalCounter()");
}
public int next(){
System.out.println(name);
return count++;
}
}
return new LocalCounter();
}
//the same thing with an anonymous(匿名) inner class
Counter getCounter2(final String name){
return new Counter(){
//anonymous inner class cannot hava a named
{
System.out.println("Counter2()");
}
public int next(){
return count++;
}
};
}
public static void main(String[] args){
LocalInnerClass l=new LocalInnerClass();
Counter c1=l.getCounter1("Local inner"),
c2=l.getCounter2("Anonymous inner");
for(int i=0;i<5;i++){
System.out.println(c1.next());
}
}
}
上例中我们分别使用局部内部类和匿名内部类实现了同样的功能,他们具有相同的行为和能力。既然局部内部类的名字在方法外是不可见的,那为什么我们仍然使用局部内部类 而不是匿名内部类呢?唯一的理由是:我们需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。
10.12 内部类标识
内部类的文件也必须是以.class文件格式,而且内部类的文件命名有严格的规则:外围类的名字,加上“$”再加上内部类的名字。例如
LocalInnerClass$1LocalCounter.class
Parcel11$ParcelDestination.class
Parcel11$ParcelDestination$AnotherLevel.class
10.13 总结
随着时间的推移,读者将能够更好的识别在什么情况下使用接口,什么情况下使用内部类,或者两者同时同时,此时你至少应该已经理解了他们的语法和语义。
Good Luck!!!
可以将一个类的定义放在另一个类的定义内部,这就是内部类。
内部类允许你把一些逻辑相关的类组织在一起,并控制位于内部类的可见性。 内部类与组合不同。
10.1 创建内部类
创建内部类的方式就如你想的一样----把类的定义置于外围类的里面。
package chapter10;
/*@name RandomDoubles.java
* @describe 10.1 创建内部类
* @since 2013-06-23 16:59
* @author 张彪
*/
public class Parcel1 {
class Contents{
private int i=11;
public int value(){return i;}
}
class Desination{
private String label;
Desination(String label){this.label=label;}
String readLabel(){return label;}
}
public void ship(String dest){
Contents c=new Contents();
Desination d=new Desination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args){
Parcel1 p=new Parcel1();
p.ship("Tasmania");
}
}
//当我们在ship()方法里面使用内部类的时候,与使用不同类没什么区别。在这里,实际的区别只是内部类的名字嵌套在Parel1里面的。更典型的情况是,外部类将有一个方法,方法返回一个指向内部类的引用,就像在to和contents()方法中看到的那样。
package chapter10;
/*@name RandomDoubles.java
* @describe 10.1 创建内部类
* @since 2013-06-23 16:59
* @author 张彪
*/
public class Parcel2 {
class Contents{
private int i=11;
public int value(){return i;}
}
class Desination{
private String label;
Desination(String label){
this.label=label;
}
String readLabel(){
return label;
}
}
public Desination to(String s){
return new Desination(s);
}
public Contents contents(){
return new Contents();
}
public void ship(String dest){
Contents c=new Contents();
Desination d=new Desination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args){
Parcel2 p=new Parcel2();
p.ship("Tasmania");
Parcel2.Contents c=p.contents();
Parcel2.Desination d= p.to("Boring");
}
}
//如果想在外部类的非静态方法中之外的任何位置创建某个内部类的对象。那么必须在main()方法中那样,具体地指明这个对象的类型。OuterClassName.InnerClassName.
10.2 链接到外部类
到目前为止,内部类似乎还只是一种名字隐藏和组织代码的模式。这些是很有用,但还不是最引人注目的。当生成一个内部类的对象时,此对象与制造它的外围对象之间就有了一种联 系,所以它能访问其外围对象的所有成员,而不需要任何特殊条件。此外,内部类还拥有其他外围类的所有元素的访问权限。(这与C++嵌套类的设计非常不同,在C++中只是单纯的名字隐藏 机制,与外围对象没有联系)
package chapter10;
/*@name Sequence.java
* @describe 10.2 链接到外部类
* @since 2013-06-23 17:48
* @author 张彪
*/
interface Selector{
boolean end();
Object current();
void next();
}
public class Sequence {
private Object[] items;
private int next=0;
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 boolean end(){return i==items.length;}
public Object current(){return items[i];}
public void next(){if(i<items.length){i++;}}
}
public Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args){
Sequence s=new Sequence(10);
for(int i=0;i<10;i++){
s.add(Integer.toString(i));
}
Selector selector=s.selector();
while(!selector.end()){
System.out.println(selector.current());
selector.next();
}
}
}
注意:内部类自动拥有对外围类所有成员的访问权限。这是如何做到的呢?当某个外围类的对象创建了一个内部类对象是,此内部类对象必定会秘密地捕获一个指向那个外围类的引用。
10.3 使用.this和.new
10.3.1 .this的用法
如果你需要生成对外边对象的引用,可以使用外边类的名字后面紧跟圆点和this。这样产生的引用自动地具有正确的类型。
package chapter10;
/*@name DotThis.java
* @describe 10.3 使用.this和.new
* @since 2013-06-23 17:48
* @author 张彪
*/
public class DotThis {
void f(){System.out.println("DotThis.f()");}
public class Inner{
public DotThis outer(){
return DotThis.this; //注意:this的使用
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args){
DotThis d=new DotThis();
DotThis.Inner n= d.inner();
n.outer().f();
}
}
10.3.2 .new的用法
有时你可能要告知某些其他对象,去创建其某个内部类的对象。要实现此目的,你必须在new表达式中提供对其他外部对象的引用,这是需要使用.new语法。例如:
package chapter10;
/*@name DotNew.java
* @describe 10.3 使用.this和.new
* @since 2013-06-23 18:48
* @author 张彪
*/
public class DotNew {
public class Inner{}
public static void main(String[] args){
DotNew dn=new DotNew();
DotNew.Inner n=dn.new Inner(); //注意.new的用法
//dn.new DotNew.Inner(); 不能这样声明
//Inner r=new Inner(); 也不能这样声明
}
}
要想直接创建内部类的对象,必须使用外部类的对象来创建内部类对象。这样解决了内部类名字作用域的问题。因此你不必声明(实际上你不能声明)dn.new DotNew.Inner()
10.3.4 嵌套类(静态内部类)
在拥有外部类对象之前是不可能创建内部类对象的。这是因为内部类对象会暗暗地链接到创建它的外部类对象上。但是如果你创建的是嵌套类(静态内部类),那么它就不需 要对外部类对象的引用。
package chapter10;
/*@name DotNew.java
* @describe 10.3 嵌套类(静态内部类)
* @since 2013-06-23 19:11
* @author 张彪
*/
public class Pracel3 {
class Contents{
private int i=11;
public int value(){return i;}
}
class Destination{
private String label;
Destination(String whereTo){this.label=whereTo;}
String readLabel(){return label;}
}
public static void main(String[] args){
//Must use instance of outer class to create an instance of the inner class
Pracel3.Contents c=(new Pracel3()).new Contents();
Pracel3.Destination d=(new Pracel3()).new Destination("Tasmania");
}
}
10.4 内部类和向上转型
当将内部类向上转型为其基类,尤其是转型为一个接口的时候,内部类就有了用武之地。(从实现了某个接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效 果是一样的。)这是因为此内部类--某个接口的实现--能够完全不可见,并且不可用。所得到的只是指向基类或接口的引用,所以能够很方便地隐藏实现的细节。
我们可以创建前一个示例的接口:
package chapter10;
import chapter10.Contents;
import chapter10.Destination;
public class Pracel4 {
private class PContents implements Contents{
private int i=11;
public int value(){return i;}
}
protected class PDestination implements Destination{
private String label;
private PDestination(String label){this.label=label;}
public String readLabel(){return label;}
}
public Destination destination(String s){
return new PDestination(s);
}
public Contents contents(){
return new PContents();
}
public static void main(String[] args){
Pracel4 p=new Pracel4();
Destination pd= p.destination("Tasmania");
Contents c=p.contents();
Pracel4.PContents pc= p.new PContents(); //在同一个类就可以这样访问;若在不同类中,则不能访问私有类。
}
}
10.5 在方法和作用域内的内部类
到目前为止,所见的都是“平凡的”内部类,简单而且容易理解。然而,内部类的语法覆盖了大量的其他的更加难以理解的技术。例如。可以在一个方法里面或者在任意作用域内定义 内部类。这么做有两个理由:
1)如前所示,你实现了某类型的接口,于是可以创建并返回对其引用。
2)你要解决一个复杂的问题,想创建一个类用来辅助你的解决方案,但又不希望这个类是公共可用的。
下面的例子,先前的代码将被修改,以用于实现:
1)一个定义在方法中的类
2)一个定义在作用域中的类,此作用域在方法的内部
3)一个实现了接口的匿名类
4)一个匿名类,它扩展了有非默认构造器的类
5)一个匿名类,它执行字段初始化
6)一个匿名类,它通过实例初始化实现构造(匿名类不可能有构造器)
下面这个例子展示了在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类。这称为局部内部类。
package chapter10;
import chapter10.Pracel4.PDestination;
/*@name DotNew.java
* @describe 10.5 在方法的作用域内(而不是在其他类的作用域内)创建一个完整的类。这称为局部内部类。
* @since 2013-06-23 22:49
* @author 张彪
*/
public class Parcel5 {
public Destination destination(String s){
class PDestination implements Destination{
private String label;
private PDestination(String whereTo){this.label=whereTo;}
public String readLabel(){return label;}
}
return new PDestination(s);
}
public static void main(String[] args){
Parcel5 p=new Parcel5();
Destination d= p.destination("Tasmania");
System.out.println(d.readLabel());
}
}
10.5.1 在任意的作用域内嵌入一个内部类
package chapter10;
/*@name DotNew.java
* @describe 10.5 如何在任意的作用域内嵌入一个内部类
* @since 2013-06-23 22:49
* @author 张彪
*/
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip{
private String id;
TrackingSlip(String id){this.id=id;}
String getSlip(){return id;}
}
TrackingSlip ts=new TrackingSlip("slip");
String s=ts.getSlip();
}
}
public void track(){internalTracking(true);}
public static void main(String[] args){
Parcel6 p=new Parcel6();
p.track();
}
}
TrackingSlip类被嵌入在if语句的作用域内,这并不是说该类的创建是有条件的,它其实与别的类一起编译过了。
10.6 匿名内部类
看下面的这个例子看起来有点奇怪哦:
package chapter10;
/*@name DotNew.java
* @describe 10.7 匿名内部类
* @since 2013-06-24 9:00
* @author 张彪
*/
public class Parcel7 {
public Contents contents(){
return new Contents(){ //insert a class definition
private int i=11;
public int value(){return i;}
};
}
public static void main(String[] args){
Parcel7 p=new Parcel7();
Contents s =p.contents();
System.out.print(s.value());
}
}
contents()方法将返回值的生成与表示这个返回值的类的定义结合在一起!另外这个类是匿名的,它没有名字,更糟的是,看起来似乎是你正要创建一个Contents对象。但是然后你却说:"等一等,我想在这里插入一个类的定义。"
这种奇怪的语法指的是:“创建一个继承自Contents的匿名类的对象。”通过new表达式返回的引用被自动向上转型为对Contents的引用。
上述匿名内部类的语法是下述形式的简化形式:
package chapter10;
public class Parcel7b {
class MyContents implements Contents{
private int i=11;
public int value(){return i;}
}
public Contents contents(){
return new MyContents();
}
public static void main(String[] args){
Parcel7b p=new Parcel7b();
Contents s =p.contents();
System.out.print(s.value());
}
}
在匿名内部类中定义字段并执行初始化操作:
package chapter10;
/*@name DotNew.java
* @describe 10.6 匿名内部类中定义字段并执行初始化操作
* @since 2013-06-24 9:00
* @author 张彪
*/
public class Parcel9 {
public Destination destination(final String dest){
return new Destination(){
private String label=dest;
public String readLabel(){return dest;}
};
}
public static void main(String[] args){
Parcel9 p=new Parcel9();
Destination d=p.destination("Timanis");
System.out.println(d.readLabel());
}
}
注意:如果定义了一个匿名内部类,并且希望它使用一个在其外部定义的对象,那么编译会要求其参数引用的是final的。如上例destination()方法,否则编译器会报错。
package chapter10;
public class Parcel10 {
public Destination destination(final String dest, final float price){
return new Destination(){
private int cost;
{
cost=Math.round(price);
if(cost>100){System.out.println("Over bugget!");}
}
private String label=dest;
public String readLabel(){return label;}
};
}
public static void main(String[] args){
Parcel10 p=new Parcel10();
Destination d=p.destination("Tamanis", 120);
}
}
匿名内部类与正规的继承相比有些受限,因为匿名内部类既可以扩展类,也可以实现接口,但是不能两者兼备。而且是如果实现了接口,也只能实现一个接口。
10.6.1 再访工厂方法
看看在使用内部类时,Factory实例变得多么美妙呀:
package chapter10;
/*@name DotNew.java
* @describe 10.6.1 再访工厂方法
* @since 2013-06-24 14:52
* @author 张彪
*/
interface Service{
void method1();
void method2();
}
interface ServiceFactory{
Service getService();
}
class Implementation1 implements Service{
private Implementation1(){}
public void method1(){System.out.println("Implementation1.method1()");}
public void method2(){System.out.println("Implementation1.method2()");}
public static ServiceFactory factory=new ServiceFactory(){
public Service getService(){
return new Implementation1();
}
};
}
class Implementation2 implements Service{
private Implementation2(){}
public void method1(){System.out.println("Implementation2.method1()");}
public void method2(){System.out.println("Implementation2.method2()");}
public static ServiceFactory factory=new ServiceFactory(){
public Service getService(){
return new Implementation2();
}
};
}
public class Factories {
public static void serviceConsumer(ServiceFactory factory){
Service s=factory.getService();
s.method1();
s.method2();
}
public static void main(String[] args){
serviceConsumer(Implementation1.factory);
serviceConsumer(Implementation2.factory);
}
}
现在用于Implementation1和Implementation2的构造器都可以是private的,并且没有必要去创建作为工厂的具体名。另外,你经常只需要单一的工厂对象,因此在本历中它 被创建为Service实现中的一个static域。
10.7 嵌套类
如果不需要内部类对象与其外围类对象之间有联系,那么可以将内部类声明为static。这通常称为嵌套类。想要理解static应用于内部类时的含义,就必须记住,普通的内部类对象隐式的保 存了一个引用,指向创建它的外围类对象。然后,当内部类为static时,就不是这样了,
当内部类为static时,嵌套类意味着:
1)要创建嵌套类的对象,并不需要外围类的对象
2)不能从嵌套类的对象中访问非静态的外围类对象
普通内部类和嵌套类的另一个区别为:普通内部类的字段与方法,只能放在类的外部层次上,所以普通的内部类不能有static数据和static字段,也不能包含嵌套类。但是嵌套类可 以包含所有这些东西。
package chapter10.innerclass;
import chapter10.Contents;
import chapter10.Destination;
public class Parcel11 {
private static class ParcelContents implements Contents{
private int i=11;
public int value(){return i;}
}
protected static class ParcelDestination implements Destination{
private String label;
public ParcelDestination(String label){this.label=label;}
public String readLabel(){return label;}
public static void f(){}
static int x=10;
static class AnotherLevel{
public static void f(){}
static int x=10;
}
}
public static Destination destination(String s){return new ParcelDestination(s);}
public static Contents contents(){return new ParcelContents();}
public static void main(String[] args){
Contents c=contents();
Destination d=destination("Tasmania");
d.readLabel();
}
}
在一个普通(非static)的内部类中,通过一个特殊的this引用可以连接到外围类的对象。嵌套类中没有这个特殊的this引用,这使得它类似于一个static方法。
10.7.1 接口内部的类
正常情况下,不能在内部类中放置任何代码,但嵌套类可以作为接口的一部分。你放到接口中的任何类型都自动地是public和static的。只是将嵌套类置于接口的命名空间内,这并 不违反接口的规则。你甚至可以在内部类中实现其外围接口。如下:
package chapter10.innerclass;
public interface ClassInInterface {
void howdy();
class Test implements ClassInInterface{
public void howdy(){
System.out.println("-------");
}
public static void main(String[] args){
new Test().howdy();
}
}
}
如果你想创建公共代码,使得他们可以被某个接口的所有不同实现所共用,那么使用内部的嵌套类会显得很方便。
10.7.2 从多层嵌套中访问外部类的成员
一个内部类被嵌套多少层并不重要------它能透明地访问所有它所嵌入的外围类的所以成员。 如下所示:
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.7.2 从多层嵌套中访问外部类的成员
* @since 2013-06-24 16:14
* @author 张彪
*/
class MNA{
private void f(){}
class A{
private void g(){}
public class B{
void h(){
g();
f();
}
}
}
}
public class MultiNestingAccess {
public static void main(String[] args){
MNA m=new MNA();
MNA.A mnaa=m.new A(); //使用外部类.new来创建内部类对象
MNA.A.B mnab=mnaa.new B(); //使用外部类.new来创建内部类对象
mnab.h();
}
}
10.8 为什么需要内部类
使用内部类的原因:每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没用影响。
10.5.1 闭包与回调
闭包(closure)是一个可调用的对象,它记录了一些信息,这些信息来自于创建它的作用域。通过这个定义,可以看出内部类是面向对象的闭包,因为它不仅包含外围类对象的信 息,还自动拥有一个指向此外围类对象的引用,在此作用域内,内部类有权操作所有的成员,包括Private成员。
Java最引人争议的问题之一就是,人们认为Java应该包含某种类似指针的机制。以允许回调。
package chapter10.innerclass;
interface Incrementable{ void increment();}
class Callee1 implements Incrementable{
private int i=0;
public void increment(){
i++;
System.out.println();
}
}
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){this.CallbackReference=cbh;}
void go(){CallbackReference.increment();}
}
public class Callbacks {
public static void main(String[] args){
Callee1 c1=new Callee1();
Callee2 c2=new Callee2();
MyIncrement.f(c2);
Caller call1=new Caller(c1);
Caller call2=new Caller(c2.getCallbackReference());
call1.go();
call2.go();
}
}
上面这个例子展示了外围类实现一个接口与内部类实现接口直接的区别。就代码而言,Callee1是简单的解决方法,Callee2继承MyIncrement类,并用内部类实现了Incrementable接口。
10.5.2 内部类与控制框架
在将要介绍的控制框架中(control framework)中,可以看到更多使用内部类的具体例子。
应用程序框架(application framework)就是被设计用于解决某类特定问题的一个类或一组类。
详见类chapter10\greenhouse\GreenHouseControllers.java
有关命令设计模式见类chapter10\greenhouse\GreenHouseController.java
10.9 内部类的继承
因为内部类的构造器必须连接到指向其外围类对象的引用,所以在继承内部类的时候,事情会变得有点复杂。问题在于,哪个执行外围类对象的“秘密的”引用必须被初始化,而在导出类中 不再存在可连接的默认对象。要解决这个问题,必须使用特殊的语法来说明他们之间的关系。
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.9 内部类的继承
* @since 2013-06-24 19:23
* @author 张彪
*/
class WithInner{
class Inner{}
}
public class InheritInner extends WithInner.Inner{
InheritInner(WithInner wi){
wi.super();
}
public static void main(String[] args){
WithInner w=new WithInner();
InheritInner h=new InheritInner(w);
}
}
可以 InheritInner类只是基础内部类,而不是外围类。但是当要生成一个构造器时,默认的构造器并不算好,而且不能只是传递一个指向外围类对象的引用 而已。此外,必须在构造器内部使用如下语法:
enclosingClassReference.super();
10.10 内部类可以被覆盖吗
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.10 内部类可以被覆盖吗
* @since 2013-06-24 19:34
* @author 张彪
*/
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){System.out.println("Egg.Yolk()");}
}
public Egg(){
System.out.println("New.Yolk()");
y=new Yolk();
}
}
public class BigEgg extends Egg{
public class Yolk{
public Yolk(){System.out.println("BigEgg.Yolk()");}
}
public static void main(String[] args){
BigEgg b=new BigEgg();
Yolk y=b.new Yolk();
}
}
/*New.Yolk()
Egg.Yolk()
BigEgg.Yolk()*/
注意:从输出的结果来看,符合程序的处理思维,个人认为是正常,但是好像书本上将的。。。。。。。有点晕。
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.10 明确继承某个内部类
* @since 2013-06-24 19:34
* @author 张彪
*/
class Egg2{
protected class Yolk{
public Yolk(){System.out.println("Egg2.Yolk()");}
public void f(){System.out.println("Egg2.Yolk.f()");}
}
private Yolk y=new Yolk();
public Egg2(){
System.out.println("New Egg2()");
}
public void insertYolk(Yolk yy){this.y=yy;}
public void g(){y.f();}
}
public class BigEgg2 extends Egg2{
public class Yolk extends Egg2.Yolk{ //明确地继承某个内部类
public Yolk(){System.out.println("BigEgg2.Yolk()");}
public void f(){System.out.println("BigEgg2.Yolk.f()");}
}
public BigEgg2(){
insertYolk(new Yolk());
}
public static void main(String[] args){
Egg2 e=new BigEgg2();
e.g();
}
}
/*Egg2.Yolk()
New Egg2()
Egg2.Yolk()
BigEgg2.Yolk()
BigEgg2.Yolk.f()*/
P:上面这个例子的输出结果看的有点晕乎。。。。。。。
10.11 局部内部类
可以在代码块中创建内部类,典型的方式是在一个方法体的里面创建。局部内部类不能有访问说明符,因为它不是外部类的一部分;但是它可以访问当前代码块中的常量以及此外围类的所有成员。
package chapter10.innerclass;
/*@name DotNew.java
* @describe 10.11 局部类
* @since 2013-06-24 20:09
* @author 张彪
*/
interface Counter{
int next();
}
public class LocalInnerClass {
private int count=0;
Counter getCounter1(final String name){
//a local inner class
class LocalCounter implements Counter{
public LocalCounter(){
//local inner class can hava a constructor
System.out.print("LocalCounter()");
}
public int next(){
System.out.println(name);
return count++;
}
}
return new LocalCounter();
}
//the same thing with an anonymous(匿名) inner class
Counter getCounter2(final String name){
return new Counter(){
//anonymous inner class cannot hava a named
{
System.out.println("Counter2()");
}
public int next(){
return count++;
}
};
}
public static void main(String[] args){
LocalInnerClass l=new LocalInnerClass();
Counter c1=l.getCounter1("Local inner"),
c2=l.getCounter2("Anonymous inner");
for(int i=0;i<5;i++){
System.out.println(c1.next());
}
}
}
上例中我们分别使用局部内部类和匿名内部类实现了同样的功能,他们具有相同的行为和能力。既然局部内部类的名字在方法外是不可见的,那为什么我们仍然使用局部内部类 而不是匿名内部类呢?唯一的理由是:我们需要一个已命名的构造器,或者需要重载构造器,而匿名内部类只能用于实例初始化。
10.12 内部类标识
内部类的文件也必须是以.class文件格式,而且内部类的文件命名有严格的规则:外围类的名字,加上“$”再加上内部类的名字。例如
LocalInnerClass$1LocalCounter.class
Parcel11$ParcelDestination.class
Parcel11$ParcelDestination$AnotherLevel.class
10.13 总结
随着时间的推移,读者将能够更好的识别在什么情况下使用接口,什么情况下使用内部类,或者两者同时同时,此时你至少应该已经理解了他们的语法和语义。
Good Luck!!!
相关推荐
在使用匿名内部类时,要记住以下几个原则:匿名内部类不能有构造方法、匿名内部类不能是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. **静态内部类**: 静态内部类与普通的成员内部类不同,它不持有对外部类的引用。因此,可以像其他静态成员一样,...