JAVA 第二天 内部类

package com.company;

/**
 * Created by Administrator on 2016/8/23.
 */
public class Outter {//生成的字节码文件是Outter.class
    /**
     * 嵌套的概念
     * 类中除了变量和方法之外,还可以定义一个类
     * 这个类就是内部类,就是嵌套
     *
     * 调用内部类 需要创建内部类的对象
     * */
    private int a=1;     //内部类可以调用外部类的成员,外部类不可以调用内部类的成员。
    private int b=1;
    public void a(){
        System.out.println("外部类a方法");
    }

    class Inner{//生成的字节码文件Outter$Inner.class
        //内部类中的成员与外部类的成员同名的话,则采用就近原则,使用内部类的成员。
        int b=2;
        public void b(){
            int b=3;
            System.out.println("内部类b方法,调用外部类的变量a="+a + "\n内部类调用外部类的a方法:");
            a();
            //如果要调用外部类中与内部类中重名的成员则采用
            System.out.println("外部类中的b="+Outter.this.b);
            System.out.println("内部类中的b="+this.b);
            System.out.println("函数中的b="+b);
        }
    }
}
package com.company;
/**
 * 同一个包下面,普通类创建对象市可以直接调用
 * 但是内部类就需要使用import引入
 * */

//import com.company.Outter.Inner;

public class Main {
    public static void main(String[] args)
    {
        Outter outter=new Outter();
        outter.a();
        /*
        * 不可以通过外部类对象去调用内部类中的变量和方法。
        *
        * 创建内部类对象的错误写法:
        *   Inner a=new Inner(); //错误的写法
        *   没有父类,就没有子类。
        *   同样没有外部类的对象,就不能创建内部类的对象
        *
        * 创建内部类对象的正确方法:
        *     通过外部类的对象创建内部类的对象
        *     写法一:
        *       Outter.Inner b=outter.new Inner();//正确的写法
        *     写法二:
        *       Outter.Inner b=new Outter().new Inner();//正确的写法   匿名的概念
        *       通过这种方式创建的外部类对象没有引用,是不能使用外部类里面的变量和方法
        *
        * */
        Outter.Inner b=new Outter().new Inner();
        b.b();
    }
}

运行效果:

外部类a方法
内部类b方法,调用外部类的变量a=1
内部类调用外部类的a方法:
外部类a方法
外部类中的b=1
内部类中的b=2
函数中的b=3

Process finished with exit code 0

匿名内部类


package com.company;

/**
 * Created by Administrator on 2016/8/23.
 */
public abstract class Computer {
    /**
     * 抽象类不能够创建出抽象类的对象
     * */
    public abstract void Internet();
    public abstract void WatchTV();
}
package com.company;
/**
 * 同一个包下面,普通类创建对象市可以直接调用
 * 但是内部类就需要使用import引入
 * */

//import com.company.Outter.Inner;

public class Main {
    public static void main(String[] args)
    {
        /**
         * 内名内部类
         * 这个下面其实是有一个类存在的,但是我们却看不见类的任何影子 没有名字,也看不到class关键字
         * 这个类没有名字,是一个一次性的
         * 证据就是在编译后的目录中会发现多出来一个名为Main$1.class 这个是系统为它命名的
         * 相当于创建出了一个匿名的内部类,继承了抽象类Computer并且实现了抽象类的抽象方法。
         * 我们创建出的是抽象类的子类的对象
         * */
        Computer computer=new Computer() {
            /**
             * 不能够创建出抽象类对象的说法是正确的
             * 这里是匿名的概念
             * 内名内部类
             * */
            @Override
            public void Internet() {
                System.out.println("我是Computer的子类,我可以上网");
            }

            @Override
            public void WatchTV() {
                System.out.println("我是Computer的子类,我可以看电视");
            }
        };
        computer.Internet();
        computer.WatchTV();
    }
}

执行结果:

我是Computer的子类,我可以上网
我是Computer的子类,我可以看电视

Process finished with exit code 0

提起Java内部类(Inner Class)可能很多人不太熟悉,实际上类似的概念在C++里也有,那就是嵌套类(Nested Class),关于这两者的区别与联系,在下文中会有对比。内部类从表面上看,
就是在类中又定义了一个类(下文会看到,内部类可以在很多地方定义),而实际上并没有那么简单,乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,
但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦。学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构。
下面从以下几个方面来介绍:
第一次见面

