java 内部类、匿名内部类

java

一:内部类

1:什么是内部类?
  大部分时候,类被定义成一个独立的程序单元。在某些情况下,也会把一个类放在另一个类的内部定义,这个定义在其他类内部的类就被称为内部类(有些地方也叫做嵌套类),包含内部类的类也被称为外部类(有些地方也叫做宿主类)

我们先创建一个基本的内部类结构:

class Outer{//外部类

//内部类

class Inner{

}

}

2:内部类的划分

内部类分为成员内部类和局部内部类。内部类也会生成.class文件。

2.1: 成员内部类

  定义在外部类中的成员位置,与类中的成员变量相似,可通过外部类对象进行访问。

 内部类可以使用外部类的成员,包括私有成员。但是外部类要使用内部类的成员,必须建立内部类变量。

2.2: 局部内部类(比较少用)

定义:在方法里面有一个内部类。

 只有在内部类所属的方法中创建内部类对象,方可访问局部内部类。而测试类中只需要创建外部类对象,然后调用外部类方法即可。

3:例子

import java.util.HashMap;

public class Parcell {

private HashMap<String, String> testMap = new HashMap<String, String>();

class Contents {

// 返回一个外部类的引用.

public Parcell ParcellRef = Parcell.this;

}

class Destination {

public void putSomethingInMap() {

testMap.put("hello", "world");

System.out.println(testMap.get("hello"));

}

}

public Destination to() {

return new Destination();

}

public Contents contents() {

return new Contents();

}

public void ship(String dest) {

Contents c = new Contents();

Destination d = new Destination();

}

public static void main(String[] args) {

Parcell p = new Parcell();

Parcell.Contents c = p.contents();

Parcell.Destination d = p.to();

d.putSomethingInMap();

Parcell.Contents c1 = p.new Contents();

}

}

内部类的语法介绍

  (1)普通内部类持有一个指向外部类的引用。要创建普通内部类,一定要先创建外部类。
  (2)普通内部类就像人体的心脏一样,能够随意访问外部类的任意成员变量。
  (3)在内部类中可以通过“外部类类名.this”的方式返回一个指向外部类实例的引用.如Parcell.this
  (4)在外部类的static方法中若要创建内部类对象,则需要通过“外部类类名.new XXX()”的方式来创建。
  (5)普通内部类中不能拥有静态成员变量。静态内部类中可以拥有静态成员变量。也可以拥有非静态成员变量。但是静态内部类不能访问外部类中非静态的成员变量。而普通内部类可以访问外部类的静态成员变量。

为什么static方法中需要p.new XXX()的方式而非static方法中我们直接new 内部类名 就可以创建一个对象了呢?
如果你有这样的疑问请再看看第一条,一定可以想明白的。

4.作用
  1)更好的封装性
  2)内部类成员可以直接访问外部类的私有数据,因为内部类被当成其外部类成员,但外部类不能访问内部类的实现细节,例如内部类的成员变量
  3)匿名内部类适合用于创建那些仅需要一次使用的类

体外话:静态内部类

  Java里面static一般用来修饰成员变量或函数。但有一种特殊用法是用static修饰内部类,普通类是不允许声明为静态的,只有内部类才可以。被static修饰的内部类可以直接作为一个普通类来使用,而不需实例一个外部类。

静态内部类的特点:

  1.非静态内部类中不允许定义静态成员
  2.外部类的静态成员不可以直接使用非静态内部类
  3.静态内部类,不能访问外部类的实例成员,只能访问外部类的类成员

二:匿名内部类

匿名内部类使用最频繁的场合就是在创建线程的时候。

程序清单2-1:

