java学习笔记9--内部类总结

java内部类分为: 非静态内部类、静态内部类、局部内部类、匿名内部类

内部类的共性:

(1)内部类仍然是一个独立的类,在编译之后内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号 。

(2)内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的 。

(3)内部类声明成静态的,就不能随便的访问外部类的成员变量了,此时内部类只能访问外部类的静态成员变量 。

java 中的内部类和接口加在一起,可以的解决常被 C++ 程序员抱怨 java 中存在的一个问题:没有多继承。实际上,C++ 的多继承设计起来很复杂,而 java 通过内部类加上接口,可以很好的实现多继承的效果。

非静态内部类

当一个类作为另一个类的非静态成员,则这个类就是一个非静态内部类。

创建非静态内部类是很容易的,只需要定义一个类让该类作为其他类的非静态成员。该非静态内部类和成员变量或者成员方法没有区别,同样可以在非静态内部类前面加可以修饰成员的修饰符。创建非静态内部类的基本语法如下所示:

class OutClass {
    class InClass {
        //内部类成员
    }
    //外部类成员
}

在内部类的程序中,是经常会进行外部类和内部类之间访问的。在外部类中访问内部类是很容易的,只要把内部类看成一个类,然后创建该类的对象,使用对象来调用内部类中的成员就可以了。

在外部类中访问内部类的程序--举个例子:

class OutClass {
    class InClass {    //创建非静态内部类
        int i = 5;    //内部类成员
    }
    public void fun() {    //外部类成员
        InClass in = new InClass();    //创建一个内部类对象
        int i = in.i;        //访问内部类成员
        System.out.println("InClass's var is: " + i);
    }
}
public class javatest {
    public static void main(String args[ ]) {
         OutClass out = new OutClass();
         out.fun();
   }
}

运行结果:

InClass's var is: 5

分析:在main方法中,首先创建一个外部类对象,然后访问外部类的成员方法。在外部类的成员方法中,创建了一个内部类对象,然后使用内部类对象调用内部类的成员变量,从而得到结果。编译该程序将产生三个class文件,分别是主类、外部类和内部类。内部类产生的class文件的名称为OutClass$InClass.class,在该名称中可以区分该内部类到底是哪一个类的内部类。

不但可以在外部类中访问内部类,还可以在外部类外访问内部类。在外部类外访问内部类的基本语法如下所示。

OutClass.InClass oi=new OutClass().new InClass();

使用该方法就能够创建一个内部类对象,使用该内部类对象就可以访问内部类的成员。该方法是不容易理解的,可以分为下面的两条语句:

Wai w=new Wai();

Wai.Nei wn=w.new Nei();

这样就很容易理解了。首先是创建一个外部类的对象,然后让该外部类对象调用创建一个内部类对象。 

在外部类外访问内部类的程序--举个例子:

class OutClass {
    class InClass {    //创建非静态内部类
        int i = 5;    //内部类成员
        int j = 6;
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass.InClass oi1 = new OutClass().new InClass();
        OutClass ocClass = new OutClass();
        OutClass.InClass oi2 = ocClass.new InClass();
        System.out.println("InClass's var i is: " + oi1.i);
        System.out.println("InClass's var j is: " + oi1.j);
   }
}

在示例代码中使用了两种方法来从外部类外访问内部类。在外部类外访问内部类时,是不能够直接创建内部类对象的,因为内部类只是外部类的一个成员。所以要想创建内部类对象,首先要创建外部类对象,然后以外部类对象为标识来创建内部类对象。 

在内部类中访问外部类

在内部类中访问外部类,就像所有的同一个类中成员互相访问一样,这样是没有限制的,包括将成员声明为private私有的。

举个例子:

class OutClass {
    int i = 8;    //外部类成员变量
    class InClass {    //创建非静态内部类
        public void fun() {
            System.out.println("OutClass's var is: " + i);
        }
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass oc = new OutClass();    //创建外部类对象
        OutClass.InClass oi = oc.new InClass();    //创建内部类对象
        oi.fun();    //调用内部类中的成员
   }
}

在示例代码中,在内部类中定义了一个fun来访问外部类中的成员变量i。可以看到从内部类中访问外部类是非常容易的,不需要添加任何内容,就像成员方法间调用一样。如果外部类中也有一个成员变量i,得到的是内部类成员变量的值。下面通过示例代码解决这个问题:

