欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
java內部類(lèi)
java內部類(lèi)
內部類(lèi)學(xué)習
所謂內部類(lèi)(Inner Class),顧名思義,就是指定義在另外一個(gè)類(lèi)中的類(lèi),我們?yōu)槭裁匆@么做呢?為什么不直接定義它而要在別的類(lèi)中定義一個(gè)內部類(lèi)呢?這樣做主要有如下三個(gè)原因:
1.  內部類(lèi)的方法可以訪(fǎng)問(wèn)它所在的外部類(lèi)中的所有域,包括私有型別的;
2.  對于同一個(gè)包中的其它類(lèi)它是隱藏的;
3.  匿名的內部類(lèi)可以讓我們很方便的定義事件響應(call back),這在GUI編程中很常見(jiàn);
一.內部類(lèi)(inner class)如何訪(fǎng)問(wèn)外部類(lèi)(outer class)中的域
因為安全機制的原因,內部類(lèi)通常聲明為private類(lèi)別,因此,只有在內部類(lèi)所在的外部中才能夠創(chuàng )建內部類(lèi)的對象,對其它類(lèi)而言它是隱藏的。另外,只有內部類(lèi)才會(huì )用到private修飾符,一般的類(lèi)如果用private修飾符則會(huì )報錯。
下面看如下的代碼:
Java代碼 
package cn.edu.hust.cm.test;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class InnerClassTest {
public InnerClassTest() {
super();
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
Court court=new Court(10000,true);
court.start();
JOptionPane.showMessageDialog(null,"停止么,CMTobby?");
System.exit(0);
}
}
class Court{
public Court(int interval,boolean beep){
this.interval=interval;
this.beep=beep;
}
public void start(){
TimerPrinter action=new TimerPrinter();
Timer t=new Timer(interval,action);
t.start();
}
private int interval;
private boolean beep;
private class TimerPrinter implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.println("Cindyelf,would you be my mm?");
if(beep) Toolkit.getDefaultToolkit().beep();
}
}
}
注意上面紅色加粗部分的代碼,如你所見(jiàn)beep這個(gè)變量在內部類(lèi)TimerPrinter中我們并沒(méi)有聲明,那么它引用自何處呢?顯然是來(lái)自于外部類(lèi)。一般來(lái)說(shuō),一個(gè)方法可直接refer to調用它的對象中的所有域,而一個(gè)內部類(lèi)的方法則可以直接refer to它所在類(lèi)以及創(chuàng )建它的外部類(lèi)中的所有域,如上例所示。
事實(shí)上,在每一個(gè)內部類(lèi)中都存在一個(gè)默認的隱式的reference,它指向創(chuàng )建了這個(gè)內部類(lèi)的實(shí)例的那個(gè)對象,我們假設它叫outer,這樣上面紅色加粗部分就相當于:
if(outer.beep) Toolkit.getDefaultToolkit().beep();。Ok,既然存在這樣一個(gè)reference,那么outer的值又是如何設置的?實(shí)際上編譯器會(huì )合成一個(gè)構造方法來(lái)設置它,如下面代碼所示:
public TimePrinter(Court court) {
outer = clock;
}
這段代碼是編譯時(shí)自動(dòng)產(chǎn)生的,就像前面我們討論的自動(dòng)拆箱裝箱中一樣,編譯器自
己會(huì )添加一些代碼。然后當我們在Court類(lèi)的start()方法中創(chuàng )建TimerPrinter實(shí)例的時(shí)
候,編譯器會(huì )自動(dòng)把this作為參數傳遞過(guò)去,效果如下面代碼所示:
Java代碼 
public void start(){
TimerPrinter action=new TimerPrinter(this);//編譯器自動(dòng)加上的
Timer t=new Timer (interval,action);
t.start ();
}
參數是編譯器自動(dòng)給加上的,不用我們來(lái)管。
二.內部類(lèi)的一些特殊語(yǔ)法規則
前面我們說(shuō)在每一個(gè)內部類(lèi)中都存在一個(gè)默認的隱式的reference,它指向創(chuàng )建了這個(gè)內
部類(lèi)的實(shí)例的那個(gè)對象,并且我們以outer來(lái)帶指它,如果我們想顯式的指明該按照如下的
語(yǔ)法,OuterClass.this,例如if(Court.this.beep) Toolkit.getDefaultToolkit().beep();。
此外,因為我們定義的內部類(lèi)通常是private,所以它通常是通過(guò)外部類(lèi)的方法創(chuàng )建,如
本例中的start()方法,這樣那個(gè)隱式的reference就指向調用了start()方法的對象,就是this。
如果內部類(lèi)聲明為public,那么我們就可以在任何地方實(shí)例化一個(gè)內部類(lèi),如下面代碼:
Court court=new Court(10000,true);
Court.TimerPrinter test=court.new TimerPrinter();
上述代碼在InnerClassTest的main方法中,這時(shí)候那個(gè)隱式的reference就直接指向了
court對象。注意語(yǔ)法是:OuterClassName.InnerClassName
許多人認為內部類(lèi)的語(yǔ)法十分復雜,尤其是匿名內部類(lèi),這與Java所一直奉行的“簡(jiǎn)單”原則相背離的,有人甚至懷疑java中加入這么一個(gè)“特征”(feature),是不是已經(jīng)開(kāi)始走向“滅亡”?就像許多其它語(yǔ)言一樣走向“滅亡”??jì)炔款?lèi)是否真的有用,有沒(méi)有存在的必要?我們首先來(lái)看看內部的工作原理。
先指明一點(diǎn),內部類(lèi)如何工作是由編譯器來(lái)負責的,與java虛擬機無(wú)關(guān),它對這個(gè)是一無(wú)所知的。仔細留意一下上篇中編譯后產(chǎn)生的class文件,你會(huì )發(fā)現有一個(gè)class文件的名字是Court$TimerPrinter,它的基本格式是:外部類(lèi)名稱(chēng)$內部類(lèi)名稱(chēng)。當碰到內部類(lèi)時(shí),編譯器會(huì )自動(dòng)根據內部類(lèi)的代碼生成一個(gè)class文件并按照上述規則命名,那么編譯器到底對它做了什么呢?我們可以使用Java的反射(reflection)機制來(lái)“偷窺”它,嘿嘿。具體的代碼如下所示:
Java代碼 
* Created on 2006-09-24
*
* TODO To change the template for this generated file go to
* Window - Preferences - Java - Code Style - Code Templates
*/
package cn.edu.hust.cm.access;
import java.lang.reflect.*;
import javax.swing.*;
/**
* @author Demon
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
public class ReflectionTest {
public static void main(String[] args) {
String name="";
if(args.length>0)
name=args[0];
else
name=JOptionPane.showInputDialog("Class name (e.g. java.util.Date): ");
try{
Class c1=Class.forName(name);
Class c2=c1.getSuperclass();
System.out.print("class " + name);
if(c2!=null&&c2!=Object.class)
System.out.print(" extends " + c2.getName());
System.out.print("\n{\n");
printConstructors(c1);
System.out.println();
printMethods(c1);
System.out.println();
printFields(c1);
System.out.println("}");
}
catch(ClassNotFoundException e) { e.printStackTrace(); }
System.exit(0);
}
public static void printConstructors(Class c1){
Constructor[] constructors=c1.getDeclaredConstructors();
for(int i=0;i<constructors.length;i++){
Constructor c=constructors[i];
String name =c.getName();
System.out.print(Modifier.toString(c.getModifiers()));
System.out.print("   " + name + "(");
Class[] paramTypes = c.getParameterTypes();
for(int j=0;j<paramTypes.length;j++){
if (j > 0) System.out.print(", ");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
public static void printMethods(Class c1){
Method[] methods=c1.getDeclaredMethods();
for(int i=0;i<methods.length;i++){
Method m=methods[i];
String name=m.getName();
Class type=m.getReturnType();
System.out.print(Modifier.toString(m.getModifiers())+"  "+type.getName()+"  "+name+"(");
Class[] paramTypes=m.getParameterTypes();
for(int j=0;j<paramTypes.length;j++){
if(j>0) System.out.print(",");
System.out.print(paramTypes[j].getName());
}
System.out.println(");");
}
}
public static void printFields(Class c1){
Field fields[]=c1.getDeclaredFields();
for(int i=0;i<fields.length;i++){
System.out.print(Modifier.toString(fields[i].getModifiers()));
System.out.print("  ");
Class type=fields[i].getType();
System.out.print(type.getName());
System.out.println("  "+fields[i].getName()+";");
}
}
}
運行該程序,在對話(huà)框中輸入cn.edu.hust.cm.test.Court$TimerPrinter,將會(huì )得到如下輸出:
}
cn.edu.hust.cm.test.Court$TimerPrinter(cn.edu.hust.cm.test.Court);
public  void  actionPerformed(java.awt.event.ActionEvent);
final  cn.edu.hust.cm.test.Court  this$0;
}
如上所示,編譯器自動(dòng)為我們加上了一個(gè)域this$0,它指向一個(gè)外部類(lèi),另外自動(dòng)給構造方法增加了一個(gè)Court型別參數,用來(lái)設置this$0的值,注意this$0是編譯器自己合成的,不能直接引用。
既然編譯器能夠自動(dòng)進(jìn)行轉化,為什么我們不直接自己進(jìn)行轉換,把TimerPrinter改寫(xiě)成普通的class呢?如下所示:
Java代碼 
class Court
{
. . .
public void start()
{
ActionListener listener = new TimePrinter(this);
Timer t = new Timer(interval, listener);
t.start();
}
}
class TimePrinter implements ActionListener
{
public TimePrinter(TalkingClock clock)
{
outer = clock;
}
. . .
private TalkingClock outer;
}
問(wèn)題來(lái)了,我們在實(shí)現actionPerformed方法的時(shí)候要用到訪(fǎng)問(wèn)outer.beep,但是beep是private類(lèi)型的,在TimerPrinter中是不能直接訪(fǎng)問(wèn)的。這樣內部類(lèi)的一個(gè)優(yōu)點(diǎn)就顯示出來(lái)了:內部類(lèi)能夠訪(fǎng)問(wèn)其所屬外部類(lèi)中的私有域而其它普通的類(lèi)則不行。
那么內部類(lèi)是通過(guò)什么樣的機制訪(fǎng)問(wèn)它所屬的外部類(lèi)中的私有數據的呢?聯(lián)想前面講私有域的時(shí)候,我們都是通過(guò)方法來(lái)間接訪(fǎng)問(wèn)私有域的,那么這里是不是這樣的呢?我們還是對外部類(lèi)Court進(jìn)行一下反射,結果如下所示:
Java代碼 
class cn.edu.hust.cm.test.Court
{
public   cn.edu.hust.cm.test.Court(int, boolean);
static  boolean  access$0(cn.edu.hust.cm.test.Court);
public  void  start();
private  int  interval;
private  boolean  beep;
}
我們看到新增了一個(gè)方法access$0,它的返回值就是傳遞過(guò)來(lái)的Court對象的beep域,這樣actionPerformed方法中的if(beep)就相當于if(access$0(outer)),內部類(lèi)就是通過(guò)這種機制來(lái)訪(fǎng)問(wèn)外部類(lèi)的私有數據。
這里我們介紹一種特殊的內部類(lèi):局部?jì)炔款?lèi)(Local Inner Classes)。
在前面的例子中,我們可以發(fā)現TimerPrinter僅在start方法中創(chuàng )建一個(gè)新的對象時(shí)出現過(guò)一次,其它地方都沒(méi)再用到過(guò),這個(gè)情況下我們可以把TimerPrinter就定義在start方法中,如下面代碼所示:
Java代碼 
public void start(){
class TimerPrinter implements ActionListener{
//private boolean beep;
public void actionPerformed(ActionEvent e){
System.out.println("Bigface,would you be my boy?");
if(beep) Toolkit.getDefaultToolkit().beep();
}
}
TimerPrinter action=new TimerPrinter();
Timer t=new Timer(interval,action);
t.start();
}
注意,局部?jì)炔款?lèi)不需要任何access modifier,否則編譯出錯,它的作用域一般都被限制在它所在的block中。此時(shí),編譯會(huì )產(chǎn)生一個(gè)名字叫Court$1TimerPrinter的class文件。局部?jì)炔款?lèi)有如下兩個(gè)優(yōu)點(diǎn):
1.  它對外面的所有類(lèi)來(lái)說(shuō)都是隱藏的,即時(shí)是它所屬的外部類(lèi),僅有它所在的方法知道它;
2.  它不僅可以訪(fǎng)問(wèn)它所屬外部類(lèi)中的數據,還可以訪(fǎng)問(wèn)局部變量,不過(guò)局部變量必須生命為final類(lèi)型,看下面的例子:
Java代碼 
package cn.edu.hust.cm.test;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class InnerClassTest {
public InnerClassTest() {
super();
}
public static void main(String[] args) {
Court court=new Court();
court.start(5000,true);
JOptionPane.showMessageDialog(null,"停止么,CMTobby?");
}
}
class Court{
public void start(int interval,final boolean beep){
class TimerPrinter implements ActionListener{
public void actionPerformed(ActionEvent e){
System.out.println("Cindyelf,are you crazy?");
if(beep) Toolkit.getDefaultToolkit().beep();
}
}
TimerPrinter action=new TimerPrinter();//編譯器會(huì )自動(dòng)更改
Timer t=new Timer(interval,action);
t.start();
}
}
注意,局部?jì)炔款?lèi)所要訪(fǎng)問(wèn)的局部變量必須聲明為final類(lèi)型,如上例中紅色粗體部分。那么局部?jì)炔款?lèi)是如何訪(fǎng)問(wèn)這個(gè)局部變量的呢?我們再對Court$1TimerPrinter反射一下,會(huì )得到如下的輸出:
Java代碼 
class cn.edu.hust.cm.test.Court$1TimerPrinter
{
cn.edu.hust.cm.test.Court$1TimerPrinter(cn.edu.hust.cm.test.Court, boolean);
public  void  actionPerformed(java.awt.event.ActionEvent);
final  cn.edu.hust.cm.test.Court  this$0;
private final  boolean  val$beep;
}
編譯器又給我們增加了一個(gè)域val$beep,同時(shí)構造方法增加了一個(gè)boolean類(lèi)型的參數,因此我們猜想如下的實(shí)現過(guò)程:
TimerPrinter action=new TimerPrinter(this,beep);//編譯器自動(dòng)增加
然后構造方法中會(huì )有:val$beep=beep;這樣就成功的把局部變量的值復制過(guò)來(lái)了。局部變量必須為final就是為了保證成功的復制值,因為final類(lèi)型的變量一經(jīng)賦值就不能再發(fā)生變化了。
這里再介紹一種特殊的內部類(lèi)――匿名內部類(lèi)(Anonymous Inner Class),顧名思義,就是沒(méi)有名字的內部類(lèi),這是Java為了方便我們編寫(xiě)程序而設計的一個(gè)機制。因為有時(shí)候有的內部類(lèi)只需要創(chuàng )建一個(gè)它的對象就可以了,以后再不會(huì )用到這個(gè)類(lèi),這時(shí)候使用匿名內部類(lèi)就比較合適,而且也免去了給它取名字的煩惱,:)。
匿名類(lèi)的語(yǔ)法是什么樣的呢?如下所示:
new SuperType(){
內部類(lèi)的方法和域;
}
注意,這里的SuperType指超類(lèi),它可以是一個(gè)接口(interface)或者是一個(gè)類(lèi)(Class),當它是一個(gè)接口的時(shí)候就不能有構造參數(Construction parameters)了。匿名類(lèi)的語(yǔ)法相對于Java的其他部分來(lái)說(shuō)稍微復雜一點(diǎn),我們可以按如下方式理解:
1.SuperType為接口
例子:Interface1() test=new Interface1(){
要實(shí)現的的方法;
Interface1的域;
內部類(lèi)的域以及方法;
}
我們可以如下理解:
先聲明了如下一個(gè)類(lèi),
class Anonymous1 implements Interface1{
要實(shí)現的的方法;
Interface1的域;
內部類(lèi)的域以及方法;
}
然后,Interface1() test=new Anonymouse1();
這樣就比較容易理解了。
2.SuperType為類(lèi)
例子:Class2 test=new Class2(Construction parameters){
內部類(lèi)的域以及方法;
}
我們可以如下理解:
先聲明了如下一個(gè)類(lèi),
class Anonymous2 extends Class2{
public Anonymous2(Construction parameters){
super(Construction parameters);
}
內部類(lèi)的域以及方法;
}
然后,Class2 test=new Anonymouse2(Construction parameters);
本節測試代碼如下:
Java代碼 
package cn.edu.hust.cm.test;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.Toolkit;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class InnerClassTest {
public InnerClassTest() {
super();
}
public static void main(String[] args) {
Court court=new Court(10000,true);
court.start();
JOptionPane.showMessageDialog(null,"停止么,CMTobby?");
System.exit(0);
}
}
class Court{
public Court(int interval,boolean beep){
this.interval=interval;
this.beep=beep;
}
public void start(){
ActionListener action=new ActionListener(){
public void actionPerformed(ActionEvent e){
System.out.println("Cindyelf,wouly you be my girl?");
}
};
Timer t=new Timer(interval,action);
t.start();
}
private int interval;
private boolean beep;
}
這里介紹最后一種比較特殊的內部類(lèi)――靜態(tài)內部類(lèi)(Static Inner Class),即在內部類(lèi)的前面增加了static修飾符(modifier)。注意,僅僅只有內部類(lèi)能夠被聲明為static類(lèi)型,通常我們聲明一個(gè)普通類(lèi)的時(shí)候不能使用static,否則編譯出錯。
那么為什么我們要使用靜態(tài)的內部類(lèi)呢?在什么情況下我們需要使用靜態(tài)的內部類(lèi)呢?我們前面講過(guò),編譯器會(huì )自動(dòng)給內部類(lèi)加上一個(gè)reference,指向產(chǎn)生它的那個(gè)外部類(lèi)的對象,如果不想要或者說(shuō)不需要這個(gè)reference,那么我們就可以把這個(gè)內部類(lèi)聲明為static,禁止這個(gè)reference的產(chǎn)生。除此之外靜態(tài)類(lèi)的使用與普通的靜態(tài)類(lèi)是一樣的。例子如下:
Java代碼 
package cn.edu.hust.cm.test;
public class StaticInnerClassTest {
public StaticInnerClassTest() {
super();
// TODO Auto-generated constructor stub
}
public static void main(String[] args) {
// TODO Auto-generated method stub
double d[]=new double[20];
for(int i=0;i<d.length;i++)
d[i]=100*Math.random();
//FindMinMax test=new FindMinMax();
FindMinMax.Pair pair=FindMinMax.getMinMax(d);
System.out.println("最小值是:"+pair.getFirst());
System.out.println("最大值是:"+pair.getSecond());
}
}
class FindMinMax{
static double min=Double.MAX_VALUE;
static double max=Double.MIN_VALUE;
public static Pair getMinMax(double d[]){
for(double value:d){
if(min>value) min=value;
if(max<value) max=value;
}
return new Pair(min,max);
}
public static class Pair{
public Pair(double first,double second){
this.first=first;
this.second=second;
}
public double getFirst(){
return this.first;
}
public double getSecond(){
return this.second;
}
private double first;
private double second;
}
}
在這個(gè)例子中之所以要用靜態(tài)內部類(lèi),主要是因為getMinMax這個(gè)方法是靜態(tài)的,由類(lèi)直接調用。而前面說(shuō)過(guò)創(chuàng )建內部類(lèi)的時(shí)候語(yǔ)法是這樣的:
OuterClassObject.new InnerClassName(),如果省略了OuterClassObject則是
this. new InnerClassName(),OuterClassObject或者this指代創(chuàng )建這個(gè)內部類(lèi)對象的一個(gè)外部類(lèi)對象,是一個(gè)隱式參數,它將傳入內部類(lèi)的構造方法(見(jiàn)前所述)。但是現在這個(gè)內部類(lèi)對象是由“類(lèi)”直接創(chuàng )建的,不會(huì )產(chǎn)生這樣的一個(gè)隱式參數傳入內部類(lèi)構造方法,因此內部類(lèi)也就不需要“編譯器自動(dòng)給內部類(lèi)加上一個(gè)reference,指向產(chǎn)生它的那個(gè)外部類(lèi)的對象”,所以我們把這個(gè)內部類(lèi)聲明為static。上面的代碼中如果我們去掉static將會(huì )報錯,除非我們把getMinMax的static去掉,同時(shí)通過(guò)FindMinMax的一個(gè)實(shí)例來(lái)調用這個(gè)方法,如下:
FindMinMax test=new FindMinMax();
test.getMinMax(d);
我們下面來(lái)對內部類(lèi)所產(chǎn)生的class文件反射(reflection)一下,結果如下:
Java代碼 
class cn.edu.hust.cm.test.FindMinMax$Pair
{
public   cn.edu.hust.cm.test.FindMinMax$Pair(double, double);
public  double  getSecond();
public  double  getFirst();
private  double  first;
private  double  second;
}
很清楚的看到,編譯器沒(méi)有給我們自動(dòng)加上一個(gè)reference,指向產(chǎn)生它的那個(gè)外部類(lèi)的對象,也沒(méi)有給構造方法加上一個(gè)FindMinMax型別的參數。
本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
最全的Java筆試題庫之選擇題篇-總共234道【1~60】
靜態(tài)方法中獲取當前類(lèi)/類(lèi)名
java中類(lèi)里面還能在定義類(lèi)嗎
java中2個(gè)不同類(lèi)的變量調用
靜態(tài)代碼塊、非靜態(tài)代碼塊、構造函數的執行順序
父類(lèi)的私有方法不能被子類(lèi)覆蓋
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久