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();
}