深入了解Java内部类的用法

1.内部类分类和概念

java类的五大成员:属性,方法,构造器(构造方法),代码块,内部类

内部类的分类:

定义在外部类局部的位置(比如方法内):

  • 局部内部类(有类名)
  • 匿名内部类(无类名)

定义在外部类成员位置上:

  • 成员内部类(没有static修饰)
  • 静态内部类(有static修饰)

概念:在一个类的内部再定义一个完整的类,也会生成一个class文件

深入了解Java内部类的用法_第1张图片

代码示例:

/**
 * 内部类
 */
public class InnerClass {
    private int n = 521;

    public InnerClass(int n) {
        this.n = n;
    }

    class Inner { // 内部类

    }
}

谨记:内部类很重要,java底层源码内部类使用场景很多!

2.局部内部类

class Outer001 { // 外部类
    private int n = 521;
    private void kaka() {
        System.out.println("我是外部类的方法!");
    }
    public void show() {
        // 局部内部类定义在外部类的局部位置,通常在方法中
        class Inner001 {
            // 局部内部类
            public void f() {
                // 可以直接访问外部类的所有成员,包含私有的
                System.out.println(n);
            }
        }
    }
}

不能添加访问修饰符,但是可以添加final

局部内部类的作用域只在定义它的方法或者代码块中

外部类使用内部类的方法,直接new即可:

public void show() {
    // 局部内部类定义在外部类的局部位置,通常在方法中
    final class Inner001 {
        // 局部内部类
        public void f() {
            // 可以直接访问外部类的所有成员,包含私有的
            System.out.println(n);
            kaka();
        }
    }
    // 外部类使用内部类的方法
    Inner001 inner001 = new Inner001();
    inner001.f();
}

外部其他类不能访问局部内部类!

外部类和局部内部类的成员重名时,默认遵循就近原则,如果想要访问外部类的成员,使用外部类名.this.成员进行访问

3.匿名内部类(重要)

匿名内部类其实有名字,它的名字是底层的JDK给分配的~系统分配该类名的时候会在外部类的基础上加上$1,存在多个内部类的,$后面的值进行递增

基于接口的匿名内部类

/**
 * 匿名内部类
 */
public class AnonymousInnerClass {
    public static void main(String[] args) {
        Outer002 outer002 = new Outer002();
        outer002.method();
    }
}

class Outer002 {
    private int n = 521;

    public void method() {
        // 基于接口的匿名内部类
        // tiger的编译类型是IA,运行类型就是匿名内部类!
        // 系统分配该类名的时候会在外部类的基础上加上$1,此处是Outer002$1
        // JDK底层在创建了匿名内部类之后,立即创建了一个实例,并且把地址返回给tiger
        IA tiger = new IA() {
            @Override
            public void cry() {
                System.out.println("我是一只小老虎");
            }
        };
        tiger.cry();
        System.out.println(tiger.getClass());
    }
}

interface IA {
    public void cry();
}

输出:

我是一只小老虎
class seniorobject.innerclass.Outer002$1

注意:匿名内部类使用一次就不能再使用了!

基于类的匿名内部类

基于类的匿名内部类和基于接口的差不太多

Father类:

class Father {
    private String name;

    public Father(String name) {
        this.name = name;
    }
    public void test() {

    }
}

匿名内部类:

// 基于类的匿名内部类,加入大括号就摇身一变变成内部类了
Father jack = new Father("jack"){
    @Override
    public void test() {
        super.test();
        System.out.println("♪(^∇^*)");
    }
};
System.out.println(jack.getClass());

输出:

class seniorobject.innerclass.Outer002$2

一些细节

匿名内部类是类,同时,它也可以理解为是一个对象

匿名内部类可以访问外部类的所有成员,包括私有的

不能添加访问修饰符

定义域在定义它的方法或者代码块中,转瞬即逝!

外部其他类不能访问匿名内部类

外部类和匿名内部类成员重名时,参照局部内部类的方式即可

匿名内部类的最佳实践