class OutClass {
    int i = 8;    //外部类成员变量
    class InClass {    //创建非静态内部类
        int i = 9;
        OutClass oc = new OutClass();
        public void fun() {    //内部类成员
            System.out.println("InClass's var is: " + i);
            System.out.println("OutClass's var is: " + oc.i);
        }
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass oc = new OutClass();    //创建外部类对象
        OutClass.InClass ic = oc.new InClass();    //创建内部类对象
        ic.fun();    //调用内部类中的成员
   }
}

在本程序中先定义了一个外部类的成员变量,接着定义了一个内部类的成员变量,这两个成员变量的名称是相同的。而在内部直接访问时,将访问的是内部类的成员变量。要想访问外部类成员变量,就需要首先创建一个外部类对象,然后使用该对象调用外部类成员变量。 

局部内部类

局部内部类的作用范围是和局部变量的作用范围相同的,只在局部中起作用,所以对局部内部类进行访问时,只能在该局部内部类的作用范围内。

举个例子:

class OutClass {
    public void fun() {
        class InClass {    //定义一个局部内部类
            int i = 5;    //局部内部类的成员变量
        }
        InClass ic = new InClass();
        System.out.println("InClass's var is: " + ic.i);
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass oc = new OutClass();
        oc.fun();
   }
}

在本程序中定义了一个局部内部类,并进行了对该局部内部类的访问。对该内部类进行访问必须在该内部类所在的方法中通过创建内部类对象来进行访问。这是因为这里的内部类是作为局部成员的形式出现的,只能在它所在的方法中进行调用。 

局部内部类中访问外部类成员变量

在局部内部类中访问外部类成员变量是很容易实现的,并不需要进行过多操作。在局部内部类中可以直接调用外部类的成员变量。

举个例子:

class OutClass {
    int i = 9;    //定义一个外部类的成员变量
    public void fun() {
        class InClass {    //定义一个局部内部类
            public void Infun() {
                System.out.println("OutClass's var is: " + i);    //访问外部类中的成员变量
            }
        }
        InClass ic = new InClass();    //创建内部类对象
        ic.Infun();    //调用内部类中的成员方法
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass oc = new OutClass();    //创建外部类对象
        oc.fun();    //调用内部类中的成员
   }
}

在示例代码中定义了一个局部内部类,在该局部内部类中定义了一个方法来访问外部类的成员变量。

在局部内部类中访问外部类的局部变量

和访问外部类的成员变量不同,在局部内部类中访问外部类中和局部内部类在同一局部的局部变量是不能够直接访问的。

举个例子(下面是一段错误的代码):

class OutClass {
    public void OutFun() {
        int i = 9;
        class InClass {
            public void InFun() {
                System.out.println("OutClass's var is: " + i);//访问外部类的成员变量
            }
        }
        InClass ic = new InClass();    //创建内部类对象
        ic.InFun();    //调用内部类中的成员方法
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass oc = new OutClass();    //创建外部类对象
        oc.OutFun();    //调用内部类中的成员
   }
}

运行产生异常:

Exception in thread "main" java.lang.Error: Unresolved compilation problem:
Cannot refer to a non-final variable i inside an inner class defined in a different method

运行该程序是会发生错误的,错误信息为“从内部类中访问局部变量i;需要被声明为最终类型”。在局部内部类中访问外部类的局部变量是不能够访问普通的局部变量的,必须将该局部变量声明为final。

静态方法中的局部内部类

局部内部类定义在非静态方法和静态方法中是不同的,在前面例子都是将局部内部类定义在非静态方法中,下面就来学习静态方法中定义局部内部类的情况。在静态方法中定义的局部内部类要想访问外部类中的成员,该成员必须是静态成员。

class OutClass {
    static int i = 4;
    public static void OutFun() {    //外部类成员
        class InClass {
            public void InFun() {
                System.out.println("OutClass's local var is: " + i);
            }
        }
        InClass ic = new InClass();
        ic.InFun();
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass.OutFun();
   }
}

静态内部类

前面已经学习了非静态内部类,接下来就来学习什么是静态内部类。静态内部类就是在外部类中扮演一个静态成员的角色。创建静态内部类的形式和创建
非静态内部类的形式很相似的,只是需要将该内部类使用static修饰成静态的形式。使用static修饰类,这在正常类中是不可能的。定义静态内部类的
语法如下所示:

