本文将从以下几个方面详细讲述内部类
1.内部类的定义与使用
- 内部类的基本概念
- 内部类为什么存在
- 内部类与外部类的关系
2.内部类
- 内部类分类
- 在外部类外部创建内部类
- 在外部类内部创建内部类
3.内部类详解
- 成员内部类
- 静态内部类
- 方法内部类
- 匿名内部类
正文
1. 内部类的定义与使用
1.1 基本概念:所谓内部类就是在一个类的内部嵌套其他类结构
我们通过一个例子来看看简单内部类的定义
// 定义一个外部类
class Outter{
private String title = "i am class Outters title";
//*****************************************
// 在外部类的内部定义一个内部类
class Inner{
// 在内部类中定义一个普通方法
public void print(){
// 调用外部类的private属性
System.out.println(title);
}
}
//*****************************************
// 在外部类定义一个方法,负责产生内部类对象以及调用内部类的print方法
public void fun(){
Inner inner = new Inner(); //内部类对象
inner.print(); // 内部类提供的print方法
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter(); //外部类的对象
outter.fun(); //外部类的方法
}
}
看完上述代码,我们的第一感受就是麻烦!确实,引入内部类让程序的结构变得复杂,但是内部类也有它的好处,就是我们可以方便的操作外部类的私有访问。
做个练习,我们在不修改主代码的情况下,对上述代码修改,使其也能达到上面的效果
class Outter{
private String title = "i am class Outters title";
public String getTitle(){
return title;
}
public void fun(){
Inner inner = new Inner(this);
inner.print();
}
}
class Inner{
private Outter out;
public Inner(Outter out){
this.out = out;
}
public void fun(){
System.outy.println(out.getTitle());
}
}
// 主方法代码相同,不再重复
1.2 内部类为什么存在
- 内部类可以访问该类定义所在操作域的所有数据,包括私有操作域
- 内部类可以对该包下的其他类隐藏
- 内部类可以“破解”java单继承的缺陷
看个内部类“实现多继承”的例子
class milk{
private String name = "milk的私有属性";
public String getName() { return name; }
}
class puremink{
private int price = 10;
public int getPrice() { return price; }
}
class Outter{
// *****************内部类***************
public class InnerClassMilk extends milk{
public String getName(){
return super.getName();
}
}
public class InnerClassPurMilk extends puremink{
public int getPrice(){
return super.getPrice();
}
}
// *****************内部类***************
// 外部方法
public String getName(){
InnerClassMilk innerClassMilk = new InnerClassMilk();
return innerClassMilk.getName();
}
public int getPrice(){
InnerClassPurMilk innerClassPurMilk = new InnerClassPurMilk();{
return innerClassPurMilk.getPrice();
}
}
}
public class Test {
public static void main(String[] args) {
Outter outter = new Outter();
System.out.println(outter.getName());
System.out.println(outter.getPrice());
}
}
这里我们只是利用了内部类,在一个类内部建了两个内部类用来继承两个类,实现了所谓的“多继承”,但我们要记住,java是没有多继承的!
1.3 内部类与外部类的关系
- 对于非静态内部类来说,内部类的创建依赖于外部类的实例对象,在没有外部类的实例之前是无法创建外部类的
- 内部类是一个相对独立的单元,与外部类不是is-a关系
- 内部类可以直接访问外部类的数据,但外部类不能直接访问内部类的数据
- 外部类要想访问内部类的数据,需要通过内部类引用来访问
class Outter{
public void fun(){
Inner inner = new Inner();
inner.show();
}
}
class Inner{
public void show(){
System.out.println("i am inner class's method ");
}
}
public class Test{
public static void main(String[] args) {
Outter outter = new Outter();
outter.fun();
}
}
内部类直接访问外部类的数据,上述代码中已经出现多次了,不再多说。我们看看外部类如何通过内部类引用访问内部类数据。
class Outter{
public void fun(){
Inner inner = new Inner();
inner.show();
}
}
class Inner{
public void show(){
System.out.println("i am inner class's method ");
}
}
public class Test{
public static void main(String[] args) {
Outter outter = new Outter();
outter.fun();
}
}
2. 内部类
2.1 内部类分类
在java中内部类可以分为:
- 成员内部类
- 静态内部类
- 方法内部类
- 匿名内部类
在第三部分我们来详细说这四种内部类
2.2 在外部类外部创建内部类
在外部类外部创建内部类,我们通过
举个栗子:
class Outter{
private String name;
private int age;
class Inner{
public Inner(){
Outter.this.name = "Outter's name ";
Outter.this.age = 20;
}
public void print(){
System.out.println(Outter.this.name);
System.out.println(Outter.this.age);
}
}
}
public class Test{
public static void main(String[] args) {
Outter.Inner inner = new Outter().new Inner();
inner.print();
}
}
2.3 在外部类内部创建内部类
就像创建普通类一样,直接创建。
3. 内部类详解
3.1 成员内部类
定义在类内部的类,与类的方法,属性属于同一级别的,即也是外部类的成员。
我们上面写的其实都是成员内部类。不做赘述,只需要注意两点:
- 成员内部类中不能存在任何static成员与方法
- 成员内部类的创建要依赖于外部类,没有外部类就没有内部类
3.2 静态内部类
静态内部类是用static修饰的内部类。我们直到静态内部类与非静态内部类最大的区别是非静态内部类在编译完成之后会有一个隐含的引用,这个引用指向了创造它的外部类,而静态内部类是没有这个引用的,没有这个引用意味着:
-
静态内部类的创建不依赖于外部类,可以直接创建
-
静态内部类不可以使用外部类中的任何非静态属性和方法,而非静态内部类可以
外部类的创建语法:
注意啊,这和在类的外部创建是不一样的,少了个括号!
看个栗子:
可以看到静态内部类是不能访问非静态属性的
3.3 方法内部类
方法内部类是定义在外部类的方法中,和成员内部类基本一致,只是作用域不用。方法内部类只能在该方法中被引用,出了该方法的作用域就会失效。方法内部类一般用于解决复杂问题的系统,想创建一个类来辅助我们解决方案,但又不希望这个类是公共的,因此就有了方法内部类。
方法内部类有几点需要注意的: -
方法内部类不允许使用权限修饰符,public、protected、private均不允许
-
方法内部类对外完全隐藏,除了创建这个类的方法可以访问外,别的都不可以访问
-
局部内部类要想使用方法形参,该参数必须为final声明的(JDK1.8之后隐式final声明)
栗子:
class Outter{
private int num = 10;
public void test(int num2){
class Inner{
public void fun(){
num += 20;
System.out.println(num);
// 对num2进行改变会报错
// 因为方法内部类接收外部参数必须是final的,不可修改的
System.out.println(num2);
}
}
new Inner().fun();
}
}
public class Test{
public static void main(String[] args) {
Outter outter = new Outter();
outter.test(20);
}
}
3.4 匿名内部类
匿名内部类就是一个没有名字的方法内部类。所以它在符合方法内部类的约束外,还有一些需要注意的地方:
- 匿名内部类必须继承一个抽象类或者实现一个接口
- 匿名内部类没有构造方法,因为他没有类名。
- 匿名内部类没有访问修饰符
- 匿名内部类中不能存在任何静态成员或方法
- 与局部内部相同,匿名内部类也可以引用方法形参,此形参也必须声明为final
栗子:
class MyInterface{
void test() {
System.out.println("MyInterface's test method ");
}
}
class Outter{
private int num = 10;
public void test(int testNum){
new MyInterface(){
@Override
void test() {
System.out.println("i am no-name InnerClass");
System.out.println(testNum);
}
}.test();
}
}
public class Test{
public static void main(String[] args) {
Outter outter = new Outter();
outter.test(100);
}
}