关于 Java 内部类

  还记得在刚学习内部类时,常常对外部类以及各类内部类傻傻分不清楚,等到后来知道是怎么一回过后,又随着时间的流逝,再要说出个大概倒是什么都回顾不起来了,所以本文就对内部类作个回顾。java

  关于内部类的定义就是能够将一个类的定义放在另外一个类的定义内部,内部类是一种很是有用的特性,它容许咱们把一些逻辑相关的类组织在一块儿,而且能够控制位于内部的类的可视性。对于上面提到的各类内部类,咱们能够大概分为下面张图片的分类:多线程

内部类

内部类

  从上图中能够看到,内部类分红静态内部类和非静态内部类,而非静态内部类又能够分为局部内部类和匿名内部类,同时咱们把包裹内部类的类称之为外部类,就以下:app

class OuterClass {
    ...
    // 静态内部类
    static class StaticInnerClass {
        ...
    }
    // 非静态内部类
    class InnerClass {
        ...
    }
}
复制代码

  外部类可使用 public 或者默认包权限来修饰,而内部类则可使用 private、protected、public 以及包权限进行修饰。使用内部类和咱们平时使用普通类并没什么不一样,此外当生成内部类对象的时候,内部类持有当前外部类的引用,经过这个引用它能够访问外部类全部的成员变量,包括私有变量,也就是说实际上内部类和它所在的外部类实例对象是相关联的,它不能脱离外部类实例而独自存在,那么咱们可能会好奇,它是怎么样和外部类进行相关联的呢?实际上是编译器在生成 Java 字节码的时候经过给非静态内部类添加构造方法,使其在进行实例化时获得外部类的引用。ide

  既然构建内部类时须要持有外部类对象的引用,那么要想建立内部类对象就要使用外部类的对象来建立该内部类对象,以下:函数

public class OuterClass {
    public class Inner {}
    public static void main(String[] args) {
        OuterClass out = new OuterClass();
        OuterClass.Inner in = out.new Inner();
        // 也可使用这种方式进行建立
        Inner oin = out.new Inner();
    }
}
复制代码

静态内部类

  当咱们不想内部类对象与其外部类对象之间有联系的时候,咱们能够将内部类声明为 static,这样它变成了静态内部类,既然没有和外部类对象有任何相关联,因此它也不须要再依赖与外部类对象,这样它也不能访问外部类的非静态成员,只可以访问外部类的静态成员,此外静态内部类和非静态内部类在建立时也稍有区别:学习

// OuterClass 为外部类,类含有静态内部类 S 以及非静态内部类 I
OuterClass out = new OuterClass();
// 建立静态内部类
out.S staticClass = out.S();
// 建立非静态内部类
out.I in = out.new I();
复制代码

  这里对静态内部类和非静态内部类作个总结:spa

  1. 静态内部类能够有静态成员,而非静态内部类则不能有静态成员;
  2. 静态内部类能够访问外部类的静态变量,而不可访问外部类的非静态变量;
  3. 非静态内部类的非静态成员能够访问外部类的非静态变量;
  4. 静态内部类的建立不依赖于外部类,而非静态内部类必须依赖于外部类的建立而建立;

局部内部类

  若是一个内部类只在一个方法中使用,那么咱们就能够将这个类定义在方法内部,这种内部类被称为局部内部类,其做用域也仅限于该方法区内,以下:线程

public class OuterClass {
    
    public void show() {
        System.out.println("外部类方法");
    }   
    
    public void showFunctionClass() {
		class FunctionClass {
			private void show() {
				System.out.println("我是局部内部类");
			}
		}
        FunctionClass FunctionClass = new FunctionClass();
		FunctionClass.show();
	}
    
    public static void main(String[] args) {
        OuterClass out = new OuterClass();
		out.show();
		out.showFunctionClass();
    }
    
}

// 运行结果:
//外部类方法
//我是局部内部类
复制代码

  此外,局部内部类注意事项以下:code

  1. 局部内部类对外是隐藏的,只能经过建立这个类的方法中进行访问;
  2. 局部内部类不容许使用访问权限修饰符;

匿名内部类

  匿名内部类是没有类名的局部类,匿名内部类使得类的定义和实例化同时进行,因此一般用来进行简化代码编写,而因为它没有类名也就不存在构造方法,下面经过两个小实验来学习匿名内部类的使用:cdn

public interface Person {
    public void eat();
}

public class Child implements Person {
    @Override
	public void eat() {
		// TODO Auto-generated method stub
		System.out.println("eat...");	
	}
	
	public static void main(String[] args) {
		Child child = new Child();
		child.eat();
	}
}
复制代码

  这是没有使用匿名内部类的普通写法,先实现接口再重写其中的方法,最后再实例化对象并调用方法,前面咱们说到匿名内部类能够简化代码,那接下来看一样的例子用匿名内部类怎么来写:

public class Child {
	public static void main(String[] args) {
		new Person() {
			@Override
			public void eat() {
				// TODO Auto-generated method stub
				System.out.println("eat...");
			}
		}.eat();	
	}
}
复制代码

  这样引入匿名内部类直接就将接口中的方法进行重写,就省略了一个类的编写,因此只要是一个类是抽象类或者是一个接口,那么其子类方法或接口方法均可以使用匿名内部类来实现,匿名内部类经常使用的典型场景是使用 Thread 类或者 Runnable 接口来实现多线程。此外,还须要注意的是,匿名内部类若是使用一个在其外部定义的对象时,编译器会要求该变量必须是 final,缘由即是要保持参数的一致性。

为何须要内部类

  到这里,咱们大概搞清楚内部类的相关知识点,其中在《Thinking in Java》一书中做者说到内部类最吸引人的缘由是:

每一个内部类都能独立地继承自一个(接口的)实现,因此不管外围类是否已经继承了某个(接口的)实现,对于内部类都没有影响。

  看到这儿,我想说的是大师就是大师,说的我都一脸懵逼了(太菜了),总结了下仍是有下面几点:

  • 内部类方法能够访问该类定义所在做用域中的数据,包括被 private 修饰的私有数据;
  • 内部类能够对同一包中的其余类隐藏起来;
  • 内部类能够解决 Java 单继承的缺陷;
  • 对于一些有大量冗余代码的回调函数能够经过匿名内部类来实现;


参考资料: 《Thinking in Java》

内推信息

  • 咱们正在招募小伙伴,有兴趣的小伙伴能够把简历发到 app@talkmoney.cn,备注:来自掘金社区
  • 详情能够戳这里--> 广州芦苇信息科技
相关文章
相关标签/搜索