[java] view plain copy

  1. public interface Contents {
  2. int value();
  3. }
  4. public interface Destination {
  5. String readLabel();
  6. }
  7. public class Goods {
  8. private class Content implements Contents {
  9. private int i = 11;
  10. public int value() {
  11. return i;
  12. }
  13. }
  14. protected class GDestination implements Destination {
  15. private String label;
  16. private GDestination(String whereTo) {
  17. label = whereTo;
  18. }
  19. public String readLabel() {
  20. return label;
  21. }
  22. }
  23. public Destination dest(String s) {
  24. return new GDestination(s);
  25. }
  26. public Contents cont() {
  27. return new Content();
  28. }
  29. }
  30. class TestGoods {
  31. public static void main(String[] args) {
  32. Goods p = new Goods();
  33. Contents c = p.cont();
  34. Destination d = p.dest("Beijing");
  35. }
  36. }

在这个例子里类Content和GDestination被定义在了类Goods内部,并且分别有着protected和private修饰符来控制访问级别。Content代表着Goods的内容,而GDestination代表着Goods的目的地。它们分别实现了两个接口Content和Destination。在后面的main方法里,直接用 Contents c和Destination d进行操作,你甚至连这两个内部类的名字都没有看见!这样,内部类的第一个好处就体现出来了 隐藏你不想让别人知道的操作,也即封装性。同时,我们也发现了在外部类作用范围之外得到内部类对象的第一个方法,那就是利用其外部类的方法创建并返回。
上例中的cont()和dest()方法就是这么做的。那么还有没有别的方法呢?当然有,其语法格式如下:

[java] view plain copy

  1. outerObject=new outerClass(Constructor Parameters);
  2. outerClass.innerClass innerObject=outerObject.new InnerClass(Constructor Parameters);

注意在创建非静态内部类对象时,一定要先创建起相应的外部类对象。至于原因,也就引出了我们下一个话题 非静态内部类对象有着指向其外部类对象的引用,对刚才的例子稍作修改:

[java] view plain copy

  1. public class Goods {
  2. private valueRate = 2;
  3. private class Content implements Contents {
  4. private int i = 11 * valueRate;
  5. public int value() {
  6. return i;
  7. }
  8. }
  9. protected class GDestination implements Destination {
  10. private String label;
  11. private GDestination(String whereTo) {
  12. label = whereTo;
  13. }
  14. public String readLabel() {
  15. return label;
  16. }
  17. }
  18. public Destination dest(String s) {
  19. return new GDestination(s);
  20. }
  21. public Contents cont() {
  22. return new Content();
  23. }
  24. }

修改的部分用蓝色显示了。在这里我们给Goods类增加了一个private成员变量valueRate,意义是货物的价值系数,在内部类Content的方法value()计算价值时把它乘上。
我们发现,value()可以访问valueRate,这也是内部类的第二个好处 一个内部类对象可以访问创建它的外部类对象的内容,甚至包括私有变量!
这是一个非常有用的特性,为我们在设计时提供了更多的思路和捷径。要想实现这个功能,内部类对象就必须有指向外部类对象的引用。
Java编译器在创建内部类对象时,隐式的把其外部类对象的引用也传了进去并一直保存着。
这样就使得内部类对象始终可以访问其外部类对象,同时这也是为什么在外部类作用范围之外向要创建内部类对象必须先创建其外部类对象的原因。
有人会问,如果内部类里的一个成员变量与外部类的一个成员变量同名,也即外部类的同名成员变量被屏蔽了,怎么办?没事,Java里用如下格式表达外部类的引用:
outerClass.this 
有了它,我们就不怕这种屏蔽的情况了。
静态内部类
和普通的类一样,内部类也可以有静态的。不过和非静态内部类相比,区别就在于静态内部类没有了指向外部的引用。这实际上和C++中的嵌套类很相像了,Java内部类与C++嵌套类最大的不同就在于是否有指向外部的引用这一点上,当然从设计的角度以及以它一些细节来讲还有区别。
除此之外,在任何非静态内部类中,都不能有静态数据,静态方法或者又一个静态内部类(内部类的嵌套可以不止一层)。
不过静态内部类中却可以拥有这一切。这也算是两者的第二个区别吧。
局部内部类 
是的,Java内部类也可以是局部的,它可以定义在一个方法甚至一个代码块之内。

[java] view plain copy

  1. public class Goods1 {
  2. public Destination dest(String s) {
  3. class GDestination implements Destination {
  4. private String label;
  5. private GDestination(String whereTo) {
  6. label = whereTo;
  7. }
  8. public String readLabel() {
  9. return label;
  10. }
  11. }
  12. return new GDestination(s);
  13. }
  14. public static void main(String[] args) {
  15. Goods1 g = new Goods1();
  16. Destination d = g.dest("Beijing");
  17. }
  18. }