当作实参直接传递,简洁高效

/**
 * 匿名内部类的最佳实践
 * 当作实参直接传递,简洁高效
 */
public class AnonymousInnerClassPractice {
    public static void main(String[] args) {
        f(new IL() {
            @Override
            public void show() {
                System.out.println("你好啊");
            }
        });
    }

    public static void f(IL il) {
        il.show();
    }
}

interface IL {
    void show();
}

4.成员内部类

定义在外部类的成员位置上:

实例:

/**
 * 成员内部类
 */
public class MemberInnerClass {
    public static void main(String[] args) {
        Outer003 outer003 = new Outer003();
        outer003.t();
    }
}

class Outer003 {
    private int n = 521;
    public String name = "dahe";

    class Inner003 { // 成员内部类
        public void say() {
            System.out.println(n + name);
        }
    }

    public void t() {
        // 使用成员内部类
        Inner003 inner003 = new Inner003();
        inner003.say();
    }
}

输出:

521dahe

可以访问外部类的所有成员,包括私有的

可以添加任意的访问修饰符

作用域为整个类体中

外部类想要使用成员内部类,创建对象调用即可!

外部其他类想要访问成员内部类,存在两种方式:

// 直接创建对象
Outer003.Inner003 inner003 = outer003.new Inner003();
// 注意:这里的outer003是外部类的对象实例
// 成员内部类的外部类创建一个返回内部类对象的公有方法
public Inner003 getInner003Instance() {
    return new Inner003();
}

// 外部其他类进行调用该共有方法
Outer003.Inner003 inner0031 = outer003.getInner003Instance();
inner0031.say();

外部类和成员内部类的成员重名时,参考局部内部类和匿名内部类即可

5.静态内部类

可以直接访问外部类的静态成员

可以添加任意的访问修饰符

作用域为整个类体

外部类想要访问静态内部类依然是创建对象访问

外部其他类想要访问静态内部类:

// 通过类名直接访问
Outer004.Inner004 inner004 = new Outer004.Inner004();
inner004.say();
// 静态内部类的外部类创建一个返回内部类对象的公有方法
// 返回静态内部类的对象实例
public Inner004 getInner004() {
    return new Inner004();
}

Outer004.Inner004 inner0041 = outer004.getInner004();
inner0041.say();
// 返回静态内部类的对象实例,但是是静态方法
public static Inner004 getInner004_() {
    return new Inner004();
}

// 静态内部类的外部类创建一个返回内部类对象的公有静态方法
Outer004.Inner004 inner0042 = Outer004.getInner004_();
inner0042.say();

整体代码示例:

/**
 * 静态内部类
 */
public class StaticInnerClass {
    public static void main(String[] args) {
        Outer004 outer004 = new Outer004();
        // 通过类名直接访问
        Outer004.Inner004 inner004 = new Outer004.Inner004();
        inner004.say();
        // 静态内部类的外部类创建一个返回内部类对象的公有方法
        Outer004.Inner004 inner0041 = outer004.getInner004();
        inner0041.say();
        // 静态内部类的外部类创建一个返回内部类对象的公有静态方法
        Outer004.Inner004 inner0042 = Outer004.getInner004_();
        inner0042.say();
    }
}

class Outer004 {
    private int n = 521;
    private static String name = "dahe";
    public static class Inner004 {
        public void say() {
            // 可以直接访问外部类的静态成员
            System.out.println(name);
        }
    }

    // 返回静态内部类的对象实例
    public Inner004 getInner004() {
        return new Inner004();
    }

    // 返回静态内部类的对象实例,但是是静态方法
    public static Inner004 getInner004_() {
        return new Inner004();
    }
}

外部类和成员内部类的成员重名时,遵循就近原则,如果想要访问外部类的成员,使用外部类名.成员即可

以上就是深入了解Java内部类的用法的详细内容,更多关于Java内部类的资料请关注脚本之家其它相关文章!

你可能感兴趣的:(深入了解Java内部类的用法)