public class Demo {

public void test(String title) {

Thread thread = new Thread(new Runnable() {

@Override

public void run() {

// title = "我不要吃鸡";

// 改变时会提示错误

// 在封闭范围中定义的局部变量必须是final的。

System.out.println(title);

}

});

thread.start();

}

public static void main(String[] args) {

for (int i = 0; i < 10; i++) {

Demo demo = new Demo();

demo.test("我要吃鸡" + i);

}

}

}

    在程序清单2-1中,test()方法内部有一个线程对象thread,是通过new Thread()创建的。new Thread()可以接收一个实现了Runnable接口类型的对象,这个对象要怎么创建呢?可以通过匿名内部类的形式来创建——new Runnable() {public void run(){......}}——这段简短的代码等同于:

// 实现Runnable接口

class MyRunnable implements Runnable {

@Override

public void run() {

}

}

// 向上转型

Runnable myRunnable = new MyRunnable();

匿名内部类的好处就在于不仅节省了定义实现类的过程,还能够自动向上转型。

  在程序清单2-1中,test()方法还有一个参数title,JDK1.8之前,编译器要求它必须是final类型的。但JDK1.8之后,如果我们在匿名内部类中需要访问局部变量,那么这个局部变量不再需要用final关键字修饰了。

  但如果想要在匿名内部类中改变局部变量的值,编译器就会提醒你不能这样做,它会提示:“在封闭范围中定义的局部变量必须是final的。”

另一个关于匿名内部类的例子:

开发中,最常用到的内部类就是匿名内部类了。以接口举例,当你使用一个接口时,似乎得做如下几步操作。

   1、定义子类

   2、重写接口中的方法

   3、创建子类对象

   4、调用重写后的方法

我们的目的,最终只是为了调用方法,那么能不能简化一下,把以上四步合成一步呢?匿名内部类就是做这样的快捷方式。

条件

  匿名内部类必须继承一个父类或者实现一个父接口。

格式

new 父类名或者接口名(){

// 方法重写

@Override

public void method() {

// 执行语句

}

};

使用方式

以接口为例,匿名内部类的使用,代码如下:

定义接口:

public abstract class FlyAble{

public abstract void fly();

}

创建匿名内部类,并调用:

public class InnerDemo {

public static void main(String[] args) {

/*

1.等号右边:是匿名内部类,定义并创建该接口的子类对象

2.等号左边:是多态赋值,接口类型引用指向子类对象

*/

FlyAble f = new FlyAble(){

public void fly() {

System.out.println("我飞了~~~");

}

};

//调用 fly方法,执行重写后的方法

f.fly();

}

}

通常在方法的形式参数是接口或者抽象类时,也可以将匿名内部类作为参数传递。代码如下:

public class InnerDemo2 {

public static void main(String[] args) {

/*

1.等号右边:定义并创建该接口的子类对象

2.等号左边:是多态,接口类型引用指向子类对象

*/

FlyAble f = new FlyAble(){

public void fly() {

System.out.println("我飞了~~~");

}

};

// 将f传递给showFly方法中

showFly(f);

}

public static void showFly(FlyAble f) {

f.fly();

}

}

以上两步,也可以简化为一步,代码如下:

public class InnerDemo3 {

public static void main(String[] args) {

/*

创建匿名内部类,直接传递给showFly(FlyAble f)

*/

showFly( new FlyAble(){

public void fly() {

System.out.println("我飞了~~~");

}

});

}

public static void showFly(FlyAble f) {

f.fly();

}

}

为什么需要内部类?

  Java的内部类让我很容易的想起来JavaScript的闭包,闭包就是定义在一个函数内部的函数——这听起来和Java的内部类定义一样一样的。本质上,闭包是将函数内部与函数外部连接起来的桥梁。内部类一样,它是将内部类与外部类连接起来的桥梁。

来看看什么是闭包吧:

function wanger() {

var age = 30;

function know() {

console.log(age);

}

}

wanger();

// 控制台输出30

除此之外,内部类最引人注意的原因是:

 内部类可以独立地继承一个抽象类或者实现一个接口,无论外部类是否也这样做了,对内部类都没有影响。

以上是 java 内部类、匿名内部类 的全部内容, 来源链接: utcz.com/z/391518.html

回到顶部