上面就是这样一个例子。在方法dest中我们定义了一个内部类,最后由这个方法返回这个内部类的对象。如果我们在用一个内部类的时候仅需要创建它的一个对象并创给外部,就可以这样做。当然,定义在方法中的内部类可以使设计多样化,用途绝不仅仅在这一点。
下面有一个更怪的例子:

[java] view plain copy

  1. public class Goods2 {
  2. private void internalTracking(boolean b) {
  3. if (b) {
  4. class TrackingSlip {
  5. private String id;
  6. TrackingSlip(String s) {
  7. id = s;
  8. }
  9. String getSlip() {
  10. return id;
  11. }
  12. }
  13. TrackingSlip ts = new TrackingSlip("slip");
  14. String s = ts.getSlip();
  15. }
  16. }
  17. public void track() {
  18. internalTracking(true);
  19. }
  20. public static void main(String[] args) {
  21. Goods2 g = new Goods2();
  22. g.track();
  23. }
  24. }

你不能在if之外创建这个内部类的对象,因为这已经超出了它的作用域。不过在编译的时候,内部类TrackingSlip和其他类一样同时被编译,只不过它由它自己的作用域,超出了这个范围就无效,除此之外它和其他内部类并没有区别。
匿名内部类 
java的匿名内部类的语法规则看上去有些古怪,不过如同匿名数组一样,当你只需要创建一个类的对象而且用不上它的名字时,使用内部类可以使代码看上去简洁清楚。它的语法规则是这样的:
new interfacename(){......}; 或 new superclassname(){......}; 
下面接着前面继续举例子:

[java] view plain copy

  1. public class Goods3 {
  2. public Contents cont() {
  3. return new Contents() {
  4. private int i = 11;
  5. public int value() {
  6. return i;
  7. }
  8. };
  9. }
  10. }

这里方法cont()使用匿名内部类直接返回了一个实现了接口Contents的类的对象,看上去的确十分简洁。
在java的事件处理的匿名适配器中,匿名内部类被大量的使用。例如在想关闭窗口时加上这样一句代码:

[java] view plain copy

  1. frame.addWindowListener(new WindowAdapter(){
  2. public void windowClosing(WindowEvent e){
  3. System.exit(0);
  4. }
  5. });

有一点需要注意的是,匿名内部类由于没有名字,所以它没有构造函数(但是如果这个匿名内部类继承了一个只含有带参数构造函数的父类,创建它的时候必须带上这些参数,并在实现的过程中使用super关键字调用相应的内容)。如果你想要初始化它的成员变量,有下面几种方法:
如果是在一个方法的匿名内部类,可以利用这个方法传进你想要的参数,不过记住,这些参数必须被声明为final。
将匿名内部类改造成有名字的局部内部类,这样它就可以拥有构造函数了。 
在这个匿名内部类中使用初始化代码块。 
为什么需要内部类? 
java内部类有什么好处?为什么需要内部类?
首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口。由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能。
不过你可能要质疑,更改一下方法的不就行了吗?
的确,以此作为设计内部类的理由,实在没有说服力。
真正的原因是这样的,java中的内部类和接口加在一起,可以的解决常被C++程序员抱怨java中存在的一个问题 没有多继承。实际上,C++的多继承设计起来很复杂,而java通过内部类加上接口,可以很好的实现多继承的效果。

时间: 2024-10-06 16:28:04

JAVA 第二天 内部类的相关文章

【转 Java 中的内部类和匿名类

 Java 中的内部类和匿名类 2008-10-16 13:47:41 标签:Java 内部类 匿名类 休闲 职场 Java 中的内部类和匿名类* 为什么需要内部类? Java 内部类有什么好处?为什么需要内部类? 首先举一个简单的例子,如果你想实现一个接口,但是这个接口中的一个方法和你构想的这个类中的一个方法的名称,参数相同,你应该怎么办?这时候,你可以建一个内部类实现这个接口.由于内部类对外部类的所有内容都是可访问的,所以这样做可以完成所有你直接实现这个接口的功能. 不过你可能要质疑,更改一

【转】Java中的内部类和匿名类

