Java编程思想第四版第十章学习——内部类(1)
2016-05-30 23:45
337 查看
内部类是指在一个外部类的内部再定义一个类。类名不需要和文件名相同。
注意:成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的。
(1)可以实现某个接口,从而可以创建并返回对其的引用
(2)创建一个类来辅助解决复杂问题,并且这个类是不可用的。
局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
从格式上可以发现,使用匿名构造类必须要继承一个父类或者实现一个接口,且不能同时发生。匿名构造类没有class关键字,直接使用new来生成一个对象的引用(隐式)。例子如下:
注意
在使用匿名内部类的过程中,我们需要注意如下几点:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
6、匿名内部类仅能使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用。
方法的形参需要设置为final
给匿名内部类传递参数的时候,若该形参在内部类中需要被使用,那么该形参必须要为final。也就是说:当所在的方法的形参需要被内部类里面使用时,该形参必须为final。例如
内部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上是自己的属性而不是外部方法传递进来的参数。
但是为什么要加final呢?因为为了保持内部类和外部类的形参的一致性。通过拷贝引用,内部类为了避免引用值发生改变,如外部类的方法修改而导致内部类得到的值不一致。于是就用final让引用不可改变。
匿名内部类的初始化
匿名内部类中没有构造器,一般通过代码块来完成初始化工作。
嵌套类与普通内部类的区别:
普通内部类对象隐式地保存了一个引用,指向创建它的外围类对象,而要创建嵌套类对象,不需要其外围类的对象,也不能从嵌套类的对象中访问非静态的外围类对象。
接口内部的类
正常情况下,不能在接口内部放置任何代码。但嵌套类可以作为接口的一部分,放到接口中的任何类都自动地是public和static。
甚至可以在内部类中实现外围接口,如下所示
测试小技巧:
如果在每个类中都编写一个main()方法来测试这个类,那就必须带着那些已经编译过的额外代码,这带来额外的开销。此时可以用嵌套类来放置测试代码。
在编译后,上述代码会生成一个独立的测试类TestBedTester(在Unix/Linux系统中必须转义)。可以用这个类来测试,但是不必在发布的产品中包含它,在将产品打包前删去这个测试类。
从多层嵌套类中访问外部类的成员
一个内部类即使被嵌套多层,它也能透明地访问所有它所嵌入的外围类的所有成员。
1、成员内部类
成员内部类,就是作为外部类的成员,可以直接使用外部类的所有成员和方法,即使是private的。同时外部类要访问内部类的所有成员变量/方法,则需要通过内部类的对象来获取。注意:成员内部类不能含有static的变量和方法。因为成员内部类需要先创建了外部类,才能创建它自己的。
2、成员内部类的引用和创建
在内部类要生成对外部类对象的引用,可以使用外部类的名字后紧跟”.this”。而想直接创建内部类的对象,必须使用外部类的对象来创建该内部类对象,可以使用外部类的变量名后紧跟“.new”。注意,在外部类对象之前不能创建内部类对象,除非创建的是嵌套类(静态内部类)。3、局部内部类——在方法和作用域中定义内部类
可以在一个方法里面或者在任意的作用域内定义内部类。这么做有两个好处:(1)可以实现某个接口,从而可以创建并返回对其的引用
(2)创建一个类来辅助解决复杂问题,并且这个类是不可用的。
//定义在方法之内的内部类——Java编程思想例子 public class Parcel4 { public Destination destination(String s) { class PDestination implements Destination { private String label; private PDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new PDestination(s); } public static void main(String[] args) { Parcel4 p = new Parcel4(); Destination d = p.destination("Tasmania"); } }
//定义在if作用域的内部类——Java编程思想例子 public class Parcel5 { private void internalTracking(boolean b) { if (b) { class TrackingSlip { private String id; TrackingSlip(String s) { id = s; } String getSlip() { return id; } } TrackingSlip ts = new TrackingSlip("slip"); String s = ts.getSlip(); } } public void track() { internalTracking(true); } public static void main(String[] args) { Parcel5 p = new Parcel5(); p.track(); } }
局部内部类也像别的类一样进行编译,但只是作用域不同而已,只在该方法或条件的作用域内才能使用,退出这些作用域后无法引用的。
4、匿名内部类
匿名内部类创建格式如下:new 父类构造器(参数列表)|实现接口() { //匿名内部类的类体部分 }
从格式上可以发现,使用匿名构造类必须要继承一个父类或者实现一个接口,且不能同时发生。匿名构造类没有class关键字,直接使用new来生成一个对象的引用(隐式)。例子如下:
interface Hello{ void say(); } public class Dada{ public static void main(String[] args){ Hello h = new Hello(){ public void say(){ System.out.println("C++"); } }; h.say(); } }/*Output C++ *///
abstract class Hello{ public abstract void say(); } public class Dada{ public static void main(String[] args){ Hello h = new Hello(){ public void say(){ System.out.println("C++"); } }; h.say(); } }/*Output C++ *///
注意
在使用匿名内部类的过程中,我们需要注意如下几点:
1、使用匿名内部类时,我们必须是继承一个类或者实现一个接口,但是两者不可兼得,同时也只能继承一个类或者实现一个接口。
2、匿名内部类中是不能定义构造函数的。
3、匿名内部类中不能存在任何的静态成员变量和静态方法。
4、匿名内部类为局部内部类,所以局部内部类的所有限制同样对匿名内部类生效。
5、匿名内部类不能是抽象的,它必须要实现继承的类或者实现的接口的所有抽象方法。
6、匿名内部类仅能使用一次,创建匿名内部类时它会立即创建一个该类的实例,该类的定义会立即消失,所以匿名内部类是不能够被重复使用。
方法的形参需要设置为final
给匿名内部类传递参数的时候,若该形参在内部类中需要被使用,那么该形参必须要为final。也就是说:当所在的方法的形参需要被内部类里面使用时,该形参必须为final。例如
public class OuterClass { public void display(final String name,String age){ class InnerClass{ void display(){ System.out.println(name); } } } }
内部类并不是直接调用方法传递的参数,而是利用自身的构造器对传入的参数进行备份,自己内部方法调用的实际上是自己的属性而不是外部方法传递进来的参数。
但是为什么要加final呢?因为为了保持内部类和外部类的形参的一致性。通过拷贝引用,内部类为了避免引用值发生改变,如外部类的方法修改而导致内部类得到的值不一致。于是就用final让引用不可改变。
匿名内部类的初始化
匿名内部类中没有构造器,一般通过代码块来完成初始化工作。
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 budget!"); } private String label = dest; public String readLabel() {return label;} }; } public static void main(String[] args){ Parcel10 p = new Parcel10(); Destination d = p.destination("Tasmania",101.395F); } }/*Output Over budget! *///
5、嵌套类
如果不需要内部类与其外围类对象之间的联系,可以将内部类声明为static,通常称为嵌套类。嵌套类与普通内部类的区别:
普通内部类对象隐式地保存了一个引用,指向创建它的外围类对象,而要创建嵌套类对象,不需要其外围类的对象,也不能从嵌套类的对象中访问非静态的外围类对象。
接口内部的类
正常情况下,不能在接口内部放置任何代码。但嵌套类可以作为接口的一部分,放到接口中的任何类都自动地是public和static。
甚至可以在内部类中实现外围接口,如下所示
public interface ClassInInterface{ void howdy(); class Test implements ClassInInterface { public void howdy(){ System.out.println("Howdy!"); } public static void main(String[] args){ new Test().howdy(); } } }/*Output: Howdy! *///
测试小技巧:
如果在每个类中都编写一个main()方法来测试这个类,那就必须带着那些已经编译过的额外代码,这带来额外的开销。此时可以用嵌套类来放置测试代码。
public class TestBed{ public void f() {System.out.println("f()");} public static class Tester { public static void main(String[] args){ TestBed t = new TestBed(); t.f(); } } }/*Output: f() *///
在编译后,上述代码会生成一个独立的测试类TestBedTester(在Unix/Linux系统中必须转义)。可以用这个类来测试,但是不必在发布的产品中包含它,在将产品打包前删去这个测试类。
从多层嵌套类中访问外部类的成员
一个内部类即使被嵌套多层,它也能透明地访问所有它所嵌入的外围类的所有成员。
相关文章推荐
- java对世界各个时区(TimeZone)的通用转换处理方法(转载)
- java-注解annotation
- java-模拟tomcat服务器
- java-用HttpURLConnection发送Http请求.
- java-WEB中的监听器Lisener
- Android IPC进程间通讯机制
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- 介绍一款信息管理系统的开源框架---jeecg
- 聚类算法之kmeans算法java版本
- java实现 PageRank算法
- PropertyChangeListener简单理解
- c++11 + SDL2 + ffmpeg +OpenAL + java = Android播放器
- 插入排序
- 冒泡排序
- 堆排序
- 快速排序
- 二叉查找树