引用类型
百科名片
引用类型 由类型的实际值引用(类似于指针)表示的数据类型。如果为某个变量分配一个引用类型,则该变量将引用(或“指向”)原始值。不创建任何副本。引用类型包括类、接口、委托和装箱值类型。
目录
引用类型 (reference type)
引用和指针的区别
引用的规则:
引用的主要功能
引用在类中的使用
编辑本段引用类型 (reference type)
“引用”(reference)是c++的一种新的变量类型,是对C的一个重要补充。它的作用是为变量起一个别名。假如有一个变量a,想给它起一个别名,可以这样写:
int a;int &b=a;
这就表明了b是a的“引用”,即a的别名。经过这样的声明,使用a或b的作用相同,都代表同一变量。在上述引用中,&是“引用声明符”,并不代表地址。
不要理解为“把a的值赋给b的地址”。声明引用并不开辟内存单元,b和a都代表同一变量单元。
注意:在声明引用变量类型时,必须同时使之初始化,及声明它代表哪一变量。在声明一个变量的引用之后,在本函数执行期间,该引用一直与其代表的变量相联系
,不能再作为其他变量的别名。下面的用法不对:
int a1,a2;
int &b=a1;
int &b=a2;//企图使b变成a2的别名(引用)是不行的。这样是错误的。
我们可以把a2的值赋给b。
b=a2;
编辑本段引用和指针的区别
看实例吧:
引用是C++中的概念,初学者容易把引用和指针混淆一起。
下面的程序中,n是m的一个引用(reference),m是被引用物(referent)。
int m;
int &n = m;
n相当于m的别名(绰号),对n的任何操作就是对m的操作。
所以n既不是m的拷贝,也不是指向m的指针,其实n就是m它自己。
编辑本段引用的规则:
(1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
(2)不能有NULL引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
(3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。
以下示例程序中,k被初始化为i的引用。
语句k = j并不能将k修改成为j的引用,只是把k的值改变成为6。
由于k是i的引用,所以i的值也变成了6。
int i = 5;
int j = 6;
int &k = i;
k = j; // k和i的值都变成了6;
编辑本段引用的主要功能
引用的主要功能:传递函数的参数和返回值。
C++语言中,函数的参数和返回值的传递方式有三种:值传递、指针传递和引用传递。
以下是"值传递"的示例程序。
由于Func1函数体内的x是外部变量n的一份拷贝,改变x的值不会影响n, 所以n的值仍然是0。
void Func1(int x)
{
x = x + 10;
}
...
int n = 0;
Func1(n);
cout << "n = " << n =" 0" n =" 0;" n = " << n << endl; // n = 10 以下是" size="14">
void Func3(int &x) { x = x + 10; } ... int n = 0; Func3(n); cout << "n = " << n =" 10">
(1) 在实际的程序中,引用主要被用做函数的形式参数--通常将类对象传递给一个函数.引用必须初始化. 但是用对象的地址初始化引用是错误的,我们可以定义一个指针引用。
1 int ival = 1092;
2 int &re = ival; //ok
3 int &re2 = &ival; //错误
4 int *pi = &ival;
5 int *&pi2 = pi; //ok
(2) 一旦引用已经定义,它就不能再指向其他的对象.这就是为什么它要被初始化的原因。
(3) const引用可以用不同类型的对象初始化(只要能从一种类型转换到另一种类型即可),也可以是不可寻址的值,如文字常量。例如
double dval = 3.14159;
//下3行仅对const引用才是合法的
const int &ir = 1024;
const int &ir2 = dval;
const double &dr = dval + 1.0;
上面,同样的初始化对于非const引用是不合法的,将导致编译错误。原因有些微妙,需要适当做些解释。
引用在内部存放的是一个对象的地址,它是该对象的别名。对于不可寻址的值,如文字常量,以及不同类型的对象,编译器为了实现引用,必须生成一个临时对象,引用实际上指向该对象,但用户不能访问它。
例如:
double dval = 23;
const int &ri = dval;
编译器将其转换为:
int tmp = dval; // double -> int
const int &ri = tmp;
同理:上面代码
double dval = 3.14159;
//下3行仅对const引用才是合法的
const int &ir = 1024;
const int &ir2 = dval;
const double &dr = dval + 1.0;
内部转化为:
double dval = 3.14159;
//不可寻址,文字常量
int tmp1 = 1024;
const int &ir = tmp1;
//不同类型
int tmp2 = dval;//double -> int
const int &ir2 = tmp2;
//另一种情况,不可寻址
double tmp3 = dval + 1.0;
const double &dr = tmp3;
(4) 不允许非const引用指向需要临时对象的对象或值,即,编译器产生临时变量的时候引用必须为const!!!!切记!!
int iv = 100;
int *&pir = &iv;//错误,非const引用对需要临时对象的引用
int *const &pir = &iv;//ok
const int ival = 1024;
int *&pi_ref = &ival; //错误,非const引用是非法的
const int *&pi_ref = &ival; //错误,需要临时变量,且引用的是指针,而pi_ref是一个非常量指针
const int * const &pi_ref = &ival; //正确
//补充
const int *p = &ival;
const int *&pi_ref = p; //正确
(5) ********对于const int *const & pi_ref = &iva; 具体的分析如下:*********
1.不允许非const引用指向需要临时对象的对象或值
int a = 2;
int &ref1 = a;// OK.有过渡变量。
const int &ref2 = 2;// OK.编译器产生临时变量,需要const引用
2.地址值是不可寻址的值
int * const &ref3 = &a; // OK;
3.于是,用const对象的地址来初始化一个指向指针的引用
const int b = 23;
const int *p = &b;
const int *& ref4 = p;
const int *const & ref5 = &b; //OK
const引用的语义到底是什么?
最后,我们可能仍然不明白const引用的这个const的语义是什么
const引用表示,试图通过此引用去(间接)改变其引用的对象的值时,编译器会报错!
这并意味着,此引用所引用的对象也因此变成const类型了。我们仍然可以改变其指向对象的值,只是不通过引用
下面是一个简单的例子:
1 #include
2 using namespace std;
3
4 int main()
5 {
6 int val = 1024;
7 const int &ir = val;
8
9 val++;
10 //ir++;
11
12 cout <<>
13
14 return 0;
15 }
其中第10行,如果我们通过ir来改变val的值,编译时会出错。但是我们仍然可以通过val直接改变其值(第9行)
总结:const引用只是表明,保证不会通过此引用间接的改变被引用的对象!
另外,const既可以放到类型前又可以放到类型后面,放类型后比较容易理解:
string const *t1;
const string *t1;
typedef string* pstring;string s;
const pstring cstr1 = &s;就出错了
但是放在类型后面不会出错:
pstring const cstr2 = &s;
编辑本段引用在类中的使用
1. #include 2. using namespace std; 3. 4. class A 5. { 6. public: 7. A(int i=3):m_i(i){} 8. void print() 9. { 10. cout<<"m_i="< 12. private: 13. int m_i; 14. }; 15. 16. class B 17. { 18. public: 19. B(){} 20. B(A& a):m_a(a){} 21. void display() 22. { 23. m_a.print(); 24. } 25. private: 26. A& m_a; 27. }; 28. 29. 30. int main(int argc,char** argv) 31. { 32. A a(5); 33. B b(a); 34. b.display(); 35. return 0; 36. } 其中,要注意的地方就是引用类型的成员变量的初始化问题,它不能直接在构造函数里初始化,必须用到初始化列表,且形参也必须是引用类型。 凡是有引用类型的成员变量的类,不能有缺省构造函数。原因是引用类型的成员变量必须在类构造时进行初始化。 如果两个类要对第三个类的数据进行共享处理,可以考虑把第三个类作为这两个类的引用类型的成员变量 2,java中为什么实例方法可以调用实例变量也可以调用类变量,而类方法只能调用类变量 java 中为什么实例方法可以调用实例变量也可以调用类变量,而类方法只能调用类变量 悬赏分:20 | 解决时间:2008-1-14 15:02 | 提问者:jy00271436 顺便再告知道下实例方法可以调用实例方法和该类的类方法,而类中的类方法却只能调用该类的方法,另外可以互相调用不是一个类的方法吗,可以的话应该怎么样操作 谢谢 问题补充: 我的意思是CLASS A中的的方法可以调用CLASS B中的方法吗,如果可以的话,程序应该怎么写呢,还有实例变量的初始化就是为对象分配内存吧,实例方法的初始化就是在方法中写如成员变量,是这样吗,我是初学者,希望耐心指导,谢谢 最佳答案 实例方法随着实例的产生而产生,随着实例的消亡而消亡。 并且实例方法是存储在内存中的堆中的,每一个实例,就在内存中存在一个该方法的副本 类方法是static的,和实例没有关系,存储在栈中,多个实例共享一个类方法。 类如果直接调用方法,由于在内存中没有初始化,内存中不存在实例方法,所以类不能调用实例方法。 对于补充的回答: class A调用class B class A{ public void funA(){} } class B{ public void funB(){ A a=new A(); a.funA();//调用A的方法 } } 方法的初始化的时候,程序自动会给方法分配内存,不用像成员变量那样还要赋初值。所以方法初始化,楼主可以不用管。呵呵 分享给你的朋友吧: ∙人人网 ∙新浪微博 ∙开心网 ∙MSN ∙QQ空间 对我有帮助 4static final和final和static的区别 1)final 修饰的变量都不能再改变,要么在声明的时候初始化,要么在构造函数中初始化。 static final 加上静态修饰符,这个变量就属于类,而不是某个对象。 2)static 关键字是表示只有一份,final表示生命的变量的“引用”在内存中不能改变:如过是基本类型的变量(在栈中分配,那就是不可变的), 如过是对象,那么你还是可以在引用所指的堆中改变对象的实质的。 如果你已经将一个变量声明为final的,即不可变,而且每创建一个对象多要初始化一个此变量,也没有什么实质的意义那么通常情况下还不如声明 为static final,那样,就只有一份不可变的,降低了性能的开销,优化了设计 3)首先要改正一个错误: 用Final修饰变量即是常量,所以凡是用Final修饰的都是常量, 没有Final的变量之说. Final修饰的常量和static Final修饰的常量都存放在内存中的data segment区. 并且它们都是不可改变的. 它们的区别: 用Final修饰的常量要访问时,需要创建一个对象, 而用static Final修饰的常量要访问时不需要创建对象,直接用类名.+常量。 深层原因:当类被类装载器装到内存时,static Final常量首先被初始化,并且被所有对象共享,这样就大大减少了空间和 时间。 而Final常量只有创建对象时才能访问,而且每创建一个对象,就会为这个Final常量分配一个空间。 另外,Final 和 static Final 各有长处,要根据需要选择哪种方式。 5讨论Java中的内部类和匿名类 2007-12-27 10:43 作者:执木 来源:赛迪网 [摘要] 提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比。 [关键字] Java 内部类 匿名类 内部类:一个内部类的定义是定义在另一个内部的类。 原因是: 1.一个内部类的对象能够访问创建它的对象的实现,包括私有数据。 2.对于同一个包中的其他类来说,内部类能够隐藏起来。 3.匿名内部类可以很方便的定义回调。 4.使用内部类可以非常方便的编写事件驱动程序。 提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比。内部类从表面上看,就是在类中又定义了一个类(下文会看到,内部类可以在很多地方定义),而实际上并没有那么简单,乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦。学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构。下面从以下几个方面来介绍: * 第一次见面 public interface Contents { int value(); } public interface Destination { String readLabel(); } public class Goods { private class Content implements Contents { private int i = 11; public int value() { return i; } } protected class GDestination implements Destination { private String label; private GDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } public Destination dest(String s) { return new GDestination(s); } public Contents cont() { return new Content(); } } class TestGoods { public static void main(String[] args) { Goods p = new Goods(); Contents c = p.cont(); Destination d = p.dest("Beijing"); } } 在这个例子里类Content和GDestination被定义在了类Goods内部,并且分别有着protected和private修饰符来控制访问级别。Content代表着Goods的内容,而GDestination代表着Goods的目的地。它们分别实现了两个接口Content和 Destination。在后面的main方法里,直接用 Contents c和Destination d进行操作,你甚至连这两个内部类的名字都没有看见!这样,内部类的第一个好处就体现出来了隐藏你不想让别人知道的操作,也即封装性。 同时,我们也发现了在外部类作用范围之外得到内部类对象的第一个方法,那就是利用其外部类的方法创建并返回。上例中的cont()和dest()方法就是这么做的。那么还有没有别的方法呢?当然有,其语法格式如下: outerObject=new outerClass(Constructor Parameters); outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters); 注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象。至于原因,也就引出了我们下一个话题 * 非静态内部类对象有着指向其外部类对象的引用 对刚才的例子稍作修改: public class Goods { private valueRate=2; private class Content implements Contents { private int i = 11*valueRate; public int value() { return i; } } protected class GDestination implements Destination { private String label; private GDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } public Destination dest(String s) { return new GDestination(s); } public Contents cont() { return new Content(); } } 修改的部分用蓝色显示了。在这里我们给Goods类增加了一个private成员变量valueRate,意义是货物的价值系数,在内部类Content的方法value()计算价值时把它乘上。我们发现,value()可以访问valueRate,这也是内部类的第二个好处一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。 Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因 有人会问,如果内部类里的一个成员变量与外部类的一个成员变量同名,也即外部类的同名成员变量被屏蔽了,怎么办?没事,Java里用如下格式表达外部类的引用: outerClass.this 有了它,我们就不怕这种屏蔽的情况了。 * 静态内部类 和普通的类一样,内部类也可以有静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部的引用。这实际上和C++中的嵌套类很相像了,Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用这一点上,当然从设计的角度以及以它一些细节来讲还有区别。 除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。 * 局部内部类 是的,Java内部类也可以是局部的,它可以定义在一个方法甚至一个代码块之内。 public class Goods1 { public Destination dest(String s) { class GDestination implements Destination { private String label; private GDestination(String whereTo) { label = whereTo; } public String readLabel() { return label; } } return new GDestination(s); } public static void main(String[] args) { Goods1 g= new Goods1(); Destination d = g.dest("Beijing"); } } 上面就是这样一个例子。在方法dest中我们定义了一个内部类,最后由这个方法返回这个内部类的对象。如果我们在用一个内部类的时候仅需要创建它的一个对象并创给外部,就可以这样做。当然,定义在方法中的内部类可以使设计多样化,用途绝不仅仅在这一点。 下面有一个更怪的例子: public class Goods2{ 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) { Goods2 g= new Goods2(); g.track(); } } 你不能在if之外创建这个内部类的对象,因为这已经超出了它的作用域。不过在编译的时候,内部类TrackingSlip和其他类一样同时被编译,只不过它由它自己的作用域,超出了这个范围就无效,除此之外它和其他内部类并没有区别。 * 匿名内部类 java的匿名内部类的语法规则看上去有些古怪,不过如同匿名数组一样,当你只需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚。它的语法规则是这样的: new interfacename(){......}; 或 new superclassname(){......}; 下面接着前面继续举例子: public class Goods3 { public Contents cont(){ return new Contents(){ private int i = 11; public int value() { return i; } }; } } 这里方法cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去的确十分简洁。 在java的事件处理的匿名适配器中,匿名内部类被大量的使用。例如在想关闭窗口时加上这样一句代码: frame.addWindowListener(new WindowAdapter(){ public void windowClosing(WindowEvent e){ System.exit(0); } }); 有一点需要注意的是,匿名内部类由于没有名字,所以它没有构造函数(但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容)。如果你想要初始化它的成员变量,有下面几种方法: 1. 如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。 2. 将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。 3. 在这个匿名内部类中使用初始化代码块。 * 为什么需要内部类? java内部类有什么好处?为什么需要内部类? 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。 不过你可能要质疑,更改一下方法的不就行了吗? 的确,以此作为设计内部类的理由,实在没有说服力。 真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。 6,内部类的四种情况: JAVA中局部内部类和匿名内部类的特点和作用?最好能详细说明,谢谢各位了。 悬赏分:20 | 解决时间:2010-8-29 08:37 | 提问者:she2lh 最佳答案 Java 内部类 分四种:成员内部类、局部内部类、静态内部类和匿名内部类。 1、成员内部类: 即作为外部类的一个成员存在,与外部类的属性、方法并列。 注意:成员内部类中不能定义静态变量,但可以访问外部类的所有成员。 public class Outer{ private static int i = 1; private int j=10; private int k=20; public static void outer_f1(){ //do more something } public void out_f2(){ //do more something } //成员内部类 class Inner{ //static int inner_i =100; //内部类中不允许定义静态变量 int j=100;//内部类中外部类的实例变量可以共存 int inner_i=1; void inner_f1(){ System.out.println(i);//外部类的变量如果和内部类的变量没有同名的,则可以直接用变量名访问外部类的变量 System.out.println(j);//在内部类中访问内部类自己的变量直接用变量名 System.out.println(this.j);//也可以在内部类中用"this.变量名"来访问内部类变量 //访问外部类中与内部类同名的实例变量可用"外部类名.this.变量名"。 System.out.println(k);//外部类的变量如果和内部类的变量没有同名的,则可以直接用变量名访问外部类的变量 outer_f1(); outer_f2(); } } //外部类的非静态方法访问成员内部类 public void outer_f3(){ Inner inner = new Inner(); inner.inner_f1(); } //外部类的静态方法访问成员内部类,与在外部类外部访问成员内部类一样 public static void outer_f4(){ //step1 建立外部类对象 Outer out = new Outer(); //***step2 根据外部类对象建立内部类对象*** Inner inner=out.new Inner(); //step3 访问内部类的方法 inner.inner_f1(); } public static void main(String[] args){ outer_f4(); } } 成员内部类的优点: ⑴ 内部类作为外部类的成员,可以访问外部类的私有成员或属性。(即使将外部类声明为PRIVATE,但是对于处于其内部的内部类还是可见的。) ⑵ 用内部类定义在外部类中不可访问的属性。这样就在外部类中实现了比外部类的private还要小的访问权限。 注意:内部类是一个编译时的概念,一旦编译成功,就会成为完全不同的两类。对于一个名为outer的外部类和其内部定义的名为inner的内部类。编译完成后出现outer.class和outer$inner.class两类。 2、局部内部类: 即在方法中定义的内部类,与局部变量类似,在局部内部类前不加修饰符public或private,其范围为定义它的代码块。 注意:局部内部类中不可定义静态变量,可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的。 public class Outer { private int s = 100; private int out_i = 1; public void f(final int k){ final int s = 200; int i = 1; final int j = 10; class Inner{ //定义在方法内部 int s = 300;//可以定义与外部类同名的变量 //static int m = 20;//不可以定义静态变量 Inner(int k){ inner_f(k); } int inner_i = 100; void inner_f(int k){ System.out.println(out_i);//如果内部类没有与外部类同名的变量,在内部类中可以直接访问外部类的实例变量 System.out.println(k);//*****可以访问外部类的局部变量(即方法内的变量),但是变量必须是final的***** // System.out.println(i); System.out.println(s);//如果内部类中有与外部类同名的变量,直接用变量名访问的是内部类的变量 System.out.println(this.s);//用"this.变量名" 访问的也是内部类变量 System.out.println(Outer.this.s);//用外部"外部类类名.this.变量名" 访问的是外部类变量 } } new Inner(k); } public static void main(String[] args) { //访问局部内部类必须先有外部类对象 Outer out = new Outer(); out.f(3); } } 注意: 在类外不可直接生成局部内部类(保证局部内部类对外是不可见的)。要想使用局部内部类时需要生成对象,对象调用方法,在方法中才能调用其局部内部类。通过内部类和接口达到一个强制的弱耦合,用局部内部类来实现接口,并在方法中返回接口类型,使局部内部类不可见,屏蔽实现类的可见性。 3、静态内部类: 静态内部类定义在类中,任何方法外,用static定义。 注意:静态内部类中可以定义静态或者非静态的成员 public class Outer { private static int i = 1; private int j = 10; public static void outer_f1(){ } public void outer_f2(){ } // 静态内部类可以用public,protected,private修饰 // 静态内部类中可以定义静态或者非静态的成员 static class Inner{ static int inner_i = 100; int inner_j = 200; static void inner_f1(){ System.out.println("Outer.i"+i);//静态内部类只能访问外部类的静态成员 outer_f1();//包括静态变量和静态方法 } void inner_f2(){ // System.out.println("Outer.i"+j);//静态内部类不能访问外部类的非静态成员 // outer_f2();//包括非静态变量和非静态方法 } } public void outer_f3(){ // 外部类访问内部类的静态成员:内部类.静态成员 System.out.println(Inner.inner_i); Inner.inner_f1(); // 外部类访问内部类的非静态成员:实例化内部类即可 Inner inner = new Inner(); inner.inner_f2(); } public static void main(String[] args) { new Outer().outer_f3(); } } 注意:*******生成(new)一个静态内部类不需要外部类成员:这是静态内部类和成员内部类的区别。静态内部类的对象可以直接生成: Outer.Inner in=new Outer.Inner(); 而不需要通过生成外部类对象来生成。这样实际上使静态内部类成为了一个顶级类。静态内部类不可用private来进行定义。******* 例子: 对于两个类,拥有相同的方法: class People { run(); } class Machine{ run(); } 此时有一个robot类: class Robot extends People implement Machine. 此时run()不可直接实现。 注意:当类与接口(或者是接口与接口)发生方法命名冲突的时候,此时必须使用内部类来实现。用接口不能完全地实现多继承,用接口配合内部类才能实现真正的多继承。 4、匿名内部类 匿名内部类是一种特殊的局部内部类,它是通过匿名类实现接口。 IA被定义为接口。 IA I=new IA(){}; 匿名内部类的特点: 1,一个类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的事先或是覆盖。 2,只是为了获得一个对象实例,不需要知道其实际类型。 3,类名没有意义,也就是不需要使用到。 public class Outer { private static int i = 1; private int j = 10; public static void outer_f1(){ } public void outer_f2(){ } // 静态内部类可以用public,protected,private修饰 // 静态内部类中可以定义静态或者非静态的成员 static class Inner{ static int inner_i = 100; int inner_j = 200; static void inner_f1(){ System.out.println("Outer.i"+i);//静态内部类只能访问外部类的静态成员 outer_f1();//包括静态变量和静态方法 } void inner_f2(){ // System.out.println("Outer.i"+j);//静态内部类不能访问外部类的非静态成员 // outer_f2();//包括非静态变量和非静态方法 } } public void outer_f3(){ // 外部类访问内部类的静态成员:内部类.静态成员 System.out.println(Inner.inner_i); Inner.inner_f1(); // 外部类访问内部类的非静态成员:实例化内部类即可 Inner inner = new Inner(); inner.inner_f2(); } public static void main(String[] args) { new Outer().outer_f3(); } } 注:一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类,没有类名,根据多态,我们使用其父类名。因他是局部内部类,那么局部内部类的所有都对其生效。匿名内部类是唯一一种无构造方法类。大部分匿名内部类是用于接口回调用的。匿名内部类在编译的时候由系统自动起名Out$1.class。如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。因匿名内部类无构造方法,所以其使用范围非常的有限。当需要多个对象时使用局部内部类,因此局部内部类的应用相对比较多。匿名内部类中不能定义构造方法。如果一个对象编译时的类型是接口,那么其运行的类型为实现这个接口的类。 ________________________________________________________________________________ 内部类总结: 1.首先,把内部类作为外部类的一个特殊的成员来看待,因此它有类成员的封闭等级:private ,protected,默认(friendly),public 它有类成员的修饰符: static,final,abstract 2.非静态内部类nested inner class,内部类隐含有一个外部类的指针this,因此,它可以访问外部类的一切资源(当然包括private) 外部类访问内部类的成员,先要取得内部类的对象,并且取决于内部类成员的封装等级。 非静态内部类不能包含任何static成员. 3.静态内部类:static inner class,不再包含外部类的this指针,并且在外部类装载时初始化. 静态内部类能包含static或非static成员. 静态内部类只能访问外部类static成员. 外部类访问静态内部类的成员,循一般类法规。对于static成员,用类名.成员即可访问,对于非static成员,只能 用对象.成员进行访问 4.对于方法中的内部类或块中内部类只能访问块中或方法中的final变量。 类成员有两种static , non-static,同样内部类也有这两种 non-static 内部类的实例,必须在外部类的方法中创建或通过外部类的实例来创建(OuterClassInstanceName.new innerClassName(ConstructorParameter)),并且可直接访问外部类的信息,外部类对象可通过OuterClassName.this来引用 static 内部类的实例, 直接创建即可,没有对外部类实例的引用。 内部类不管static还是non-static都有对外部类的引用 non-static 内部类不允许有static成员 方法中的内部类只允许访问方法中的final局部变量和方法的final参数列表,所以说方法中的内部类和内部类没什麽区别。但方法中的内部类不能在方法以外访问,方法中不可以有static内部类 匿名内部类如果继承自接口,必须实现指定接口的方法,且无参数 匿名内部类如果继承自类,参数必须按父类的构造函数的参数传递