1.什么是内部类?
将一个类定义在另一个内的内部,也就是嵌套在另一个类里面,这就是内部类(可以看下面的代码,Inner类和StaticInner就是Outer的内部类)。其实也可以把内部类看做一个类的普通成员,类似成员变量,成员方法。
2.内部类长什么样子?怎么定义?怎么调用?
内部类跟普通类一样,只不过它是定义在另一个类的内部,可以用public, protected, default, private这几个修饰符修饰(前面说了,可以把内部类当普通成员看待,那么当然也能用这几个修饰符了,可以参考另一篇文章java基础(四)——访问控制符)。看代码
package com.xupk.inner.demo;
public class Outer {
int i = 1;
static int j = 10;
//普通内部类可当做Outer类的普通成员
class Inner{
}
//静态内部类可当作Outer类的静态类成员
static class StaticInner{
}
//普通方法分别访问两个内部类,相当于普通方法访问两个类成员
public void access(){
i = 2;//普通变量
j = 9;//静态变量
Inner i = new Inner();//对于普通内部类,可以直接访问
StaticInner s = new StaticInner();//普通方法肯定可以访问到类成员
}
//静态方法
public static void main(String[] args) {
Outer o = new Outer();
int oi = o.i;//普通成员变量需要通过实例访问
Inner i2 = o.new Inner();//类的静态方法访问普通成员,必须通过类的实例来访问
/***
* 下面这语句会报错:
* 没有任何类型 Outer 的外层实例可访问。必须用类型 Outer 的外层实例
* (例如,x.new A(),其中 x 是 Outer 的实例)来限定分配。
* Inner i = new Inner();//类的静态方法不能直接访问类的普通成员
*/
Outer.j = 8;//类成员可以直接访问,不需要通过实例
StaticInner i3 = new StaticInner();//类的静态方法可以直接访问类的静态成员
}
}
3.静态内部类的加载顺序是怎么样的?
首先我们知道,类加载时有加载、验证、准备、解析、初始化等阶段;那么初始化阶段,就是按代码出现的顺序先执行类的静态成员赋值语句和静态代码块,然后再执行静态方法。静态内部类会在其外部类加载的时候也把它加载进去吗?首先得了解一下,触发类初始化的5个条件(可以参考:初探java虚拟机类加载机制(零)——概述),我们发现下面代码中,并没有触发内部类的初始化,因为它不满足上面5个条件中的任意一个,所以,在外部类加载的时候,内部类并不会自己加载。看代码示例:
package com.xupk.inner.demo;
public class ClzInitTest {
private static int i = 10;
static{
System.out.println("=============outer static code start===================");
System.out.println("outer class load……");
System.out.println("i=:"+i);
System.out.println("=============outer static code end===================");
}
//静态内部类
static class Inner{
private static int i = 1;
static{
System.out.println("===================inner static code start================");
System.out.println("inner class load……");
System.out.println("i=:"+i);
}
static void init(){
System.out.println("inner method load");
}
static{
System.out.println("===================inner static code end==================");
}
}
public static void main(String[] args) {
//什么也不做
}
}
输出如下:
=============outer static code start===================
outer class load……
i=:10
=============outer static code end===================
可见,当外部类加载的时候,并没有加载内部类。再回头看看主动触发类初始化的5个条件,我们调用一个静态内部类的静态方法,应该是能触发内部类的初始化才对。实验一下,把上面的main方法改一下,看代码:
public static void main(String[] args) {
Inner.init();
}
输出如下:
=============outer static code start===================
outer class load……
i=:10
=============outer static code end===================
===================inner static code start================
inner class load……
i=:1
===================inner static code end==================
inner method load
首先会加载外部类的静态代码块,然后main方法调用了静态内部类的静态方法init(),所以会触发Inner类的初始化,这时候初始化顺序是跟普通类初始化顺序一样的:顺序执行静态代码块和静态成员变量赋值语句,然后执行静态方法。
这里有个典型的例子,就是单例模式的设计。JVM内部的机制能够保证:当一个类被加载的时候,这个类的加载过程是线程互斥的。这样当我们第一次调用getInstance的时候,会触发SingleTon的初始化,然后在该方法内访问StaticClassLazy这个内部类的静态变量instance时,会触发这个内部类的初始化,所以JVM能够帮我们保证instance只被创建一次,并且会保证把赋值给instance的内存初始化完毕,这样我们就能保证单例的安全实现。同时该方法也只会在第一次调用的时候使用互斥机制,这样就解决了低性能问题
package com.xupk.inner.demo;
public class SingleTon {
//私有化构造方法
private SingleTon(){
}
//利用类加载的线程是互斥的机制来保证加载这个内部类安全加载
private static class StaticClassLazy{
//类的静态变量只加载一次来保证单例
private static SingleTon instance = new SingleTon();
}
//外部获取实例的方法
public static SingleTon getInstance(){
return StaticClassLazy.instance;
}
}
4.在哪里用到内部类?
LinkedList里面就使用了大量的内部类,比如Entry(jdk1.7后改为Node了)。下面引用一篇文章来说明一下内部类的应用场景(转自:http://blog.csdn.net/hivon/article/details/606312#insertcode)
public interface Pool extends TimerListener
{
//初始化连接池
public boolean init();
//销毁连接池
public void destory();
//取得一个连接
public Connection getConn();
//还有一些其他的功能,这里不再列出
……
}
public class PoolConn
{
private Connection conn;
private boolean isUse;
private long lastAccess;
private int useCount;
……
}
public class ConnectPool implements Pool
{
//存在Connection的数组
private PoolConn[] poolConns;
//连接池的最小连接数
private int min;
//连接池的最大连接数
private int max;
//一个连接的最大使用次数
private int maxUseCount;
//一个连接的最大空闲时间
private long maxTimeout;
//同一时间的Connection最大使用个数
private int maxConns;
//定时器
private Timer timer;
public boolean init()
{
try
{
……
this.poolConns = new PoolConn[this.min];
for(int i=0;i<this.min;i++)
{
PoolConn poolConn = new PoolConn();
poolConn.conn = ConnectionManager.getConnection();
poolConn.isUse = false;
poolConn.lastAccess = new Date().getTime();
poolConn.useCount = 0;
this.poolConns[i] = poolConn;
}
……
return true;
}
catch(Exception e)
{
return false;
}
}
……
private class PoolConn
{
public Connection conn;
public boolean isUse;
public long lastAccess;
public int useCount;
}
}
……
try
{
String[] divisionData = null;
conn = manager.getInstance().getConnection();
stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");
stmt.setLong(1 ,productId.longValue() );
stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;
stmt.execute();
ResultSet rs = stmt.getCursor(2);
int i = 0 ;
String strDivision = "";
while( rs.next() )
{
strDivision += rs.getString("DIVISION_ID") + "," ;
}
int length = strDivision.length() ;
if(length != 0 )
{
strDivision = strDivision.substring(0,length - 1);
}
divisionData = StringUtil.split(strDivision, ",") ;
map.put("Division", strDivision ) ;
LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;
}catch(Exception e)
{
LoggerAgent.error("GetHeaderData", "getDivisionData",
"SQLException: " + e);
e.printStackTrace() ;
}finally
{
manager.close(stmt);
manager.releaseConnection(conn);
}
public interface DataManager
{
public void manageData();
}
public class DataTemplate
{
public void execute(DataManager dm)
{
try
{
dm.manageData();
}
catch(Exception e)
{
LoggerAgent.error("GetHeaderData", "getDivisionData",
"SQLException: " + e);
e.printStackTrace() ;
}finally
{
manager.close(stmt);
manager.releaseConnection(conn);
}
}
}
new DataTemplate().execute(new DataManager()
{
public void manageData()
{
String[] divisionData = null;
conn = manager.getInstance().getConnection();
stmt = (OracleCallableStatement)conn.prepareCall("{ Call PM_GET_PRODUCT.HEADER_DIVISION(?, ?) }");
stmt.setLong(1 ,productId.longValue() );
stmt.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR); ;
stmt.execute();
ResultSet rs = stmt.getCursor(2);
int i = 0 ;
String strDivision = "";
while( rs.next() )
{
strDivision += rs.getString("DIVISION_ID") + "," ;
}
int length = strDivision.length() ;
if(length != 0 )
{
strDivision = strDivision.substring(0,length - 1);
}
divisionData = StringUtil.split(strDivision, ",") ;
map.put("Division", strDivision ) ;
LoggerAgent.debug("GetHeaderProcess","getDivisionData","getValue + " + strDivision +" " + productId) ;
}
});
public interface SortAlgor
{
public void sort(int[] is);
}
public void printSortedArray(int[] is,SortAlgor sa)
{
……
sa.sort(is);
for(int i=0;i<is.length;i++)
{
System.out.print(is[i]+” “);
}
System.out.println();
}
int[] is = new int[]{3,1,4,9,2};
printSortedArray(is,new SortAlgor()
{
public void sort(is)
{
int k = 0;
for(int i=0;i<is.length;i++)
{
for(int j=i+1;j<is.length;j++)
{
if(is[i]>is[j])
{
k = is[i];
is[i] = is[j];
is[j] = k;
}
}
}
}
});
spinner2.addChangeListener(new ChangeListener()
{
public void stateChanged(ChangeEvent e)
{
System.out.println("Source: " + e.getSource());
}
}
);
Arrays.sort(emps,new Comparator(){
Public int compare(Object o1,Object o2)
{
return ((Employee)o1).getServedYears()-((Employee)o2).getServedYears();
}
});
package polyFactory;
public interface Shape {
public void draw();
public void erase();
}
package polyFactory;
import java.util.HashMap;
import java.util.Map;
public abstract class ShapeFactory {
protected abstract Shape create();
private static Map factories = new HashMap();
public static void addFactory(String id,ShapeFactory f)
{
factories.put(id,f);
}
public static final Shape createShape(String id)
{
if(!factories.containsKey(id))
{
try
{
Class.forName("polyFactory."+id);
}
catch(ClassNotFoundException e)
{
throw new RuntimeException("Bad shape creation : "+id);
}
}
return ((ShapeFactory)factories.get(id)).create();
}
}
package polyFactory;
public class Circle implements Shape {
public void draw() {
// TODO Auto-generated method stub
System.out.println("the circle is drawing...");
}
public void erase() {
// TODO Auto-generated method stub
System.out.println("the circle is erasing...");
}
private static class Factory extends ShapeFactory
{
protected Shape create()
{
return new Circle();
}
}
static {ShapeFactory.addFactory("Circle",new Factory());}
}
package polyFactory;
public class Square implements Shape {
public void draw() {
// TODO Auto-generated method stub
System.out.println("the square is drawing...");
}
public void erase() {
// TODO Auto-generated method stub
System.out.println("the square is erasing...");
}
private static class Factory extends ShapeFactory
{
protected Shape create()
{
return new Square();
}
}
static {ShapeFactory.addFactory("Square",new Factory());}
}
String[] ids = new String[]{"Circle","Square","Square","Circle"};
for(int i=0;i<ids.length;i++)
{
Shape shape = ShapeFactory.createShape(ids[i]);
shape.draw();
shape.erase();
}