class OutClass {
    static class InClass {
        //内部类成员
    }
    //外部类成员
}

在外部类中访问静态内部类

在外部类中访问静态内部类和在外部类中访问非静态内部类一样的,只需要从成员间访问的角度就可以考虑到这一点。举个例子:

class OutClass {
    static class InClass {    //创建静态内部类
        int i = 5;    //内部类成员
    }
    public void OutFun() {    //外部类成员
        InClass ic = new InClass();    //创建一个内部类对象
        int ii = ic.i;    //访问内部类成员
        System.out.println("static InClass's var is: " + ii);
    }
}
public class javatest {
    public static void main(String args[ ]) {
        OutClass oc = new OutClass();    //创建外部类对象
        oc.OutFun();    //调用内部类中的成员
   }
}

在外部类中访问静态内部类和访问非静态内部类是相同的,但是在外部类中访问静态内部类和非静态内部类就不再相同。因为静态内部类是外部类的静态成员,静态成员是不需要外部类对象而存在的,所以在外部类外,对静态内部类进行访问时是不需要创建外部类对象的。

注意:因为静态内部类是外部类的静态成员,静态成员是不需要外部类对象而存在的,所以在外部类外,对静态内部类进行访问时是不需要创建外部类对象的。

匿名内部类

在所有的内部类中最难的就应该是匿名内部类。匿名内部类从名字上看就知道是没有类名的内部类。正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写,

但使用匿名内部类还有个前提条件:必须继承一个父类或实现一个接口

创建匿名内部类

在创建匿名内部类中将使用到继承父类或者实现接口的知识,匿名内部类是没有名字的,所以在创建匿名内部类时同时创建匿名内部类的对象。创建匿名内部类的语法格式如下:

new InFather() {
    //匿名内部类
};

在创建匿名内部类的语法中,InFather是匿名内部类继承的父类的类名,使用new同时创建了匿名内部类的对象。在匿名内部类中可以重写父类中的方法,也可以定义自己的方法。

实例1:不使用匿名内部类来实现抽象方法

abstract class Person {
    public abstract void eat();
}

class Child extends Person {
    public void eat() {
        System.out.println("eat something");
    }
}
public class test {
    public static void main(String[] args) {
        Person p = new Child();
        p.eat();
    }
}

运行结果:

eat something

可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用。但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类会很麻烦。这个时候就引入了匿名内部类

实例2:匿名内部类的基本实现

abstract class Person {
    public abstract void eat();
}
public class test {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

运行结果:

eat something

可以看到,我们直接将抽象类Person中的方法在大括号中实现了,这样便可以省略一个类的书写,并且匿名内部类还能用于接口上

实例3:在接口上使用匿名内部类

interface Person {
    public void eat();
}
public class test {
    public static void main(String[] args) {
        Person p = new Person() {
            public void eat() {
                System.out.println("eat something");
            }
        };
        p.eat();
    }
}

运行结果:

eat something

由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口

实例4:Thread类的匿名内部类实现

public class test {
    public static void main(String[] args) {
        Thread t = new Thread() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        t.start();
    }
}

运行结果:

1 2 3 4 5

实例5:Runnable接口的匿名内部类实现

public class test {
    public static void main(String[] args) {
        Runnable r = new Runnable() {
            public void run() {
                for (int i = 1; i <= 5; i++) {
                    System.out.print(i + " ");
                }
            }
        };
        Thread t = new Thread(r);
        t.start();
    }
}

运行结果:

1 2 3 4 5

时间: 2024-08-03 09:20:14

java学习笔记9--内部类总结的相关文章

Java学习笔记

笔记 本笔记是在看浙大翁恺老师的视频教学时所做,希望对Java初学者有帮助! 一.Java基础1.正确认识Java(1)Java是一种有生产力的OOP语言,C++能做的Java都能做(2)Java与网络关系不大,更不是用来做网页的(3)Java是UNIX世界的产物,具有UNIX的思想(4)Java在国外广泛的被用来做各种应用2.Java历史(1)Brithday:May 23,1995(2)1991:Set-Top box:Jame Gosling(3)1994:OAK and FirstPer

Java学习笔记,适用于零基础的小伙伴

1. 成员变量与局部变量的区别     1.作用域:         成员变量的作用域是整个类中都可以访问:         局部变量是的作用域是定义它的{}内, {}中的语句执行完它就被回收:     2.初始值:         局部变量使用前必须手动赋值, 系统不会赋默认值:成员变量系统会赋默认初始值.     3.所在内存区域:         局部变量在方法运行的栈内存里,在栈里,会自动释放:         成员变量在对象里,对象在堆里,成员变量也在堆里,不使用的对象会被垃圾回收机制

java 学习笔记(入门篇)_java的安装与配置_java

