Java内部类

一、定义

在一个类的内部定义的一个类,这个定义在内部的类叫内部类

 

二、  1、内部类作为外部类的一个"成员",可以被外部类的其它的成员访问。也可以使用各种访问修饰符。

2、内部类:可以访问外部类的成员(即使外部类成员是私有的),也可以访问本类的成员;

3、内部类的常用修饰符:

1.可用修饰符:四种访问权限修饰符、static、final、abstract(外部类可以不是abstract),可以调用外部类的属性

2.private:此内部类被私有,只能在外部类内部被实例化;

  static :在其它类中实例化内部类对象,就不需要外部类对象了;

  1.被静态修饰的成员内部类只能访问外部类的静态成员

  2.内部类被静态修饰后的方法

可以是静态方法

可以是非静态方法

三、内部类分类:

1、java内部类分为:成员内部类、方法内部类、静态内部类,匿名内部类

2、成员内部类:定义在外部类的成员位置,跟外部类的其他成员是并列关系

①具有成员的特征:可以有四种访问修饰符、static和final修饰

②具有类的特征:abstract,可以有具体成员和方法、构造器

 

3、 成员内部类定义:

classOuter {

classInner{}

}

编译上述代码会产生两个文件:Outer.class和Outer$Inner.class

 

3/1  成员内部类不能含有静态变量或静态方法,因为实例化成员内部类对象要先实例化外部类对象。如果一个内部类的成员变量被声明为static的,则这个内部类也要被声明为static的,这个内部类就成为了静态内部类

2/3 创建成员内部类的对象

①创建静态内部类的对象可以直接通过  外部类.内部类  引用名 = new 外部内.内部内的构造方法,如Outer.Inneroi = new Outer.Inner();

②创建非静态内部类的对象

Outer out = new Outer();

Outer.Inner in = out.new Inner();

in.show();

或者

Outer.Inner in = new Outer().new Inner();

in.show();

 

3/2 成员内部类可以直接访问外部类包括private型的所有成员,外部类要访问内部类成员要先创建内部类的对象

3/3 在成员内部类要引用外部类对象时,使用outer.this来表示外部类对象

 

4、局部内部类:定义在某个方法的内部。只有在内部类的方法时才会创建内部类的对象

常用形式,定义一个方法,使其返回类型为某个类或接口的对象,这个类或接口在这个方法内部定义,实现接口或类

把类放在方法内

比较少用的形式:

classOuter {

publicvoid doSomething(){

classInner{

publicvoid seeOuter(){

 

}

}

}

}

 

常用形式:

class Outer{

//定义一个返回类型为某个类或接口的方法

public Interfunction(){

//class Studentimplements Inter{

String name;

int age;

}

//返回实现类的对象

return newStudent();

}

}

 

4/1 方法内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。

4/2 方法内部类对象不能使用该内部类所在方法的非final局部变量。

因为方法的局部变量位于栈上,只存在于该方法的生命期内。当一个方法结束,其栈结构被删除,局部变量成为历史。但是该方法结束之后,在方法内创建的内部类对象可能仍然存在于堆中!例如,如果对它的引用被传递到其他某些代码,并存储在一个成员变量内。正因为不能保证局部变量的存活期和方法内部类对象的一样长,所以内部类对象不能使用它们。

下面是完整的例子:

classOuter {

publicvoid doSomething(){

finalint a =10;

classInner{

publicvoid seeOuter(){

System.out.println(a);

}

}

Innerin = new Inner();

in.seeOuter();

}

publicstatic void main(String[] args) {

Outerout = new Outer();

out.doSomething();

}

}

4/3 方法内部类不能定义成static类型的,其成员变量也不能是static的

5、匿名内部类

5/1 定义

顾名思义,没有名字的内部类。表面上看起来它们似乎有名字,实际那不是它们的名字。

正因为没有名字,所以匿名内部类只能使用一次,它通常用来简化代码编写

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

 

 

5/2 声明

当程序中使用匿名内部类时,在定义匿名内部类的地方往往直接创建该类的一个对象。匿名内部类的声明格式如下:

new ParentName(){

...// 内部类的定义

}

 

例:

class Outer{

public Interfunction(){

return new Inter{

};

}

}

5/3 使用匿名内部类的情况

3/1 只用到类的一个实例 。

3/2 类在定义后马上用到。

3/3 类非常小(SUN推荐是在4行代码以下)

3/4 给类命名并不会导致你的代码更容易被理解。

5/4 匿名内部类的使用原则

4/1 匿名内部类不能有构造方法。

4/2 匿名内部类不能定义任何静态成员、静态方法。

4/3 匿名内部类不能是public,protected,private,static。

4/4 只能创建匿名内部类的一个实例。

4/5 一个匿名内部类一定是在new的后面,用其隐含实现一个接口或实现一个类。

4/6 因匿名内部类为局部内部类,所以局部内部类的所有限制都对其生效。

5/5 匿名内部类的应用:

4/5/1 当我们需要调用某个方法,这个方法需要一个某接口类型的实参。我们为了调用这个方法,可

           以先定义一个这个接口的子类,然后实例化这个子类对象,并将引用传递到这个方法;

4/5/2 如果,这个子类,只在调用这个方法时使用,其他地方不需要用到这个子类,这时,可以不用

           定义这个子类。在调用这个方法时,使用"匿名内部类"的方式。那么这个子类就没有了"性"。

6、匿名内部类的使用实例 

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

abstract class Person {

    public abstract void eat();

}

 

class Child extends Person {

    public void eat() {

        System.out.println("eat something");

    }

}

 

public class Demo {

    public static void main(String[] args) {

        Person p = new Child();

        p.eat();

    }

}

运行结果:eatsomething

可以看到,我们用Child继承了Person类,然后实现了Child的一个实例,将其向上转型为Person类的引用

但是,如果此处的Child类只使用一次,那么将其编写为独立的一个类岂不是很麻烦?

这个时候就引入了匿名内部类

 

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

1

2

3

4

5

6

7

8

9

10

11

12

13

14

abstract class Person {

    public abstract void eat();

}

 

public class Demo {

    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 Demo{

    public static void main(String[]args) {

        Personp = new Person() {

            public void eat(){

                System.out.println("eatsomething");

            }

        };

        p.eat();

    }

}

运行结果:eat something

 

由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现

最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口

 

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

public class Demo{

    public static void main(String[]args) {

        Threadt = 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接口的匿名内部类实现

1

2

3

4

5

6

7

8

9

10

11

12

13

public class Demo {

    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

四、内部类的共性

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

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

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

 

五、内部类的常用修饰符

1、可用修饰符:四中访问权限修饰符、static、final、abstract(外部类可以不是abstract)

2、内部类被私有化,则只能在外部类内部被实例化

3、内部类被static修饰,在其他类中实例化内部类对象,不需要外部类对象

4、内部类被static修饰后可以有静态成员和非静态成员,但若内部类中有由静态成员,则内部类必须是静态的

5、被static修饰的成员内部类只能访问外部类的静态成员

 

六、为什么需要内部类

        典型的情况是,内部类继承自某个类或实现某个接口,内部类的代码操作创建其的外围类的对象。所以你可以认为内部类提供了某种进入其外围类的窗口。使用内部类最吸引人的原因是:

        每个内部类都能独立地继承自一个(接口的)实现,所以无论外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。如果没有内部类提供的可以继承多个具体的或抽象的类的能力,一些设计与编程问题就很难解决。从这个角度看,内部类使得多重继承的解决方案变得完整。接口解决了部分问题,而内部类有效地实现了“多重继承”。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值