第一篇:內(nèi)部類的問(wèn)題相關(guān)(最終版)
內(nèi)部類的問(wèn)題相關(guān)
Java內(nèi)部類的使用小結(jié)
內(nèi)部類是指在一個(gè)外部類的內(nèi)部再定義一個(gè)類。類名不需要和文件夾相同。
*內(nèi)部類可以是靜態(tài)static的,也可用public,default,protected和private修飾。(而外部頂級(jí)類即類名和文件名相同的只能使用public和default)。
注意:內(nèi)部類是一個(gè)編譯時(shí)的概念,一旦編譯成功,就會(huì)成為完全不同的兩類。對(duì)于一個(gè)名為outer的外部類和其內(nèi)部定義的名為inner的內(nèi)部類。編譯完成后出現(xiàn)outer.class和outer$inner.class兩類。所以內(nèi)部類的成員變量/方法名可以和外部類的相同。
1.成員內(nèi)部類
成員內(nèi)部類,就是作為外部類的成員,可以直接使用外部類的所有成員和方法,即使是private的。同時(shí)外部類要訪問(wèn)內(nèi)部類的所有成員變量/方法,則需要通過(guò)內(nèi)部類的對(duì)象來(lái)獲取。
要注意的是,成員內(nèi)部類不能含有static的變量和方法。因?yàn)槌蓡T內(nèi)部類需要先創(chuàng)建了外部類,才能創(chuàng)建它自己的,了解這一點(diǎn),就可以明白更多事情,在此省略更多的細(xì)節(jié)了。在成員內(nèi)部類要引用外部類對(duì)象時(shí),使用outer.this來(lái)表示外部類對(duì)象;而需要?jiǎng)?chuàng)建內(nèi)部類對(duì)象,可以使用outer.innerobj = outerobj.new inner();public class Outer {
public static void main(String[] args){
Outer outer = new Outer();
Outer.Inner inner = outer.new Inner();
inner.print(“Outer.new”);
inner = outer.getInner();
inner.print(“Outer.get”);
}
// 個(gè)人推薦使用getxxx()來(lái)獲取成員內(nèi)部類,尤其是該內(nèi)部類的構(gòu)造函數(shù)無(wú)參數(shù)時(shí)public Inner getInner(){
return new Inner();
}
public class Inner {
public void print(String str){
System.out.println(str);
}
}
}
2.局部?jī)?nèi)部類
局部?jī)?nèi)部類,是指內(nèi)部類定義在方法和作用域內(nèi)。Thinking in Java給了這么兩個(gè)例子: 定義在方法內(nèi):
public class Parcel4 {
public Destination destination(String s){
class PDestination implements Destination {
private String label;
private PDestination(String whereTo){
label = whereTo;
}
public String readLabel(){
return label;
}
}
return new PDestination(s);
}
public static void main(String[] args){
Parcel4 p = new Parcel4();
Destination d = p.destination(“Tasmania”);
}
}
定義在作用域里:
public class Parcel5 {
private void internalTracking(boolean b){
if(b){
class TrackingSlip {
private String id;
TrackingSlip(String s){
id = s;
}
String getSlip(){
return id;
}
}
TrackingSlip ts = new TrackingSlip(“slip”);
String s = ts.getSlip();
}
}
public void track(){
internalTracking(true);
}
public static void main(String[] args){
Parcel5 p = new Parcel5();
p.track();
}
}
局部?jī)?nèi)部類也像別的類一樣進(jìn)行編譯,但只是作用域不同而已,只在該方法或條件的作用域內(nèi)才能使用,退出這些作用域后無(wú)法引用的。
3.嵌套內(nèi)部類
嵌套內(nèi)部類,就是修飾為static的內(nèi)部類。聲明為static的內(nèi)部類,不需要內(nèi)部類對(duì)象和外部類對(duì)象之間的聯(lián)系,就是說(shuō)我們可以直接引用outer.inner,即不需要?jiǎng)?chuàng)建外部類,也不需要?jiǎng)?chuàng)建內(nèi)部類。
嵌套類和普通的內(nèi)部類還有一個(gè)區(qū)別:普通內(nèi)部類不能有static數(shù)據(jù)和static屬性,也不能包含嵌套類,但嵌套類可以。而嵌套類不能聲明為private,一般聲明為public,方便調(diào)用。
4.匿名內(nèi)部類
有時(shí)候我為了免去給內(nèi)部類命名,便傾向于使用匿名內(nèi)部類,因?yàn)樗鼪](méi)有名字。例如:((Button)findViewById(R.id.start)).setOnClickListener(new Button.OnClickListener(){@Override
public void onClick(View v){
new Thread(){
@Override
public void run(){
// TODO Auto-generated method stub
}
}.start();
}
});
匿名內(nèi)部類是不能加訪問(wèn)修飾符的。要注意的是,new 匿名類,這個(gè)類是要先定義的,看下面例子:
public class Outer {
public static void main(String[] args){
Outer outer = new Outer();
Inner inner = outer.getInner(“Inner”, “gz”);
System.out.println(inner.getName());
}
public Inner getInner(final String name, String city){
return new Inner(){
private String nameStr = name;
public String getName(){
return nameStr;
}
};
}
}
//注釋后,編譯時(shí)提示類Inner找不到
/* interface Inner {
String getName();
} */
同時(shí)在這個(gè)例子,留意外部類的方法的形參,當(dāng)所在的方法的形參需要被內(nèi)部類里面使用時(shí),該形參必須為final。這里可以看到形參name已經(jīng)定義為final了,而形參city 沒(méi)有被使用則不用定義為final。為什么要定義為final呢?在網(wǎng)上找到本人比較如同的解釋: “這是一個(gè)編譯器設(shè)計(jì)的問(wèn)題,如果你了解java的編譯原理的話很容易理解。
首先,內(nèi)部類被編譯的時(shí)候會(huì)生成一個(gè)單獨(dú)的內(nèi)部類的.class文件,這個(gè)文件并不與外部類在同一class文件中。
當(dāng)外部類傳的參數(shù)被內(nèi)部類調(diào)用時(shí),從java程序的角度來(lái)看是直接的調(diào)用例如:public void dosome(final String a,final int b){
class Dosome{public void dosome(){System.out.println(a+b)}};
Dosome some=new Dosome();
some.dosome();
}
從代碼來(lái)看好像是那個(gè)內(nèi)部類直接調(diào)用的a參數(shù)和b參數(shù),但是實(shí)際上不是,在java編譯器編譯以后實(shí)際的操作代碼是
class Outer$Dosome{
public Dosome(final String a,final int b){
this.Dosome$a=a;
this.Dosome$b=b;
}
public void dosome(){
System.out.println(this.Dosome$a+this.Dosome$b);
}
}}
從以上代碼看來(lái),內(nèi)部類并不是直接調(diào)用方法傳進(jìn)來(lái)的參數(shù),而是內(nèi)部類將傳進(jìn)來(lái)的參數(shù)通過(guò)自己的構(gòu)造器備份到了自己的內(nèi)部,自己內(nèi)部的方法調(diào)用的實(shí)際是自己的屬性而不是外部類方法的參數(shù)。
這樣理解就很容易得出為什么要用final了,因?yàn)閮烧邚耐獗砜雌饋?lái)是同一個(gè)東西,實(shí)際上卻不是這樣,如果內(nèi)部類改掉了這些參數(shù)的值也不可能影響到原參數(shù),然而這樣卻失去了參數(shù)的一致性,因?yàn)閺木幊倘藛T的角度來(lái)看他們是同一個(gè)東西,如果編程人員在程序設(shè)計(jì)的時(shí)候在內(nèi)部類中改掉參數(shù)的值,但是外部調(diào)用的時(shí)候又發(fā)現(xiàn)值其實(shí)沒(méi)有被改掉,這就讓人非常的難以理解和接受,為了避免這種尷尬的問(wèn)題存在,所以編譯器設(shè)計(jì)人員把內(nèi)部類能夠使用的參數(shù)設(shè)定為必須是final來(lái)規(guī)避這種莫名其妙錯(cuò)誤的存在?!?/p>
(簡(jiǎn)單理解就是,拷貝引用,為了避免引用值發(fā)生改變,例如被外部類的方法修改等,而導(dǎo)致內(nèi)部類得到的值不一致,于是用final來(lái)讓該引用不可改變)
因?yàn)槟涿麅?nèi)部類,沒(méi)名字,是用默認(rèn)的構(gòu)造函數(shù)的,無(wú)參數(shù)的,那如果需要參數(shù)呢?則需要該類有帶參數(shù)的構(gòu)造函數(shù):
public class Outer {
public static void main(String[] args){
Outer outer = new Outer();
Inner inner = outer.getInner(“Inner”, “gz”);
System.out.println(inner.getName());
}
public Inner getInner(final String name, String city){
return new Inner(name, city){
private String nameStr = name;
public String getName(){
return nameStr;
}
};
}
}
abstract class Inner {
Inner(String name, String city){
System.out.println(city);
}
abstract String getName();
}
注意這里的形參city,由于它沒(méi)有被匿名內(nèi)部類直接使用,而是被抽象類Inner的構(gòu)造函數(shù)所使用,所以不必定義為final。
而匿名內(nèi)部類通過(guò)實(shí)例初始化,可以達(dá)到類似構(gòu)造器的效果:
public class Outer {
public static void main(String[] args){
Outer outer = new Outer();
Inner inner = outer.getInner(“Inner”, “gz”);
System.out.println(inner.getName());
System.out.println(inner.getProvince());
}
public Inner getInner(final String name, final String city){
return new Inner(){
private String nameStr = name;
private String province;
// 實(shí)例初始化
{
if(city.equals(“gz”)){
province = “gd”;
}else {
province = "";
}
}
public String getName(){
return nameStr;
}
public String getProvince(){
return province;
}
};
}
}
interface Inner {
String getName();
String getProvince();
}
5.內(nèi)部類的繼承
內(nèi)部類的繼承,是指內(nèi)部類被繼承,普通類 extents 內(nèi)部類。而這時(shí)候代碼上要有點(diǎn)特
別處理。
至于內(nèi)部類的重載,感覺(jué)Thinking in Java的例子很復(fù)雜,在平常應(yīng)用中應(yīng)該很少,因?yàn)橛悬c(diǎn)難懂,不清晰。而內(nèi)部類和閉包之間的事情,暫時(shí)放下,以后再看。
第二篇:Java內(nèi)部類總結(jié)
內(nèi)部類是指在一個(gè)外部類的內(nèi)部再定義一個(gè)類。內(nèi)部類作為外部類的一個(gè)成員,并且依附于外部類而存在的。內(nèi)部類可為靜態(tài),可用protected和 private修飾(而外部類只能使用public和缺省的包訪問(wèn)權(quán)限)。內(nèi)部類主要有以下幾類:成員內(nèi)部類、局部?jī)?nèi)部類、靜態(tài)內(nèi)部類、匿名內(nèi)部類
為什么需要內(nèi)部類?
典型的情況是,內(nèi)部類繼承自某個(gè)類或?qū)崿F(xiàn)某個(gè)接口,內(nèi)部類的代碼操作創(chuàng)建其的外圍類的對(duì)象。所以你可以認(rèn)為內(nèi)部類提供了某種進(jìn)入其外圍類的窗口。使用內(nèi)部類最吸引人的原因是:
每個(gè)內(nèi)部類都能獨(dú)立地繼承自一個(gè)(接口的)實(shí)現(xiàn),所以無(wú)論外圍類是否已經(jīng)繼承了某個(gè)(接口的)實(shí)現(xiàn),對(duì)于內(nèi)部類都沒(méi)有影響。如果沒(méi)有內(nèi)部類提供的可以繼 承多個(gè)具體的或抽象的類的能力,一些設(shè)計(jì)與編程問(wèn)題就很難解決。從這個(gè)角度看,內(nèi)部類使得多重繼承的解決方案變得完整。接口解決了部分問(wèn)題,而內(nèi)部類有效 地實(shí)現(xiàn)了“多重繼承”。
A:成員內(nèi)部類
作為外部類的一個(gè)成員存在,與外部類的屬性、方法并列。
public class Outer { private static int i = 1;private int j = 10;private int k = 20;
public static void outer_f1(){ }
public void outer_f2(){ }
// 成員內(nèi)部類中,不能定義靜態(tài)成員
// 成員內(nèi)部類中,可以訪問(wèn)外部類的所有成員 class Inner { // static int inner_i = 100;//內(nèi)部類中不允許定義靜態(tài)變量 int j = 100;// 內(nèi)部類和外部類的實(shí)例變量可以共存 intinner_i = 1;
void inner_f1(){ System.out.println(i);//在內(nèi)部類中訪問(wèn)內(nèi)部類自己的變量直接用變量名 System.out.println(j);//在內(nèi)部類中訪問(wèn)內(nèi)部類自己的變量也可以用this.變量名 System.out.println(this.j);//在內(nèi)部類中訪問(wèn)外部類中與內(nèi)部類同名的實(shí)例變量用外部類名.this.變量名 System.out.println(Outer.this.j);//如果內(nèi)部類中沒(méi)有與外部類同名的變量,則可以直接用變量名訪問(wèn)外部類變量 System.out.println(k);outer_f1();outer_f2();} }
//外部類的非靜態(tài)方法訪問(wèn)成員內(nèi)部類 public void outer_f3(){ Inner inner = new Inner();inner.inner_f1();}
// 外部類的靜態(tài)方法訪問(wèn)成員內(nèi)部類,與在外部類外部訪問(wèn)成員內(nèi)部類一樣 public static void outer_f4(){ //step1 建立外部類對(duì)象 Outer out = new Outer();//step2 根據(jù)外部類對(duì)象建立內(nèi)部類對(duì)象 Inner inner = out.new Inner();//step3 訪問(wèn)內(nèi)部類的方法 inner.inner_f1();}
publicstaticvoid main(String[] args){ //outer_f4();//該語(yǔ)句的輸出結(jié)果和下面三條語(yǔ)句的輸出結(jié)果一樣
//如果要直接創(chuàng)建內(nèi)部類的對(duì)象,不能想當(dāng)然地認(rèn)為只需加上外圍類Outer的名字,//就可以按照通常的樣子生成內(nèi)部類的對(duì)象,而是必須使用此外圍類的一個(gè)對(duì)象來(lái) //創(chuàng)建其內(nèi)部類的一個(gè)對(duì)象:
//Outer.Inner outin = out.new Inner()//因此,除非你已經(jīng)有了外圍類的一個(gè)對(duì)象,否則不可能生成內(nèi)部類的對(duì)象。因?yàn)榇?//內(nèi)部類的對(duì)象會(huì)悄悄地鏈接到創(chuàng)建它的外圍類的對(duì)象。如果你用的是靜態(tài)的內(nèi)部類,//那就不需要對(duì)其外圍類對(duì)象的引用。Outer out = new Outer();Outer.Inner outin = out.new Inner();outin.inner_f1();} }
注意:內(nèi)部類是一個(gè)編譯時(shí)的概念,一旦編譯成功,就會(huì)成為完全不同的兩類。對(duì)于一個(gè)名為outer的外部類和其內(nèi)部定義的名為inner的內(nèi)部類。編譯完成后出現(xiàn)outer.class和outer$inner.class兩類。
B:局部?jī)?nèi)部類
在方法中定義的內(nèi)部類稱為局部?jī)?nèi)部類。與局部變量類似,局部?jī)?nèi)部類不能有訪問(wèn)說(shuō)明符,因?yàn)樗皇峭鈬惖囊徊糠?,但是它可以訪問(wèn)當(dāng)前代碼塊內(nèi)的常量,和此外圍類所有的成員。
public class Outer { private ints = 100;private int out_i = 1;
public void f(final int k){ final int s = 200;int i = 1;final int j = 10;
//定義在方法內(nèi)部 class Inner { ints = 300;// 可以定義與外部類同名的變量
// static int m = 20;//不可以定義靜態(tài)變量 Inner(int k){ inner_f(k);}
intinner_i = 100;
void inner_f(int k){ //如果內(nèi)部類沒(méi)有與外部類同名的變量,在內(nèi)部類中可以直接訪問(wèn)外部類的實(shí)例變量 System.out.println(out_i);//可以訪問(wèn)外部類的局部變量(即方法內(nèi)的變量),但是變量必須是final的 System.out.println(j);//System.out.println(i);//如果內(nèi)部類中有與外部類同名的變量,直接用變量名訪問(wèn)的是內(nèi)部類的變量 System.out.println(s);//用this.變量名訪問(wèn)的也是內(nèi)部類變量 System.out.println(this.s);//用外部類名.this.內(nèi)部類變量名訪問(wèn)的是外部類變量 System.out.println(Outer.this.s);} } new Inner(k);} publicstaticvoid main(String[] args){ // 訪問(wèn)局部?jī)?nèi)部類必須先有外部類對(duì)象 Outer out = new Outer();out.f(3);} }
C:靜態(tài)內(nèi)部類(嵌套類):(注意:前兩種內(nèi)部類與變量類似,所以可以對(duì)照參考變量)
如果你不需要內(nèi)部類對(duì)象與其外圍類對(duì)象之間有聯(lián)系,那你可以將內(nèi)部類聲明為static。這通常稱為嵌套類(nested class)。想要理解static應(yīng)用于內(nèi)部類時(shí)的含義,你就必須記住,普通的內(nèi)部類對(duì)象隱含地保存了一個(gè)引用,指向創(chuàng)建它的外圍類對(duì)象。然而,當(dāng)內(nèi)部 類是static的時(shí),就不是這樣了。嵌套類意味著:
1.要?jiǎng)?chuàng)建嵌套類的對(duì)象,并不需要其外圍類的對(duì)象。
2.不能從嵌套類的對(duì)象中訪問(wèn)非靜態(tài)的外圍類對(duì)象。
publicclass Outer { privatestaticinti = 1;privateintj = 10;publicstaticvoidouter_f1(){ }
publicvoidouter_f2(){ }
// 靜態(tài)內(nèi)部類可以用public,protected,private修飾
// 靜態(tài)內(nèi)部類中可以定義靜態(tài)或者非靜態(tài)的成員 staticclass Inner { staticintinner_i = 100;intinner_j = 200;staticvoidinner_f1(){ //靜態(tài)內(nèi)部類只能訪問(wèn)外部類的靜態(tài)成員(包括靜態(tài)變量和靜態(tài)方法)System.out.println(“Outer.i” + i);outer_f1();}
voidinner_f2(){ // 靜態(tài)內(nèi)部類不能訪問(wèn)外部類的非靜態(tài)成員(包括非靜態(tài)變量和非靜態(tài)方法)// System.out.println(“Outer.i”+j);// outer_f2();} }
publicvoidouter_f3(){ // 外部類訪問(wèn)內(nèi)部類的靜態(tài)成員:內(nèi)部類.靜態(tài)成員 System.out.println(Inner.inner_i);Inner.inner_f1();// 外部類訪問(wèn)內(nèi)部類的非靜態(tài)成員:實(shí)例化內(nèi)部類即可 Inner inner = new Inner();inner.inner_f2();}
publicstaticvoid main(String[] args){ newOuter().outer_f3();} }
生成一個(gè)靜態(tài)內(nèi)部類不需要外部類成員:這是靜態(tài)內(nèi)部類和成員內(nèi)部類的區(qū)別。靜態(tài)內(nèi)部類的對(duì)象可以直接生成:Outer.Inner in = new Outer.Inner();而不需要通過(guò)生成外部類對(duì)象來(lái)生成。這樣實(shí)際上使靜態(tài)內(nèi)部類成為了一個(gè)頂級(jí)類(正常情況下,你不能在接口內(nèi)部放置任何代碼,但嵌套類可以作為接口的一部 分,因?yàn)樗莝tatic 的。只是將嵌套類置于接口的命名空間內(nèi),這并不違反接口的規(guī)則)
D:匿名內(nèi)部類(from thinking in java 3th)
簡(jiǎn)單地說(shuō):匿名內(nèi)部類就是沒(méi)有名字的內(nèi)部類。什么情況下需要使用匿名內(nèi)部類?如果滿足下面的一些條件,使用匿名內(nèi)部類是比較合適的:
·只用到類的一個(gè)實(shí)例。
·類在定義后馬上用到。
·類非常小(SUN推薦是在4行代碼以下)
·給類命名并不會(huì)導(dǎo)致你的代碼更容易被理解。
在使用匿名內(nèi)部類時(shí),要記住以下幾個(gè)原則:
·匿名內(nèi)部類不能有構(gòu)造方法。
·匿名內(nèi)部類不能定義任何靜態(tài)成員、方法和類。
·匿名內(nèi)部類不能是public,protected,private,static。
·只能創(chuàng)建匿名內(nèi)部類的一個(gè)實(shí)例。
·一個(gè)匿名內(nèi)部類一定是在new的后面,用其隱含實(shí)現(xiàn)一個(gè)接口或?qū)崿F(xiàn)一個(gè)類。
·因匿名內(nèi)部類為局部?jī)?nèi)部類,所以局部?jī)?nèi)部類的所有限制都對(duì)其生效。
下面的例子看起來(lái)有點(diǎn)奇怪:
//在方法中返回一個(gè)匿名內(nèi)部類 public class Parcel6 { public Contents cont(){ return new Contents(){ private int i = 11;
public int value(){ return i;} };// 在這里需要一個(gè)分號(hào) }
public static void main(String[] args){ Parcel6 p = new Parcel6();Contents c = p.cont();} }
cont()方法將下面兩個(gè)動(dòng)作合并在一起:返回值的生成,與表示這個(gè)返回值的類的定義!進(jìn)一步說(shuō),這個(gè)類是匿名的,它沒(méi)有名字。更糟的是,看起來(lái)是你正要?jiǎng)?chuàng)建一個(gè)Contents對(duì)象:
return new Contents()
但是,在到達(dá)語(yǔ)句結(jié)束的分號(hào)之前,你卻說(shuō):“等一等,我想在這里插入一個(gè)類的定義”:
return new Contents(){ private int i = 11;public int value(){ return i;} };
這種奇怪的語(yǔ)法指的是:“創(chuàng)建一個(gè)繼承自Contents的匿名類的對(duì)象?!蓖ㄟ^(guò)new 表達(dá)式返回的引用被自動(dòng)向上轉(zhuǎn)型為對(duì)Contents的引用。匿名內(nèi)部類的語(yǔ)法是下面例子的簡(jiǎn)略形式:
class MyContents implements Contents { private int i = 11;public int value(){ return i;} } return new MyContents();
在這個(gè)匿名內(nèi)部類中,使用了缺省的構(gòu)造器來(lái)生成Contents。下面的代碼展示的是,如果你的基類需要一個(gè)有參數(shù)的構(gòu)造器,應(yīng)該怎么辦:
public class Parcel7 { public Wrapping wrap(int x){ // Base constructor call: return new Wrapping(x){ // Pass constructor argument.public int value(){ return super.value()* 47;} };// Semicolon required } public static void main(String[] args){ Parcel7 p = new Parcel7();Wrapping w = p.wrap(10);} }
只需簡(jiǎn)單地傳遞合適的參數(shù)給基類的構(gòu)造器即可,這里是將x 傳進(jìn)new Wrapping(x)。在匿名內(nèi)部類末尾的分號(hào),并不是用來(lái)標(biāo)記此內(nèi)部類結(jié)束(C++中是那樣)。實(shí)際上,它標(biāo)記的是表達(dá)式的結(jié)束,只不過(guò)這個(gè)表達(dá)式正 巧包含了內(nèi)部類罷了。因此,這與別的地方使用的分號(hào)是一致的。
如果在匿名類中定義成員變量,你同樣能夠?qū)ζ鋱?zhí)行初始化操作:
public class Parcel8 { // Argument must be final to use inside // anonymous inner class: public Destination dest(final String dest){ return new Destination(){ private String label = dest;public String readLabel(){ return label;} };} public static void main(String[] args){ Parcel8 p = new Parcel8();Destination d = p.dest(“Tanzania”);} }
如果你有一個(gè)匿名內(nèi)部類,它要使用一個(gè)在它的外部定義的對(duì)象,編譯器會(huì)要求其參數(shù)引用是final 型的,就像dest()中的參數(shù)。如果你忘記了,會(huì)得到一個(gè)編譯期錯(cuò)誤信息。如果只是簡(jiǎn)單地給一個(gè)成員變量賦值,那么此例中的方法就可以了。但是,如果你 想做一些類似構(gòu)造器的行為,該怎么辦呢?在匿名類中不可能有已命名的構(gòu)造器(因?yàn)樗緵](méi)名字?。?,但通過(guò)實(shí)例初始化,你就能夠達(dá)到為匿名內(nèi)部類“制作” 一個(gè)構(gòu)造器的效果。像這樣做:00000000000000
abstract class Base { public Base(int i){ System.out.println(“Base constructor, i = ” + i);} public abstract void f();}
public class AnonymousConstructor { public static Base getBase(int i){ return new Base(i){ { System.out.println(“Inside instance initializer”);} public void f(){ System.out.println(“In anonymous f()”);} };} public static void main(String[] args){ Base base = getBase(47);base.f();} }
在此例中,不要求變量i 一定是final 的。因?yàn)閕 被傳遞給匿名類的基類的構(gòu)造器,它并不會(huì)在匿名類內(nèi)部被直接使用。下例是帶實(shí)例初始化的“parcel”形式。注意dest()的參數(shù)必須是final,因?yàn)樗鼈兪窃谀涿悆?nèi)被使用的。
public class Parcel9 { public Destinationdest(final String dest, final float price){ return new Destination(){ private int cost;// Instance initialization for each object: { cost = Math.round(price);if(cost > 100)System.out.println(“Over budget!”);}
private String label = dest;public String readLabel(){ return label;} };} public static void main(String[] args){ Parcel9 p = new Parcel9();Destination d = p.dest(“Tanzania”, 101.395F);} }
在實(shí)例初始化的部分,你可以看到有一段代碼,那原本是不能作為成員變量初始化的一部分而執(zhí)行的(就是if 語(yǔ)句)。所以對(duì)于匿名類而言,實(shí)例初始化的實(shí)際效果就是構(gòu)造器。當(dāng)然它受到了限制:你不能重載實(shí)例初始化,所以你只能有一個(gè)構(gòu)造器。
從多層嵌套類中訪問(wèn)外部
一個(gè)內(nèi)部類被嵌套多少層并不重要,它能透明地訪問(wèn)所有它所嵌入的外圍類的所有成員,如下所示:
class MNA { private void f(){} class A { private void g(){} public class B { void h(){ g();f();} } } } public class MultiNestingAccess { public static void main(String[] args){ MNA mna = new MNA();MNA.A mnaa = mna.new A();MNA.A.B mnaab = mnaa.new B();mnaab.h();} }
可以看到在MNA.A.B中,調(diào)用方法g()和f()不需要任何條件(即使它們被定義為private)。這個(gè)例子同時(shí)展示了如何從不同的類里面創(chuàng)建多層嵌套的內(nèi)部類對(duì)象的基本語(yǔ)法?!?new”語(yǔ)法能產(chǎn)生正確的作用域,所以你不必在調(diào)用構(gòu)造器時(shí)限定類名。
內(nèi)部類的重載問(wèn)題
如果你創(chuàng)建了一個(gè)內(nèi)部類,然后繼承其外圍類并重新定義此內(nèi)部類時(shí),會(huì)發(fā)生什么呢?也就是說(shuō),內(nèi)部類可以被重載嗎?這看起來(lái)似乎是個(gè)很有用的點(diǎn)子,但是“重載”內(nèi)部類就好像它是外圍類的一個(gè)方法,其實(shí)并不起什么作用:
class Egg { private Yolk y;
protectedclass Yolk { public Yolk(){ System.out.println(“Egg.Yolk()”);} }
public Egg(){ System.out.println(“New Egg()”);y = new Yolk();} }
publicclass BigEgg extends Egg { publicclass Yolk { public Yolk(){ System.out.println(“BigEgg.Yolk()”);} }
publicstaticvoid main(String[] args){ new BigEgg();} }
輸出結(jié)果為:
New Egg()Egg.Yolk()
缺省的構(gòu)造器是編譯器自動(dòng)生成的,這里是調(diào)用基類的缺省構(gòu)造器。你可能認(rèn)為既然創(chuàng)建了BigEgg 的對(duì)象,那么所使用的應(yīng)該是被“重載”過(guò)的Yolk,但你可以從輸出中看到實(shí)際情況并不是這樣的。
這個(gè)例子說(shuō)明,當(dāng)你繼承了某個(gè)外圍類的時(shí)候,內(nèi)部類并沒(méi)有發(fā)生什么特別神奇的變化。這兩個(gè)內(nèi)部類是完全獨(dú)立的兩個(gè)實(shí)體,各自在自己的命名空間內(nèi)。當(dāng)然,明確地繼承某個(gè)內(nèi)部類也是可以的:
class Egg2 { protected class Yolk { public Yolk(){ System.out.println(“Egg2.Yolk()”);}
public void f(){ System.out.println(“Egg2.Yolk.f()”);} }
private Yolk y = new Yolk();
public Egg2(){ System.out.println(“New Egg2()”);}
public void insertYolk(Yolk yy){ y = yy;}
public void g(){ y.f();} }
public class BigEgg2 extends Egg2 { public class Yolk extends Egg2.Yolk { public Yolk(){ System.out.println(“BigEgg2.Yolk()”);}
public void f(){ System.out.println(“BigEgg2.Yolk.f()”);} }
public BigEgg2(){ insertYolk(new Yolk());}
public static void main(String[] args){ Egg2 e2 = new BigEgg2();e2.g();} }
輸出結(jié)果為:
Egg2.Yolk()New Egg2()Egg2.Yolk()BigEgg2.Yolk()BigEgg2.Yolk.f()
現(xiàn)在BigEgg2.Yolk 通過(guò)extends Egg2.Yolk 明確地繼承了此內(nèi)部類,并且重載了其中的方法。Egg2 的insertYolk()方法使得BigEgg2 將它自己的Yolk 對(duì)象向上轉(zhuǎn)型,然后傳遞給引用y。所以當(dāng)g()調(diào)用y.f()時(shí),重載后的新版的f()被執(zhí)行。第二次調(diào)用Egg2.Yolk()是 BigEgg2.Yolk 的構(gòu)造器調(diào)用了其基類的構(gòu)造器??梢钥吹皆谡{(diào)用g()的時(shí)候,新版的f()被調(diào)用了。
內(nèi)部類的繼承問(wèn)題(thinking in java 3th p294)
因?yàn)閮?nèi)部類的構(gòu)造器要用到其外圍類對(duì)象的引用,所以在你繼承一個(gè)內(nèi)部類的時(shí)候,事情變得有點(diǎn)復(fù)雜。問(wèn)題在于,那個(gè)“秘密的”外圍類對(duì)象的引用必須被初始化,而在被繼承的類中并不存在要聯(lián)接的缺省對(duì)象。要解決這個(gè)問(wèn)題,需使用專門的語(yǔ)法來(lái)明確說(shuō)清它們之間的關(guān)聯(lián):
class WithInner { class Inner { Inner(){ System.out.println(“this is a constructor in WithInner.Inner”);};} }
public class InheritInner extends WithInner.Inner { //!InheritInner(){} // Won't compile InheritInner(WithInner wi){ wi.super();System.out.println(“this is a constructor in InheritInner”);}
public static void main(String[] args){ WithInner wi = new WithInner();InheritInner ii = new InheritInner(wi);} }
輸出結(jié)果為:
this is a constructor in WithInner.Inner this is a constructor in InheritInner
可以看到,InheritInner 只繼承自內(nèi)部類,而不是外圍類。但是當(dāng)要生成一個(gè)構(gòu)造器時(shí),缺省的構(gòu)造器并不算好,而且你不能只是傳遞一個(gè)指向外圍類對(duì)象的引用。此外,你必須在構(gòu)造器內(nèi)使用如下語(yǔ)法:
enclosingClassReference.super();
這樣才提供了必要的引用,然后程序才能編譯通過(guò)。
1.實(shí)例化非靜態(tài)內(nèi)部類時(shí)是否需要先實(shí)例化外部類,為什么?
2.非靜態(tài)內(nèi)部類可以訪問(wèn)其外部類的哪些成員,為什么?
3.內(nèi)部類可以定義在外部類的哪些位置,要實(shí)例化各位置的內(nèi)部類有哪些限制? 4.匿名內(nèi)部類和普通內(nèi)部類有什么區(qū)別,為什么創(chuàng)建匿名內(nèi)部類時(shí)可以new抽象類或接口?
5.如何在匿名內(nèi)部類實(shí)現(xiàn)構(gòu)造器的行為?
6.嵌套類(靜態(tài)內(nèi)部類)和普通非靜態(tài)類有什么區(qū)別?
7.當(dāng)繼承一個(gè)類時(shí),如何覆蓋它的內(nèi)部類?
回答:
1.實(shí)例化非靜態(tài)內(nèi)部類需要先實(shí)例化外部類,因?yàn)榉庆o態(tài)內(nèi)部類就像外部類的實(shí)例域一樣,和外部類是有關(guān)聯(lián)的。
2.非靜態(tài)內(nèi)部類可以訪問(wèn)其外部類的所有成員,因?yàn)樵趯?shí)例化內(nèi)部類時(shí),會(huì)隱式的保留其外部類的實(shí)例的一個(gè)引用,通過(guò)該引用來(lái)訪問(wèn)外部類的成員,而內(nèi)部類是在外部類的里面,所以不受訪問(wèn)修飾符的限制。
3.內(nèi)部類可以定義在外部類的內(nèi)部、方法體、局部域,在內(nèi)部的類可以通過(guò)外部類的實(shí)例來(lái)實(shí)例化,方法體和局部域 只能在定義的域?qū)嵗?.匿名內(nèi)部類沒(méi)有類名,沒(méi)有構(gòu)造函數(shù),當(dāng)在匿名內(nèi)部類里使用外部類定義的對(duì)象時(shí),需要用final修改該對(duì)象,匿名
內(nèi)部類只能單繼承單實(shí)現(xiàn)。匿名內(nèi)部類new的并非對(duì)象本身,而是作為其子類實(shí)例化,所以new抽象類或接口時(shí),實(shí)際上是實(shí)例化該抽象類的一個(gè)子類或?qū)崿F(xiàn)該接口的一個(gè)類。
5.通過(guò)實(shí)例域初始化(在內(nèi)部類加一對(duì)花括號(hào))來(lái)實(shí)現(xiàn)匿名內(nèi)部類的構(gòu)造器行為。
6.1)嵌套類不保留其外部類的實(shí)例的引用,因?yàn)榍短最惡屯獠繘](méi)有任何關(guān)系。2)實(shí)例化嵌套類不需要先實(shí)例化其外部類,直接使用嵌套類的限定名進(jìn)行實(shí)例化(如果嵌套類的訪問(wèn)級(jí)別允許)3)內(nèi)部類不能包含靜態(tài)域和嵌套類,嵌套類可以。
7.繼承一個(gè)A類時(shí),對(duì)于A類的內(nèi)部類不會(huì)有什么影響變化,如果要覆蓋A類的內(nèi)部類,則可以定義一個(gè)內(nèi)部類繼承A類的內(nèi)部類。
第三篇:JAVA 內(nèi)部類的簡(jiǎn)單總結(jié)
核心提示:定義在一個(gè)類內(nèi)部的類叫內(nèi)部類,包含內(nèi)部類的類稱為外部類。內(nèi)部類提供更好的封裝,可以把內(nèi)部類隱藏在外部類之內(nèi),不允許同一個(gè)包中其他類訪問(wèn)。內(nèi)部類可以聲明public、protected、private等訪問(wèn)限制,可以聲明為abstract的供其他內(nèi)部類或外部類繼承與擴(kuò)展定義在一個(gè)類內(nèi)部的類叫內(nèi)部類,包含內(nèi)部類的類稱為外部類。內(nèi)部類提供更好的封裝,可以把內(nèi)部類隱藏在外部類之內(nèi),不允許同一個(gè)包中其他類訪問(wèn)。內(nèi)部類可以聲明public、protected、private等訪問(wèn)限制,可以聲明為abstract的供其他內(nèi)部類或外部類繼承與擴(kuò)展,或者聲明為static、final的,也可以實(shí)現(xiàn)特定的接口。static的內(nèi)部類行為上象一個(gè)獨(dú)立的類,非static在行為上類似類的屬性或方法且禁止聲明static的方法。內(nèi)部類可以訪問(wèn)外部類的所有方法與屬性,內(nèi)部類被單成其外部類的成員,同一個(gè)類的成員之間可以相互訪問(wèn)。但外部類不能訪問(wèn)內(nèi)部類的實(shí)現(xiàn)細(xì)節(jié),如內(nèi)部類的屬性。static的內(nèi)部類只能訪問(wèn)外部類的靜態(tài)屬性與方法。匿名內(nèi)部類適合用于創(chuàng)建那些僅需要一次使用的類。
內(nèi)部類被作為成員內(nèi)部類定義,而且不是局部?jī)?nèi)部類。成員內(nèi)部類是一種與屬性、方法、構(gòu)造器和初始化塊相似的類成員;局部?jī)?nèi)部類和匿名內(nèi)部類則不是類成員。成員內(nèi)部類分為兩種:靜態(tài)內(nèi)部類(使用static修飾)和非靜態(tài)內(nèi)部類,當(dāng)在非靜態(tài)內(nèi)部類的方法訪問(wèn)某個(gè)變量時(shí),系統(tǒng)優(yōu)先在該方法內(nèi)查找是否在該名字的局部變量,如果存在改名字的局部變量,就是用改變量;如果不存在則到內(nèi)部類所在的外部類中查找是否存在改名字的屬性,如果存在就是用。如果不存在編譯錯(cuò)誤。
如外部類屬性、內(nèi)部類屬性與內(nèi)部類里方法的局部變量通明,則通過(guò)使用this,外部類類名.this作為限制類區(qū)分。
1.public class DiscernVariable
2.{
3.private String prop = “外部類屬性”;
4.private class InClass
5.{
6.private String prop = “內(nèi)部類屬性”;
7.public void info()
8.{
9.String prop = “局部變量”;
10.//通過(guò) 外部類類名.this.varName 訪問(wèn)外部類實(shí)例屬性
11.System.out.println(“外部類的屬性值:” + DiscernVariable.this.prop);
12.//通過(guò) this.varName 訪問(wèn)外內(nèi)部類實(shí)例的屬性
13.System.out.println(“內(nèi)部類的屬性值:” + this.prop);
14.//直接訪問(wèn)局部變量
15.System.out.println(“局部變量的屬性值:” + prop);
16.}
17.}
18.public void test()
19.{
20.InClass in = new InClass();
21.in.info();
22.}
23.public static void main(String[] args)
24.{
25.new DiscernVariable().test();
26.}
27.}
非靜態(tài)內(nèi)部類的成員可以訪問(wèn)外部類的private成員,但反過(guò)來(lái)不可以。非靜態(tài)內(nèi)部類成員只在非靜態(tài)內(nèi)部類范圍內(nèi)是可知的,并不能被外部類直接使用。如果外部類需要訪問(wèn)非靜態(tài)內(nèi)部類成員,則必須相示創(chuàng)建非靜態(tài)內(nèi)部類對(duì)象來(lái)調(diào)用訪問(wèn)其實(shí)例成員。
1.public class Outer
2.{
3.private int outProp = 9;
4.class Inner
5.{
6.private int inProp = 5;
7.public void acessOuterProp()
8.{
9.//內(nèi)部類可以直接訪問(wèn)外部類的成員
10.System.out.println(“外部類的outProp屬性值:” + outProp);
11.}
12.}
13.public void accessInnerProp()
14.{
15.//外部類不能直接訪問(wèn)內(nèi)部類屬性,下面代碼出現(xiàn)編譯錯(cuò)誤
16.//System.out.println(“內(nèi)部類的inProp屬性值:” + inProp);
17.//如需訪問(wèn)內(nèi)部類成員,必須顯式創(chuàng)建內(nèi)部類對(duì)象
18.System.out.println(“內(nèi)部類的inProp屬性值:” + new Inner().inProp);19.20.}
21.public static void main(String[] args)
22.{
23.//執(zhí)行下面代碼,只創(chuàng)建了外部類對(duì)象,還未創(chuàng)建內(nèi)部類對(duì)象
24.Outer out = new Outer();
25.}
26.}
外部類按常規(guī)的類訪問(wèn)方式使用內(nèi)部類,唯一的差別是外部類可以訪問(wèn)內(nèi)部類的所有方法與屬性,包括私有方法與屬性。如:
1.pinner p = new pinner();
2.p.index = 20;
3.p.Print();
4.----這種方式適合外部類的非static方法;
5.6.pouter po = new pouter();
7.pinner pi = po.new pinner();
8.pi.index = 40;
9.pi.Print();
10.----這種方式適合外部類的static方法;
內(nèi)部類類似外部類的屬性,因此訪問(wèn)內(nèi)部類對(duì)象時(shí)總是需要一個(gè)創(chuàng)建好的外部類對(duì)象。內(nèi)部類對(duì)象通過(guò)‘外部類名.this.xxx’的形式訪問(wèn)外部類的屬性與方法。如:
1.System.out.println(“Print in inner Outer.index=” + pouter.this.index);
2.System.out.println(“Print in inner Inner.index=” + this.index);
如果需要在其他類中訪問(wèn)內(nèi)部類,可以使用:
(1)外部類提供創(chuàng)建內(nèi)部類的方法供其他類使用。如:
1.// 外部類
2.pinner getInner()
3.{
4.return new pinner();
5.}
6.7.// 其他類
8.pouter.pinner pi = po.getInner();
9.pi.Print();
(2)直接創(chuàng)建內(nèi)部類的對(duì)象。如:
1.pouter po = new pouter();
2.pouter.pinner pi = po.new pinner();
3.pi.Print();
內(nèi)部類可以聲明在外部類的方法中或語(yǔ)句塊中。如果內(nèi)部類需要訪問(wèn)包含它的外部類方法或語(yǔ)句塊的局部變量或參數(shù),則該局部變量或參數(shù)必須是final的。外部類的其他方法、其他類無(wú)法訪問(wèn)聲明在方法內(nèi)部或塊內(nèi)部的內(nèi)部類。
如果一個(gè)類繼承內(nèi)部類,則創(chuàng)建該類的對(duì)象時(shí)需提供一個(gè)外部類的對(duì)象作為構(gòu)造方法的參數(shù)。如:
1.class Car
2.{
3.class Wheel
4.{
5.6.}
7.}
8.9.class SuperWheel extends Car.Wheel
10.{
11.SuperWheel(Car car)
12.{
13.car.super();
14.}
15.16.public static void main(String [] args)
17.{
18.Car car = new Car();
19.SuperWheel wl = new SuperWheel(car);
20.}
21.}
如果創(chuàng)建命名的內(nèi)部類沒(méi)有多少實(shí)際意義時(shí),可以創(chuàng)建匿名的內(nèi)部類。比如使用內(nèi)部類實(shí)現(xiàn)接口的功能(如事件處理器、適配器等),而功能的差異較大,需要根據(jù)實(shí)際的情況創(chuàng)建相應(yīng)的內(nèi)部類時(shí),可以使用匿名內(nèi)部類。簡(jiǎn)單的示例如下:
1.interface WebView
2.{
3.void doGet();
4.}
5.6.class A
7.{
8.WebView ShowName()
9.{
10.return new WebView()
11.{
12.void doGet()
13.{
14.System.out.println(“Name”);
15.}
16.};
17.}
18.19.WebView ShowCode()
20.{
21.return new WebView()
22.{
23.void doGet()
24.{
25.System.out.println(“Code”);
26.}
27.};
28.}
29.}
最后,JAVA 內(nèi)部類還有一個(gè)作用,那就是實(shí)現(xiàn)JAVA的多繼承。JAVA本身是不允許多繼承的,如果我們想一個(gè)類繼承多個(gè)基類,就可以使用內(nèi)部類。通過(guò)內(nèi)部類分別繼承一個(gè)基類,外部類創(chuàng)建內(nèi)部類的對(duì)象,并使用內(nèi)部類的方法,變相地實(shí)現(xiàn)了多繼承。
第四篇:部類如何造句
【注音】: bu lei
【意思】:概括性較大的類。
部類造句:
1、馬克思的兩部類分析模式,對(duì)現(xiàn)實(shí)經(jīng)濟(jì)仍然具有指導(dǎo)作用。
2、這里所說(shuō)的是實(shí)現(xiàn)細(xì)節(jié)了,我們可以直接訪問(wèn)外部類中的變量,就好像這些變量定義在內(nèi)部類中一樣。
3、技術(shù)進(jìn)步、增加工資、對(duì)外貿(mào)易都減緩兩部類生產(chǎn)不均衡,延緩經(jīng)濟(jì)危機(jī)發(fā)生。
4、一旦定義了這些訪問(wèn)限制,Eclipse這個(gè)Java訪問(wèn)工具就會(huì)對(duì)內(nèi)部類的訪問(wèn)提供和其他編譯器警告一樣的提示。
5、史部成為獨(dú)立的部類經(jīng)過(guò)了一個(gè)很長(zhǎng)的發(fā)展過(guò)程。
6、安全科學(xué)是介于數(shù)學(xué)、自然科學(xué)、系統(tǒng)科學(xué)與哲學(xué)、社會(huì)科學(xué)、思維科學(xué)各科學(xué)部類之間的新興交叉學(xué)科門類。
7、要對(duì)城市休閑產(chǎn)業(yè)集聚進(jìn)行實(shí)證性研究,就必須在對(duì)休閑產(chǎn)業(yè)部類劃分的前提下進(jìn)行。
8、本文的目的在于改進(jìn)連續(xù)桿戰(zhàn)斗部類導(dǎo)彈殺傷概率的計(jì)算模型。
9、實(shí)際上,成員完全定義在類中的要求限制了局部類成員函數(shù)的復(fù)雜性。
10、如果把不同部類的增長(zhǎng)情況進(jìn)行分類的話,大部分出口價(jià)格從2001年以來(lái)的增長(zhǎng)都可以歸咎于燃料。
11、外圍函數(shù)對(duì)局部類的私有成員沒(méi)有特殊訪問(wèn)權(quán),當(dāng)然,局部類可以將外圍函數(shù)設(shè)為友元。
12、我們擁有著自己的愛(ài)人和部類;擁有我們?cè)?jīng)吞咽過(guò)的美味;
13、但我們死的好富有。我們擁有著自己的愛(ài)人和部類;擁有我們?cè)?jīng)吞咽過(guò)的美味;
14、我們擁有著自己的愛(ài)人和部類;擁有我們?cè)?jīng)吞咽過(guò)的美味;擁有我們進(jìn)入的身軀,我們?cè)谄渲芯拖裨诤永镉伟∮巍?/p>
第五篇:內(nèi)支撐架問(wèn)題總結(jié)
內(nèi)支撐架搭設(shè)常見問(wèn)題
立桿要端正,不得出現(xiàn)明顯傾斜;
所有立桿與樓(地)面之間均需要加設(shè)底座或墊板,且立桿要盡可能的墊在墊板中間,嚴(yán)禁立桿在墊板邊外懸空站立;
梁下立桿與兩側(cè)水平桿相連,嚴(yán)禁出現(xiàn)單桿; 立桿每步每跨縱橫方向均要用水平桿牢固連接,縱向或橫向上的水平桿不得出現(xiàn)跳兩跨甚至三跨的現(xiàn)象;
腳手架必須設(shè)置縱橫向掃地桿??v向掃地桿應(yīng)采用直角扣件固定在距鋼管底端不大于200mm處的立桿上。
剪刀撐要采用旋轉(zhuǎn)扣件固定在與之相交的立桿或水平桿上;(根據(jù)現(xiàn)場(chǎng)情況,剪刀撐兩條桿,至少有一條桿需要和立桿連接,不得全部與水平桿相連)豎向剪刀撐斜桿與地面的傾角應(yīng)為45°到60°之間; 本工程要求每跨均設(shè)置縱、橫向剪刀撐,連續(xù)布置; 水平桿要貫通,不得在中間斷開(包括掃地桿);
扣件必須扣緊、扣勞,不得遺漏或出現(xiàn)松動(dòng)、脫落的現(xiàn)象; 內(nèi)架不得與外架連接在一起。
兩戶人員搭設(shè)范圍之間縱橫掃地桿及水平桿不能斷開,應(yīng)按照后搭者順著先搭者搭設(shè)的水平桿接通搭設(shè);不得出現(xiàn)斷開現(xiàn)象;并注意水平桿接頭位置應(yīng)有意識(shí)的錯(cuò)開;
立桿除頂層頂步外,其余各層各步接頭必須采用對(duì)接扣件連接,特殊部位立桿搭接時(shí),應(yīng)采用不少于2個(gè)扣件固定;且搭接長(zhǎng)度不應(yīng)小于1m;
水平桿長(zhǎng)度不宜小于3跨(兩戶之間未連接的不應(yīng)采用水平短管1跨連接); 滿堂支撐架的可調(diào)托撐螺桿伸出長(zhǎng)度不宜超過(guò)300mm,插入立桿內(nèi)的長(zhǎng)度不得小于150mm;