黑马程序员技术交流社区
标题: 谁能帮我解释一下匿名内部类与内部类的区别? [打印本页]
作者: 曾林魁 时间: 2013-5-28 10:32
标题: 谁能帮我解释一下匿名内部类与内部类的区别?
本帖最后由 曾林魁 于 2013-5-30 12:22 编辑
这几天在学面向对象基础,里面的内部类访问规则不太懂,谁能解释一下吗?例如 Outer.Inner in = new Outer().newInner();
还有就是内部类与匿名内部类有什么区别?
我是菜鸟,谁帮我解释一下吧?我先谢谢了 !!
作者: 无妄无涯 时间: 2013-5-28 10:50
内部类中有一种定义在方法中的类叫局部内部类,匿名内部类是没有命名的一种局部内部类。
规则大体如下(是我在做一道基础测试题时总结的,可能不全面):- * 外部类实例与内部类的实例的之间为一对多关系。一个内部类实例只会引用一个外部类实例。
- * 而一个外部类实例对应零个或者多个内部类的实例。在外部类中不能直接访问内部类成员,
- * 必须通过内部类的实例访问。
- *
- * 实例内部类的实例自动持有外部类的实例的引用。
- * 在内部类中,可以直接访问外部类的所有成员。包括成员变量和成员方法。
- *
- * 一般的内部类(非static类)的内部没有静态属性。在实例内部类中不能定义静态成员,只能定义实例成员。
- *
- * 在多层嵌套中,内部类可以访问所有外部类的成员。内层内部类可以访问外层内部类。
- *
- * 局部内部类是在一个方法中定义的内部类,他的可见范围是当前的方法,局部内部类不能访问修饰符及修饰。
- *
- * 局部内部类和实例内部类一样,可以访问外部类的所有成员。
- * 局部内部类还可以访问所在方法中的final类型的参数和变量。
- * 在局部内部类和实例内部类一样,不能包含静态成员。
复制代码
作者: 小石头39910 时间: 2013-5-28 11:02
内部类:
1、访问特点:内部类可以直接访问外部类中的成员,包括私有。
2、外部类访问内部类时必须建立内部类的对象。
匿名内部类:
1、其实是内部类的简写格式,匿名内部类必须继承一个类或者实现接口。
区别:
内部类的访问格式是:Outer.Inner in=new Outer().new Inner();
匿名内部类的访问格式:new 父类或者接口(){定义子类内容}.方法();
匿名内部类对象一次只能调用一个方法。
匿名内部类时一个带内容的匿名子类对象。
作者: FantasticPie 时间: 2013-5-28 11:11
最好看看(传智播客毕向东Java基础视频教程-day09),毕竟知识不是三言两语告诉你你就能理解的,这是毕老师所有的java基础课程的下载地址:http://edu.csdn.net/news/2012821/83780387427c.shtml 。如果你已经下载了,就好好看看,想必就会了。
作者: SOAR 时间: 2013-5-28 11:15
匿名就是没名字呗。这个貌似用处不大,就是在写GUI程序的事件那部分有点用处。
作者: 王瀛 时间: 2013-5-28 12:10
以下内容均系手打,并非从网上Ctrl+C、Ctrl+V来的(我也刚学到这里)
从字面上理解,内部类就是定义在Outer类里面的类(Inner),是Outer类的一部分,所以Outer的成员变量和成员函数都可以被Inner直接调用,即便被private修饰也可以。但是如果想要调用被static修饰的成员,那么Inner本身也必须加上static。
Inner可以定义在Outer的成员位置上,这时根据类中成员的特点,Inner类可以被static等成员修饰符修饰;
Inner也能定义在Outer中方法的内部,这时Inner定义在局部,如果想要访问所在局部的局部变量,该变量必须被final修饰。
无论Inner定义在哪个位置,它都拥有对外部类的引用,即:Outer.this.
但是如果外部类想要访问内部类中的内容,就必须创建一个内部类的实例对象,因为类中的内容只有创建了对象才能被调用。(static情况除外)
Outer.Inner in = new Outer().newInner(); 这句我们类比一下Person p = new Person(); 并把它分解一下:
左边:Outer.Inner 是声明引用类型。类比一下Person p,Person声明了这是一个Person类类型的类引用,同理 Outer.Inner声明了这是一个Inner类类型的引用,但是有可能还同时存在另一个Outer02里面也定义了一个类名叫做Inner的内部类,所以加上Outer.用于区分。 "in"就是相当于p,就是给这个引用起了个名字。
右边:如果是new Person()就是创建一个实例化对象。但是,这里由于Inner是在Outer里面的,Outer是一个类,类中的成员是通过对象来调用(访问)的,所以如果想要访问到Inner类就需要创建Outer的实例化对象,即:new Outer() 。那么"new Outer()."就相当于对象调用的方式。访问到Inner类后,使用后面的new Inner()就是创建了一个Inner的实例化对象。
概括起来可以这样表示: Outer.Inner in = new Outer().new Inner() <===> 外部类名.内部类名 引用变量名 = 外部类对象.内部类对象
匿名就是隐藏起来了名字,也就是没有名字。换句话说,这个内部类很特殊,他没有名字。
没有名字我们怎么创建、使用、访问这个内部类呢?于是有了匿名内部类的前提:匿名内部类必须是继承(或者实现)父类(或者接口)。
这时内部类的父亲说了:既然你没有名字,就用我的吧。于是出现了:Fu f = new Inner(); (这里的Inner是假想出来的,为了便于表示,实际上是没有名字的)这就形成了父类的引用指向了子类的对象,也就是多态的体现。可以看到,匿名内部类其实不是“类”,而是一个子类的对象。
由于匿名内部类继承(实现)了父类(接口),所以必须复写父类(接口)的功能 ,并使用对象调用的方法调用复写的功能。
以毕老师视频中内部类练习为例说明一下(注释中的一、二、三是我根据楼主提的问题标注的,其他的是毕老师的,看视频都有的)- interface Inter//接口
- {
- void method();//接口中功能,省略了public abstract修饰符
- }
- class Test
- {
- //补足代码。通过匿名内部类。
- /*
- static class Inner implements Inter
- {
- public void method()
- {
- System.out.println("method run");
- }
- }
- */
-
- static Inter function()//返回值类型是Inter类型的对象
- {
- return new Inter()//一、从new Inter(){}开始就是匿名内部类。可以看到在创建匿名内部类对象的时候使用的是接口名,并在"{}"中复写了接口对外提供的功能。而这个new Inter(){}整体作为一个对象存在,成为function()方法的返回值,注意返回值类型是Inter类类型的
- {
- public void method()
- {
- System.out.println("method run");
- }
- };
- }
- }
- class InnerClassTest
- {
- public static void main(String[] args)
- {
- //Test.function():Test类中有一个静态的方法function。
- //.method():function这个方法运算后的结果是一个对象。而且是一个Inter类型的对象。
- //因为只有是Inter类型的对象才可以调用method方法。
- Test.function().method();
- // Inter in = Test.function();
- // in.method();
-
- show(new Inter()//二、这里的new Inter(){}整体也是一个匿名内部类,道理请类比“一”中的解释
- {
- public void method()
- {
- System.out.println("method show run");
- }
- });
- }
- public static void show(Inter in)
- {
- in.method();
- }
- }
- class InnerTest
- {
- public static void main(String[] args)
- {
- new Object()//三、Object是所有类的直接、间接父类,所以也可以被匿名内部类继承。这里定义了父类中没有的特有方法,注意方法调用的书写方式
- {
- public void function()
- {
-
- }
- }.function();
- }
- }
复制代码 差不多就这些了。。。累死我了。。。吃饭去 =。=
作者: 不胖的胖子 时间: 2013-5-28 15:14
1,如何定义内部类
把一个类放在另一个类的内部即可
- public class Outer
- {
- class Inner
- {
- }
- }
复制代码 2,内部类的划分: 成员内部类: 非静态内部类
静态内部类
匿名内部类
局部内部类
成员内部类的意思是把这个类当做外部类的一个成员,等同于属性、方法、构造器的地位。
成员内部类是类成员,故可以同方法一样可以用public、protected、private修饰。
匿名内部类、局部内部类则不是类成员。
3,访问规则
非静态内部类可以访问外部类private成员。原因:在非静态内部类对象里,保存了一个它寄存的外部对象的引用。举例说明:
- public class Outer{
- private int x = 10;//外部类属性 x
- private int y = 100;//外部类属性 y
- public Outer(){
- System.out.println("Outer"+"-->"+x);
- }
- class Inner{
- private int x = 12;//内部类成员 x
- public Inner(){
- int x = 20; //内部类局部变量 x
- System.out.println("Inner"+"-->"+x);
- System.out.println("Inner"+"-->"+this.x);
- System.out.println("Inner"+"-->"+Outer.this.x);
- System.out.println(y);//当发生调用时,其实是有一个Outer.this引用
- }
- }
- public static void main(String args[]){
- new Outer().new Inner();
- }
- }
复制代码- ---------- 运行java程序 ----------
- Outer-->10
- Inner-->20
- Inner-->12
- Inner-->10
- 100
- 输出完成 (耗时 0 秒) - 正常终止
复制代码结论:
1,
当在非静态内部类的方法内访问某个变量时(以 y为例),系统优先在该方法内产值是否存该名字的局部
变量,如果存在该名字的局部变量,就使用该变量;如果不存在,则到该方法所在内部类中
查找是否存在该名字的属性,存在则使用该属性;不存在则到内部类所在的外部类中查找是
否存在该名字的数组,存在则使用。如果还是没找到,则编译报错。
2,当外部类属性、内部类属性与内部类方法的局部变量同名(如 x),则可以通过使用this
、外部类名.this来指定调用谁的x。当不指定时参考第一条
写在后面的
由于时间有限,还有很多细节没写。推荐一个本书《疯狂java讲义》第六章 面向对象 内部类。讲的很详细。就是给的程序太啰嗦。
我写的例子就是简单粗暴了点,主要是方便说明问题。
建议:
把继承 构造器 this super引用好好看懂。
作者: 归☆夜↑『 时间: 2013-5-28 16:47
对于非静态内部类可理解为外部类的一个实例成员,要使用它必须有一个外部类的实例对象 所以先new Outer(),再通过通过外部类实例调用内部类的构造器即new Outer().new Inner()
匿名内部类相当一次性筷子,只出现一次,用完就丢了,很难再在其他地方通过引用变量再使用,因为匿名类创建实例时都是直接new出来的,没有引用变量的定义。常见的是在GUI中使用匿名内部类充当监听器如:addXXXlistener(/*后面直接创建匿名内部类的实例*/ new XXXListenner({//*匿名内部类的类体,这里是抽象方法的实现*/
})/*一个匿名内部类对象创建完成,它的活动范围也仅限于此,不能再在其他地方使用*/);
作者: 赵崇友 时间: 2013-5-28 19:45
这时我写博客总结的内部类,很详细,楼主可以看看:
http://blog.sina.com.cn/s/blog_8f5022200101a7om.html
作者: 袁梦希 时间: 2013-5-30 10:46
楼主你好,如果帖子没问题了,那么请把帖子的类型改为“已解决”。如果不会改,请看我的个性签名
作者: 曾林魁 时间: 2013-5-30 12:14
袁梦希 发表于 2013-5-30 10:46
楼主你好,如果帖子没问题了,那么请把帖子的类型改为“已解决”。如果不会改,请看我的个性签名 ...
好的谢谢
欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) |
黑马程序员IT技术论坛 X3.2 |