Java内部类(Inner Class),类似的概念在C++里也有,那就是嵌套类(Nested Class),乍看上去内部类似乎有些多余,它的用处对于初学者来说可能并不是那么显著,但是随着对它的深入了解,你会发现Java的设计者在内部类身上的确是用心良苦.学会使用内部类,是掌握Java高级编程的一部分,它可以让你更优雅地设计你的程序结构.下面从以下几个方面来介绍: 第一次见面 public interface Contents {    int value();} public interfac

学习Java第二周

这是学习java的第二周,又这样不知不觉的结束了 上周想要学习的这一周也都做到了,可是觉得进度有些慢了,学习了: 1. 接口和抽象类: 2. 集合与数组: 3. 方法的定义: 4. 递归算法: 5.对象和数据管理: 跟着视频教程学习并测试了视频上的代码,测试代码期间不乏这里哪里的小问题,是不熟练和不细心导致的,要赶快熟悉java编程的方式,多实践.下一周要学习的内容是: 包装类 数字处理类 Object类 Java类包 内部类 原文地址:https://www.cnblogs.com/ywqtr

Java 第二章 变量 、数据类型和运算符 笔记

Java 第二章 变量 .数据类型和运算符 一.变量:存储数据的一个基本单元. 二.变量的声明和赋值: 1)声明并赋值:数据类型 变量名=值;      例:int  price=1000; 2)声明.赋值分两步:数据类型 变量名;   例: int  price; 变量名=值;              price=1000; 三.数据类型2种: 1)基本数据类型8种: Byte 长度:-128~127(-2的7次方到2的7次方减1) Short   -2的15次方到2的15次方减1 Int

Java中的内部类(成员内部类、静态内部类、局部内部类、匿名内部类)

Java中的内部类(成员内部类.静态内部类.局部内部类.匿名内部类) 神话丿小王子的博客主页 我们先看这样一段话:人是由大脑.肢体.器官等身体结果组成.而组成我们人体的心脏它也有自己的属性和行为(血液.跳动),显然,此处不能单方面用属性或者方法表示一个心脏了,而需要一个类,但是这个类要依赖于人这个类存在(因为心脏不能脱离人体而存活,当然不考虑现今社会的发达科技,只从正常情况下来说),所心脏以需要写在人类的内部.内部类就相当于其中的某个器官之一. 首先看看什么是内部类:在类的内部定义另一个类.没错

自学java 第十章内部类(一)

今天学习了一部分java中的内部类. 内部类指将一个类的定义放在另一个类的内部,那它就是一个内部类. 指明一个引用时内部类的类型可以通过"外部类名.内部类名"的写法声明,如果想返回一个内部类的对象可以通过在外部类中写一个返回该内部类的方法或者通过"外部类对象.new 内部类名()"的写法返回内部类对象. 内部类拥有对外部类所有元素的访问权,可以直接访问:而外部类则需要先创建一个内部类的对象,通过这个对象可以访问内部类中的任意成员. 内部类也可以继承类或实现接口,因此

java 四种内部类的学习

内部类 定义在外部类的内部, 编译后是独立存在的类 可以访问外部类的私有成员,且不破坏封装 成员内部类 用"外部类类名.this"访问外部类的当前对象 创建对象:先创建外部类对象,再通过"外部类对象.new 内部类类名"创建内部类对象 静态内部类 只能访问外部类的静态成员 创建对象:直接用"new 外部类类名.内部类类名()" 局部内部类 定义在外部类的方法内部 作用范围:从定义开始到所在的代码块结束 同局部变量 不仅可以访问外部类的成员,还可以

java基础之 内部类

Java中的内部类共分为四种: 静态内部类static inner class (also called nested class) 成员内部类member inner class 局部内部类local inner class 匿名内部类anonymous inner class 静态内部类Static Inner Class 最简单的内部类形式. 类定义时加上static关键字. 不能和外部类有相同的名字. 被编译成一个完全独立的.class文件,名称为OuterClass$InnerClas

201671010117 2016-2017-2 《Java程序设计》Java第二周学习心得

Java第二周学习心得 这一周老师在周四进行了课堂测验,完全出乎我的意料,我以为老师会在前两周上课讲一下,由于我在课前没有好好准备,反转课堂来的有的措手不及,那些题很多很多都不会,也错了很多,班上有很多表现很好的同学,他们课前准备充分,在课堂上完全没有任何压力,我也意识到了我课前没有花大量时间看书的严重性,所以我下课便去看第三章了,以后也一定要好好看书,找出不懂得问题,课上也要认真向其他优秀同学学习,不懂的问题也要想办法解决. 今天写了PPT上的任务1-9,着实也遇到了很多不会的问题,像是最后的