一、创建内部类
package com.chenxyt.java.test;
public class Parcell {
class Contents{
private int i = 11;
public int value(){
return i;
}
}
class Destination{
private String label;
public Destination(String whereto) {
// TODO Auto-generated constructor stub
label = whereto;
}
String readLabel(){
return label;
}
}
public Contents contents(){
return new Contents();
}
public Destination destination(String s){
return new Destination(s);
}
public void ship(String dest){
Contents c = new Contents();
Destination d = new Destination(dest);
System.out.println(d.readLabel());
}
public static void main(String[] args) {
Parcell p1 = new Parcell();
p1.ship("Inner Class");
Parcell p2 = new Parcell();
Contents c = p2.contents();
Parcell.Destination d = p2.destination("Class Inner");
}
}
如上我们创建了一个内部类,内部类与其它类的区别在于将类隐藏在了另一个类的内部,同时如contents方法所示,外部类的方法还可以返回一个指向内部类的引用,这也是很常见的一种用法。此外我们看到main()方法中创建的内部类对象是使用外部类的引用关联创建的,这一点在下一节中会说到。
二、链接到外部类
package com.chenxyt.java.practice;
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;
@Override
public boolean end() {
// TODO Auto-generated method stub
return i == items.length;
}
@Override
public Object current() {
// TODO Auto-generated method stub
return items[i];
}
@Override
public void next() {
// TODO Auto-generated method stub
if(i<items.length){
i++;
}
}
}
public Selector selector(){
return new SequenceSelector();
}
public static void main(String[] args) {
//初始化一个长度为10的数组
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.print(selector.current() + " ");
//数组下标+1
selector.next();
}
}
}
上边的代码很好的展示了这一点,外部类Sequence创建了个数组,内部类SequenceSelector实现了Selector接口获取数组内容并操作数组,可以看到这个类的实现方法访问了外部类的private域。
三、使用.this与.new
package com.chenxyt.java.practice;
public class DoThis {
void f(){
System.out.println("This is outClass's method");
}
public class Inner{
public DoThis outer(){
return DoThis.this;
//return this;
}
}
public Inner inner(){
return new Inner();
}
public static void main(String[] args) {
DoThis dt = new DoThis();
Inner in = dt.inner();
in.outer().f();
}
}
如前文说到,我们不能使用new直接创建内部类对象,我们需要使用外部类对象的引用创建,这里可以使用外部类对象的引用.new语法进行创建。
package com.chenxyt.java.practice;
public class DoThis {
public class Inner{
public DoThis outer(){
return DoThis.this;
//return this;
}
}
public static void main(String[] args) {
DoThis dt = new DoThis();
Inner in = dt.new Inner();
}
}
只有内部类是静态内部类或者在非static方法中,我们才可以通过new的形式直接进行创建。
四、内部类与向上转型
package com.chenxyt.java.practice;
public interface Destination{
String readLabel();
}
package com.chenxyt.java.practice;
public interface Contents {
int value();
}
然后创建一个类,并在这个类的内部创建两个内部类去实现上边的接口:
package com.chenxyt.java.practice;
class Parcell4{
private class PContents implements Contents{
private int i = 11;
@Override
public int value() {
// TODO Auto-generated method stub
return i;
}
}
protected class PDestination implements Destination{
private String label;
private PDestination(String whereto) {
// TODO Auto-generated constructor stub
label = whereto;
}
@Override
public String readLabel() {
// TODO Auto-generated method stub
return label;
}
}
public Destination destination(String s){
return new PDestination(s);
}
public Contents contents(){
return new PContents();
}
}
public class TestParcell {
public static void main(String[] args) {
Parcell4 p = new Parcell4();
Contents c = p.contents();
Destination d = p.destination("Inner Class");
System.out.println(d.readLabel());
System.out.println(c.value());
//因为PContents是private 所以不能被访问
//Parcell4.PContents pc = p.new PContents();
}
}
Parcell4中增加了一些新的东西,首先内部类PContents是private,除了Parcell4没有人能访问它,所以main函数最后一行编译不能通过。其次PDestination是protected的,所以除了该类本身和其子类还有同一个包中的类,其它类不能访问。因此客户端如果想访问这些实现,就受到了限制。不过我们可以看到,main函数的第二、第三行都实现了转型,也就是虽然不可见,但是不影响使用接口的实现。因此private的内部类提供了一种设计思路,通过这种方式完全阻止了依赖任何类型的编码,并且完全隐藏了实现的细节,并且由于不能访问任何新增加的、原本不属于公共接口的方法,因此接口的扩展就是没有价值的了。
五、在方法和作用域内的内部类
package com.chenxyt.java.practice;
public class Parcel5 {
public Destination destination(String s){
class PDestination implements Destination{
private String label;
private PDestination(String whereTo){
label=whereTo;
}
@Override
public String readLabel() {
// TODO Auto-generated method stub
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args) {
Parcel5 p5 = new Parcel5();
Destination d = p5.destination("Area Inner Class");
System.out.println(d.readLabel());
}
}
package com.chenxyt.java.practice;
public class Parcel6 {
private void internalTracking(boolean b){
if(b){
class TrackingSkip{
private String id;
TrackingSkip(String s){
id = s;
}
String getSkip(){
return id;
}
}
TrackingSkip ts = new TrackingSkip("SLIP");
String s = ts.getSkip();
System.out.println(s);
}
//因为内部类在if(b)的作用域内 此处已经超过了作用范围 所以不可以使用
//TrackingSkip ts1 = new TrackingSkip("SLIP1");
}
public void track(){
internalTracking(true);
}
public static void main(String[] args) {
Parcel6 p = new Parcel6();
p.track();
}
}
上边的例子主要是想在方法中判断如果入参为true则实现一个类的功能,而这个类又不想被外部可见,所以在if中创建了内部类。
六、匿名内部类
package com.chenxyt.java.practice;
public class Parcel7 {
public Contents contents(){
return new Contents(){
private int i = 11;
@Override
public int value() {
// TODO Auto-generated method stub
return i;
}
};
}
public static void main(String[] args) {
Parcel7 p7 = new Parcel7();
Contents c = p7.contents();
}
}
在此处,contents方法内部要返回一个Contents对象的时候,我们突然加了一个类的定义,这个类没有名字,它实现了Contents接口,也就是我们实际上创建了一个继承自Contents类的匿名类对象,于是这个return对象的引用就变成了一个来自向上转型的Contents引用。上述这个匿名内部类是下面这种形式的一种简化。
package com.chenxyt.java.practice;
public class Parcel7 {
public class MyContents implements Contents{
private int i = 11;
@Override
public int value() {
// TODO Auto-generated method stub
return i;
}
}
public Contents contents(){
return new MyContents();
}
public static void main(String[] args) {
Parcel7 p7 = new Parcel7();
Contents c = p7.contents();
}
}
package com.chenxyt.java.practice;
public class Wrapping {
private int i;
public Wrapping(int x){
i=x;
}
public int value(){
return i;
}
}
匿名内部类:
package com.chenxyt.java.practice;
public class Parcel8 {
public Wrapping wrapping(int x){
return new Wrapping(x){
public int value(){
return super.value() * 11;
}
};
}
}
只需要传递合适的参数到基类的构造器中即可,虽然Wrapping只是一个普通的实现类,但是他还是被其导出类当做了公共接口来使用。
package com.chenxyt.java.practice;
public class Parcel8 {
public Wrapping wrapping(final int x){
return new Wrapping(x){
public int value(){
return super.value() * x;
}
};
}
}
有关匿名内部类的内容,推荐一篇文章,讲述的比较详细清晰。java提高篇(九)-----详解匿名内部类
七、嵌套类
package com.chenxyt.java.practice;
public class Parcel11 {
private static class ParcelContents implements Contents{
private int i = 11;
@Override
public int value() {
// TODO Auto-generated method stub
return i;
}
}
protected static class ParcelDestination implements Destination{
private String label;
private ParcelDestination(String whereTo){
label = whereTo;
}
@Override
public String readLabel() {
// TODO Auto-generated method stub
return label;
}
public static void f(){
//
}
static int x = 8;
static class AnotherLevel{
public static void funx(){
//
}
static int y = 11;
}
}
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 = new ParcelContents();
Destination d = new ParcelDestination("dss");
Destination d1 = destination("d1");
}
}
package com.chenxyt.java.practice;
public interface ClassInnerInterface {
void howd();
class Test implements ClassInnerInterface{
@Override
public void howd() {
// TODO Auto-generated method stub
System.out.println("其它不同实现的公共方法");
}
public static void main(String[] args) {
new Test().howd();
}
}
}
package com.chenxyt.java.practice;
class ManyInner {
private void f(){
//---
}
class A{
private void g(){
//---
}
public class B{
void h(){
f();
g();
}
}
}
}
public class MNA{
public static void main(String[] args) {
ManyInner mi = new ManyInner();
ManyInner.A a = mi.new A();
ManyInner.A.B b = a.new B();
b.h();
}
}
如上可见,在嵌套了多层的内部类B中调用方法f()和方法g()并不需要任何其它附加条件,即便他们被定义为private
八、为什么需要内部类
package com.chenxyt.java.practice;
//要继承的类1
class F{
//---
}
//要继承的类2
abstract class G{
//---
}
//外部类继承A 内部匿名类继承B
class H extends F{
G makeG(){
return new G(){
//--
};
}
}
public class MutiExtends {
static void takeF(F f){
//--
}
static void takeG(G g){
//--
}
public static void main(String[] args) {
H h = new H();
takeF(h);
takeG(h.makeG());
}
}
如果不是要解决类似上边的“多重继承”问题,那么可以不实用内部类,但是使用内部类还可以获得一些其它的特性。
九、内部类的继承
package com.chenxyt.java.practice;
class withInner{
class Inner{
}
}
public class InheritInner extends withInner.Inner{
InheritInner(withInner wi){
wi.super();
}
public static void main(String[] args) {
withInner wi = new withInner();
InheritInner ii = new InheritInner(wi);
}
}
如上,在子类的构造函数中要传入继承内部类的外部类的引用。
十、内部类可以被覆盖吗
package com.chenxyt.java.practice;
class Egg{
private Yolk y;
protected class Yolk{
public Yolk(){
System.out.println("Egg.Yolk");
}
}
public Egg(){
System.out.println("New Egg");
y = new Yolk();
}
}
public class BigEgg extends Egg{
public class Yolk{
public Yolk(){
System.out.println("BigEgg.Yolk");
}
}
public static void main(String[] args) {
new BigEgg();
}
}
十一、局部内部类
package com.chenxyt.java.practice;
interface Counter{
int next();
}
public class LocalInnerClass {
private int count = 0;
//局部内部类
Counter getCounter(final String name){
class LocalCounter implements Counter{
public LocalCounter(){
System.out.println("LocalCounter Constructor");
}
@Override
public int next() {
// TODO Auto-generated method stub
System.out.println(name);
return count++;
}
}
return new LocalCounter();
}
//匿名类
Counter getCounter2(final String name){
return new Counter(){
{
System.out.println("Counter Constructor");
}
@Override
public int next() {
// TODO Auto-generated method stub
System.out.println(name);
return count++;
}
};
}
public static void main(String[] args) {
LocalInnerClass lc = new LocalInnerClass();
Counter c1 = lc.getCounter("Local Counter");
Counter c2 = lc.getCounter2("Annoy Counter");
for(int i=0;i<5;i++){
System.out.println(c1.next());
}
for(int i=0;i<5;i++){
System.out.println(c2.next());
}
}
}
我们分别使用局部内部类和匿名类实现了相同的计数功能。