在学习JAVA的时候,发现内部类是它很有特点的一个地方,仔细看了一下,发现内部类比当初第一次遇到它时想像的还要更强大,总结了一下,内部类的功能大概可以分为:
1.隐藏代码,有的时候可能只希望在类中实现某些代码,这部分实现又不希望在外部使用时,内部类是个不错的选择。
2.实现接口,利用内部类的机制可以很方便地在一个类中对同一个接口进行不同的实现,甚至可以隐藏实现的类名(匿名类)
内部类的第二个功能也是目前JAVA中事件机制所基于的实现,也常常用于控制系统的实现中,可见其功能之强大。
自己在学习内部类的过程中,主要分为以下几个主题来进行:
1.内部类和外部类的相互访问:首先,内部类(除非特别说明,内部类指非静态内部类)可以访问外部类的所有成员和函数,包括public, default, protected和private,而外部类内部可以访问内部类的所有成员,但必须通过内部类对象,代码如下:
/**
*
* @author sunyiwei
* @2014年7月1日
*
* Note: Obviously, we can access all objects from inner class of outer class, including private variable or private function
* since it implicitly stores an reference of its enclosed class. BUT WHAT IF WE DO IT REVERSELY?
* that is, can we call private function of inner class from outer class? This test
* say yes. we can treat inner class as a property of outer class, thus it can
* explain why we can call private function from enclose class
*/
public class TestInnerClass {
public int m_nPublicValueOuter=2;
class InnerClass{
private int m_nPrivateValue=1;
public int m_nPublicValue=-1;
private void privateFunc()
{
System.out.println("This is from private func of inner class");
System.out.println(TestInnerClass.this); //get enclosing object from inner class
}
}
public void func()
{
InnerClass innerClass=new InnerClass();
innerClass.privateFunc(); //here we call private function of innerclass
System.out.println(innerClass.m_nPrivateValue);//here we access private variable of inner class
}
public static void main(String[] args)
{
TestInnerClass testInnerClass=new TestInnerClass();
testInnerClass.func();
// TestInnerClass.InnerClass innerClass=new TestInnerClass().new InnerClass();
// innerClass.privateFunc();
//TestStaticInnerClass.InnerClass.func();
}
}
在上面的例子中,内部类可以访问外部类的所有成员比较好理解,因为内部类在创建时已经隐藏地带有一份外部类的引用,而外部类居然也能访问内部类的私有变量!(m_nPrivateValue在内部类中被声明为私有变量,但在func()函数中依然可以被访问)我自己的理解是,内部类其实也可以看成是外部类的成员变量,既然是成员变量,那不管是什么样的访问修饰符,外部类能访问是很正常的事情,在这里m_nPrivateValue和m_nPublicValueOuter的地位是一样的,只不过前者需要通过内部类来访问。
2.静态内部类:普通的内部类对于外部类的所有成员变量和方法都有访问权限,但是对于静态内部类而言,它只能访问外部类中的静态成员变量和静态方法。这其实也很好理解,静态的内部类本身也可以理解为外部类的一个静态成员变量,它是类变量,自然不应该去访问实例变量(普通非静态成员变量),示例代码如下:
/**
* @author sunyiwei
* @2014年7月1日
*
*Note: we test static inner class in this example
* Results show that static inner class can only access static variables of its enclosing class
*/
public class TestStaticInnerClass {
private static int m_nStaticValueOuter=2;
private int m_nNonStaticValueOuter=3;
private static class InnerClass
{
private int m_nNonStaticValue=-1;
private static int m_nStaticValue=1;
static void func()
{
System.out.println("This is a static function of inner class");
System.out.println(m_nStaticValueOuter); //access static variable
//System.out.println(m_nNonStaticValueOuter); //compiler error, we cannot access non-static variable of enclosing class
}
}
public void func()
{
InnerClass.func();
System.out.println(InnerClass.m_nStaticValue);
}
public static void main(String[] args) {
TestStaticInnerClass testStaticInnerClass=new TestStaticInnerClass();
testStaticInnerClass.func();
}
}
3.匿名类:顾名思义,匿名类就是连名字都不愿意让人知道的类(听起来比较高冷),一般来讲,有时候我们可能只是需要某个接口,并不关心接口的具体实现是由哪个类来完成的,这时候就可以考虑使用匿名类,示例代码如下:
/**
* @author sunyiwei
* @2014年7月1日
*
*this simple example shows the usage of anonymous class
*/
public class TestAnonymousClass {
//here we wanna get an abstract animal,that is, any class implementing the animal interface
//can be return here. Within this method, we create an anonymous class to implement animal
//interface and return it directly. we don't even know its exact name! With this support, we can
//easily create many different implements of animal interface.
static public Animal getAnimal()
{
return new Animal() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println("I'm an anonymous animal, i'm also running!");
}
};
}
//this method is designed to show that we can easily to create different implements
// with anonymous class. And also we try to explain that when the anonymous class
//need to access the arguments of enclosing method, these argument must be declared
//as final, otherwise compiler would complaint an error.
static public Animal getAnotherAnimal(final String szString) //here szString must be final
{
return new Animal() {
@Override
public void run() {
// TODO Auto-generated method stub
System.out.println(szString);
}
};
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
TestAnonymousClass.getAnimal().run();
TestAnonymousClass.getAnotherAnimal("I'm another anonymous animal!").run();
}
}
在这个例子中,我们通过匿名类实现了animal接口的两种实现,但从外部看来,并不知道这两种实现是由哪两个类来完成的,在JAVA的事件中,基本上也是基于这样的方法来实现的。
4. 内部类的功能:之前说过,内部类的功能主要是能够方便地隐藏代码,并且能够在类中方便地实现同一个接口的不同实现,成为目前基于事件机制的框架的实现。这里,借用了“Thinking in Java”书中的关于“抽象工厂”和“迭代器”的两个例子,通过内部类的方式使得抽象工厂的实现变得很方便,也让我再次感受到了内部类的威力所在,代码如下:
//示例1
interface AbstractService
{
void firstMethod();
void secondMethod();
}
interface AbstractFactory
{
AbstractService getService();
}
/**
* @author sunyiwei
* @2014年7月1日
*
* this example implement the abstract-factory design pattern with inner class
* we can see the power of inner class here because it completly hide and simplify
* the implement of factory. this example is referenced from "Thinking in java", which
* is one of the best primer book to learn java.^-^
*/
public class FactoryWithInnerClass {
public static void FactoryConsumer(AbstractFactory factory)
{
AbstractService service=factory.getService();
service.firstMethod();
service.secondMethod();
}
public static void main(String[] args)
{
AbstractFactory factory=FirstService.factory;
FactoryConsumer(factory);
}
}
class SecondService implements AbstractService
{
//to avoid explicitly instantiate
private SecondService()
{}
public void firstMethod()
{
System.out.println("SecondService:first method");
}
public void secondMethod()
{
System.out.println("SecondService:second method");
}
public static AbstractFactory factory=new AbstractFactory() {
@Override
public AbstractService getService() {
// TODO Auto-generated method stub
return new SecondService();
}
};
}
class FirstService implements AbstractService
{
//to avoid explicitly instantiate
private FirstService()
{}
public void firstMethod()
{
System.out.println("FirstService:first method");
}
public void secondMethod()
{
System.out.println("FirstService: second method");
}
public static AbstractFactory factory=
new AbstractFactory() {
@Override
public AbstractService getService() {
// TODO Auto-generated method stub
return new FirstService();
}
};
}
在这个例子中,我们首先声明了抽象的AbstractService类和AbstractFactory类,然后实现了两个具体的服务类,并在服务类中通过匿名类的方式产生了相应的工厂,在测试函数中,我们通过这个工厂得到相应的服务,并调用服务中的方法,实现了抽象工厂设计模式,应该来讲,代码从实现上来讲还是很简洁的。
interface Selector
{
Boolean end();
Object current();
void next();
}
/**
* @author sunyiwei
* @2014年7月1日
*
* Inner class can be used to implement the iterator-pattern in design pattern
* In this example, we create a enclosing class and its iterators with usage of inner class
* this example also shows us that we can create not only one iterator
*/
public class IteratorWithInnerClass {
private int[] m_nIntValues;
private int nNext=0;
public IteratorWithInnerClass(int nSize)
{
m_nIntValues=new int[nSize];
}
public void add(int n)
{
if(nNext<m_nIntValues.length)
m_nIntValues[nNext++]=n;
}
//here we implement iterator using inner class for this enclosing class
private class SequenceIterator implements Selector
{
private int nIndex=0;
public Boolean end()
{
if(nIndex==m_nIntValues.length)
return true;
else
return false;
}
public Object current()
{
if(nIndex<m_nIntValues.length)
return m_nIntValues[nIndex];
return null;
}
public void next()
{
if(nIndex<m_nIntValues.length)
nIndex++;
}
}
//we implement another iterator class
private class RandomIterator implements Selector
{
private int nIndex=0;
public Boolean end()
{
if(nIndex==m_nIntValues.length)
return true;
else
return false;
}
public Object current()
{
Random random=new Random();
int nLenght=m_nIntValues.length;
return m_nIntValues[random.nextInt(nLenght)];
}
public void next()
{
if(nIndex<m_nIntValues.length)
nIndex++;
}
}
//get selector, here we can hide our inner class and only expose this interface to our user
public Selector getSequenceSelector()
{
return new SequenceIterator();
}
public Selector getRandomSelector()
{return new RandomIterator();}
public static void main(String[] args)
{
int nSize=100;
IteratorWithInnerClass testClass=new IteratorWithInnerClass(nSize);
for(int i=0;i<nSize;i++)
testClass.add(i);
//go through it with two different iterator
//Selector selector=testClass.getSequenceSelector(); //sequence one
Selector selector=testClass.getRandomSelector(); //random one
while(!selector.end())
{
System.out.println(selector.current());
selector.next();
}
}
}
这个例子通过内部类实现了两种不同的迭代器,也是实现和理解迭代器模式的一个相当好的例子。