Java中,允许在一个类的内部定义类,这样的类称为内部类。内部类所在的类称为外部类,然后我们在实际开发中,根据内部类的位置、修饰符和定义的方式不同。内部类可以分为4种,分别是成员内部类、局部内部类、静态内部类以及匿名内部类。下面将会为大家讲解。
一、首先我们知道Java中存在类与类之间的关系。
(1)继承。它表达的实际上一种:(is... a... )的关系,例如Student"学生"类继承了Person"人"类,那么表达的关系实际上是不是 Student is a Person,简单的描述就是学生是一个人。
(2)还有一种关系就是拥有。(它与今天要讨论的内部类的息息相关)
它表达的实际上是一种:(has... a... ),例如:Student has a Phone,Phone是"手机"类,Student是"学生"类,那么简单的描述就是学生有一个手机
那么我们常见的内部类有哪些呢?
二、成员内部类:
在一个类中除了可以定义成员变量、成员方法,还可以定义类,这样的类称为成员内部类。
(1)首先我先创建一个Student类,里面有它的成员变量和成员方法。这个Student"学生"类我们叫做外部类,在该外部类里面写一个Phone"手机"类叫做成员内部类。
package com.feisi.inner;
public class Student {
//外部类成员变量
private String name="张三";
private int age;
private char sex;
private String sid; //学号
//成员内部类
public class Phone{
//内部类成员变量
public String brand="华为"; //手机品牌
public double price=3000.0; //手机价格
//内部类成员方法
public void call(){
//在成员内部类的方法中,访问外部类的成员变量
System.out.println("我的名字是:"+name+",刚刚打完电话.....");
//在成员内部类的方法中,访问外部类的成员方法
eat();
}
public double getPrice(){
return this.price;
}
}
//外部类成员方法
public void study(){
System.out.println("在学习中.....");
//实例化内部类对象
Phone phone =new Phone();
//访问内部类变量和方法
System.out.println("关于我的手机:");
System.out.println("手机的品牌是:"+phone.brand);
System.out.println("手机的价格是:"+phone.getPrice());
}
public void eat(){
System.out.println("吃饭中.....");
}
}
这个成员内部类的访问权限可以是(public、默认的、protected、private)都可以。因为首先你不要单纯的把它当成一个类看待,把它整体看成一个类的家庭成员看待,和外部类调用方式差不多:例如:外部类中是private修饰的成员变量,要用它就是用getXxx()和SetXxx()方法调用,是public修饰的成员方法,要调用就用创建的对象调用。其次你可以把它当成一个类看,那么它里面也可以有成员变量、成员方法。
(2) 接下来再写一个测试类Test01,对它进行测试输出。
1、现在我们不能这么创建Phone类对象,因为它不是一个外部类(举个简单例子:好比你有一个手机,我要经过你的同意才能拿到手机,不能直接拿)
2、那么我们该怎样创建它的对象呢?
首先要把它理解成一个"成员",看它是静态成员还是实例成员,那么这里它是实例成员,那是不是要用对象调用。也就是说我们要先创建Student类对象。其次之后再把它当成一个类看待,那么我要调用这个内部类中的实例方法是不是也要创建Phone类的对象。如是这样去创建:
package com.feisi.test;
import com.feisi.inner.*;
public class Test01 {
public static void main(String[] args) {
//Phone phone =new Phone();
//创建内部类Phone类的对象
Student.Phone phone=new Student().new Phone();
phone.call();
System.out.println("--------------------------");
//创建外部类Student类对象
Student student= new Student();
student.study();
}
}
3、代码运行结果是:
我们发现:
首先成功创建了内部类Phone类的对象,然后调用了属于内部类的成员方法:call()方法,输出在代码第一部分。
其次再创建了Student类对象,调用了属于外部类的成员方法:study()方法,首先输出"在学习",其次再接着在方法中new:又创建了Phone的对象,通过创建的Phone对象访问并调用了成员内部类Phone的成员变量并输出。输出在代码第二部分。
(5)如果Person内部类中的call()方法改成静态方法,那么我们会发现报错。
它要我们把Phone类变成一个static修饰的内部类,这是为啥呢?但是,它又开始报错:
它的提示错误是:Non-static field 'name' cannot be referenced from a static context :非静态字段“name”不能从静态上下文中引用。也就是我们知道的静态方法只能访问静态成员,非静态成员需要创建对象才能访问。而name和方法eat()都是外部类的非静态成员,所以外部类的部分成员变量和成员方法也要跟着分别改变成静态的成员变量才行。所以同理:当我们把内部类的call()方法变成静态方法时,那么它这个Phone类作为外部类Student的"成员"时,也要变成静态的类才行,不然不能存在我们的静态方法。所以修改如下:
public class Student{ //外部类
private static String name="张三"; //变成静态的成员变量
//中间的代码省略
public static class Phone{ //变成静态内部类
//中间的代码省略
public static void call(){ //变成静态的内部类成员方法
//中间代码省略
}
}
//外部类静态成员方法
public static void eat(){
System.out.println("吃饭中.....");
}
}
但是我们的测试类:Test01里面的创建Phone内部类的对象又出现了报错,是因为我们的内部类经过刚刚的修改,变成了static修饰的静态内部类,所以就需要进行的新的变化,这就是在(下)中会讲到的静态内部类。
(4)关于成员内部类的总结:
1、创建内部类对象的格式:(格式如下)
外部类名 外部类对象 = new 外部类名();
外部类名.内部类名 内部类对象 = 外部类对象.new 内部类名();
简化第一步(也就是合成):外部类名.内部类名 内部类对象 = new 外部类名().new 内部类名();
2、成员内部类可以访问外部类的所有成员,无论外部类的成员是何种访问权限。
3、如果想通过外部类访问内部类,则需要通过外部类去创建内部类的对象。(如果是在其他类去测试就是如上面的1方式一样。
4、其次也可以像上面另外一种情况:在外部类的成员方法中直接可以创建内部类的对象,就如:(Phone phone = new Phone(); 然后再通过phone引用,直接调用内部类Phone的成员变量或成员方法。),也就是说在外部类中可以通过创建的内部类对象,去访问内部类成员。
三、局部内部类
局部内部类,也称方法内部类:是指定义在某个局部范围中的类,它和局部变量都是在方法中定义的吗,有效范围只限于方法内部。
(1)下面我将创建一个Outer类(外部类)和它的成员方法test01()与成员方法test02()。
package com.feisi.inner;
public class Outer {
private String name01; //成员变量
public Outer(){
01="我是外部类成员变量";
}
public void test01(){
System.out.println("我是外部类成员方法");
}
public void test02(){
//在外部类的成员方法中定义一个局部内部类
class Inner{
private String name02="我是局部内部类的成员变量";
public void show(){
//在局部内部类中访问外部类的成员变量
System.out.println("访问外部类成员变量并输出:"+name01);
test01(); //在局部内部类中访问外部类的成员方法
}
}
Inner inner = new Inner();
//在局部内部类所属的方法中创建局部内部类的对象,通过对象访问局部内部类的变量和方法。
System.out.println("访问局部内部类的成员变量并输出:"+02);
inner.show();
}
}
(2)再创建一个测试类Test:
package com.feisi.test;
import com.feisi.inner.*;
public class Test {
public static void main(String[] args) {
Outer outer =new Outer();
outer.test02();
}
}
(3) 代码运行的结果如下:
此时我们发现: test01()它代表着Outer外部类的成员方法,它在方法体里输出"它的身份"。test02()它代表的是Outer外部类的另外一个成员方法,它里面有一个局部内部类叫Inner类,再在里面定义一个show()方法,它属于局部内部类的成员方法。在show()方法中先是访问外部类的成员变量"name01",并输出它。然后再调用了外部类的成员方法test01()。
最后的结果是这样的原因:是因为在测试类中创建了外部类Outer对象,然后调用它的成员方法test02(),然后它会先进入内部类直到创建内部类对象,然后再用内部类的对象inner去调用内部类的成员变量"name02"和内部类的show()成员方法。最后show()方法里会调用外部类成员变量"name01"和外部类成员方法test01()。
(4)总结:
1、局部内部类可以访问外部类的所有成员变量和成员方法,而在外部类中无法直接访问局部内部类中的变量和方法。
2、如果要在外部类中访问局部内部类的成员,只能在局部内部类的所属方法中创建局部内部类的对象,通过对象访问局部内部类的变量和方法。
四、静态内部类
(后面补充在(中)部分中)
五、匿名内部类
(后面补充在(下)部分中)