  学习Java已经很长时间了,但是总感觉基础不是很好,有时候遇到一些平时不常见的问题就会无从下手,也从侧面显现了自己的一些问题.所以,打算写Java的随手笔记来巩固基础,加强学习.今天是第一篇,主要是java的安装,配置,也就是常说的Hello world.   一.下载   进入Oracle的官网,下载Java的jdk,   二.安装   安装就简单了,只需要下一步就可以,路径可以根据需要自己选择.   三.配置    安装完jdk后还不能来编译程序,因为还需要配置java 的jdk.进入的

java 学习笔记

笔记 JAVA的多线程 一.线程基本概念 将1个程序转换成多个独立运行的子任务.每个子任务都叫做一个线程. "进程"是指一种"自包容"的运行程序.有自己的地址空间.一个进程可以容纳多个同时执行的线程. 事实上,多线程最主要的一个用途就构建1个"反应灵敏"的用户界面. 二.线程的使用 1. 创建一个线程 最简单的方法就是从Thread类继承这个类,包含了创建和运行线程所需的一切东西. Thread最重要的是run方法,继承类必须对之进行重载,使其按

java学习笔记7--Polymorphism

笔记 Polymorphism 多态(polymorphism)也被称为动态绑定『dynamic binding』.后绑定『late binding』或运行时绑定『run-time bingding』.它的意思是要在程序运行的时候,根据对象的类型来决定该绑定哪个方法.多态性是继数据抽象和继承之后的,面向对象的编程语言的第三个基本特性. 绑定(binding): 将方法的调用连到方法本身前绑定(early binding): 当绑定发生在程序运行之前时(就是由编译器或连接器负责)后绑定(late

java学习笔记--Hiding implementation

笔记 hiding the implementation这句话讲得很好:In any relationship, it's important to have boundaries that are respected by all parties involved. 不管你们是什么关系,有一个彼此尊重的界限是很重要的. #----CLASSPATH(要大写,最好加上当前目录.):java 解释器会在以下两个地方查找.class文件: 1. jdk所在的标准目录 2. 路径 = 以CLASSPA

java 学习笔记(入门篇)_java的基础语法_java

前言 学习完了第一个java程序,之后就来系统的学习java.先从基础语法开始,这个语法你也可以理解为英语或是汉语里面的语法,只不过大家各有各的特点和区别.学习编程其实也是一个编程语言的学习过程.我们在学习英语的时候都说,要想学习好英语一定要动口说,那么在学习编程的时候你一定要动手写.编程无非就是一个写代码的过程,首要就是你心中要有基础,没有基础怎么去写呢,就像一篇好文章,没有好文笔是写不出来的.好文笔不仅靠积累,更要靠创造,编程亦是如此.java是一个面向对象的语言,在写代码的过程中,接触最多

java 学习笔记(入门篇)_java程序helloWorld_java

安装配置完Java的jdk,下面就开始写第一个java程序--hello World.用来在控制台输出"Hello World".首先,我们用最原始的方法,即用文本编辑器来写代码.在任意一个盘符下,以D盘根目录为例,在这个目录下建立一个txt文本,命名为HelloWorld,然后把后缀改为java,即HelloWorld.java.    然后打开编辑代码,如下: 复制代码 代码如下: public class HelloWorld { public static void main(

java学习笔记之eclipse+tomcat 配置_java

计划开始学习java.第一步 1.在servers窗口中新建server 2.弹出的界面选择对应的tomcat版本 3.这里是关键,已存在的项目不要选择过去,否则最后生成的server配置无法修改server locations 备注说明:虽然网上找到了不少在server配置上右键点击clean之后可以设置server locations的说法,但是我本机测试不是这个效果. 4.在server配置上双击 5.弹出的server locations这个时候可以配置了,选择第二项,使用tomcat,