Logo

郎哥编程

内部、局部和匿名类

2021-06-30 244

学习目标:掌握内部类、局部类和匿名类的创建和使用方法。

内部类

在类的内部定义的类称为内部类,根据内部类定义的位置可分为成员内部类、和局部内部类。本节主要学习成员内部类。

创建一个类时,会定义类的成员变量和成员方法。成员变量的类型可以是基本数据类型,也可以是对象引用类型。对象引用类型一般指向同一包的类或从外部导入的类。

Java语言也允许在类的内部定义一个类,该类可以作为外部类(为了区分内部类和定义内部类的类,将定义内部类的类称为外部类)的成员变量。

定义内部类

定义内部类的语法如下:

public class  外部类名称 {

    …………

   

    public class 内部类名称 {

       …………

    }

    …………

}

在内部类可以随意访问外部类的成员变量和成员方法,访问权限不受限制。

案例4:建立Student类(学生类),在Student类内部定义Relation类(联系方式类)。

在PUnit8项目新建student包,在student包下新建Student类。代码如下:

package student;
public class Student {
    // 定义成员变量name
    String  name;
    // 定义内部类Relation
    public class Relation {
        // 定义成员变量phone
        public String phone;
        // 定义成员变量email
        public String email;
        // 定义构造方法
        public Relation(String phone, String email)
        {
            this.phone = phone;
            this.email = email;
        }
    }
}

内部类的定义方式和外部类的定义方式完全相同,权限修饰符同样适用于内部类。在Student类内部定义了Relation类,Relation类定义了两个成员变量和一个构造方法,构造方法用于初始化成员变量。

内部类在外部类的使用

内部类可以作为外部类的成员变量使用,当外部类实例化对象时,内部类也要实例化,内部类实例化的对象会绑定在外部类对象上。内部类的实例化方式与其它类实例化方式相同,都是使用new运算符。

案例5:在Student类定义一个Relation类型的成员变量,并在Student类的构造方法中实例化该成员变量。

修改Student类的代码:

package student;
public class Student {
    // 定义成员变量name
    String  name;
    // 定义Relation类型的成员变量
    Relation  relation;
    // 构造函数
    public Student(String name,String phone,String email)
    {
        this.name = name;
        relation = new Relation(phone,email);
    }
 
    // 定义内部类Relation
    public class Relation {
        // 定义成员变量phone
        public String phone;
        // 定义成员变量email
        public String email;
        // 定义构造方法
        public Relation(String phone, String email)
        {
            this.phone = phone;
            this.email = email;
        }
    }
}

外部类访问内部类

外部类不能直接访问内部类的成员变量和方法,这是因为内部类的成员变量和方法是在内部类定义的,使用范围也仅限于内部类。外部类可以通过在外部类定义的Relation对象引用来访问内部类的成员变量和方法。

案例6:在Student类定义一个show()方法,该方法输出学生姓名、联系电话和邮箱。

修改Student类的代码:

// 定义show()方法

    public void show()

    {

       System.out.printf("姓名:%s\n",this.name);

       System.out.printf("电话:%s\n",this.relation.phone);

       System.out.printf("邮箱:%s\n",this.relation.email);

}

Student类在原来代码的基础上,添加了show()方法,该方法输出学生姓名、联系电话和邮箱。Student类通过对象引用relation来访问内部类的成员变量和方法。

其它类访问内部类

内部类实例化的对象会绑定在外部类对象上,因此其它类在外部类对象作用范围内,也可以访问内部类的实例化对象。

局部内部类

局部内部类是指在外部类的方法内定义的类,由于内部类在外部类的方法内定义,内部类的生命周期会随着方法的生命周期结束而结束。因此内部类的作用范围仅限于方法内,在方法的外部不能访问该内部类。

案例7:新建一个Teacher类,在Teacher类的teaching()方法内部定义一个内部类Course(课程类)。

在PUnit8项目student包内新建Teacher类。代码如下:

package student;
public class Teacher {
    // 定义teaching()方法
    public String teaching(String courseName)
    {
        //定义内部类
        class Course {
            String courseName;
            public Course(String courseName)
            {
                this.courseName = courseName;
            }
            String getCourseTime()
            {
                return "每周五上午9点上课";
            }
        }
        // 实例化Course对象
        Course course = new Course(courseName);
        return course.getCourseTime();
    }
}

在Teacher 类的teaching()方法内部定义了Course类,用于获取课程的上课安排时间。Course类需要传入课程名称,并对外提供了getCourseTime()方法,返回传入课程名称的上课安排时间。

需要注意的是,局部内部类的成员变量和方法不能使用访问权限符修饰。因为方法外部的代码无法访问内部类。

案例8:建立TeacherTest类,实例化Teacher 对象,并调用Teacher 对象teaching()方法获取课程的上课安排时间。

在PUnit8项目student包内新建TeacherTest类。代码如下:

package student;
public class TeacherTest {
    public static void main(String[] args) {
        // 实例化Teacher对象
        Teacher  teacher = new Teacher();
        // 输出课程安排时间
        System.out.println("体育课上课安排:" + teacher.teaching("体育"));
    }
}

匿名对象和匿名类

匿名对象

实例化一个对象的语句一般是类似下面的代码:

Person person = new  Person();

其中Person是类的名称,person是实例化对象的名称,new运算符为对象分配存储空间,并返回对象的引用赋值给person。

假如在A类内部定义了一个tell()方法,tell()方法需要传入Person对象,该方法的声明如下:

tell(Person person);

调用A类的tell()方法时,传递person对象有两种方法。

第一种方法:

Person person = new  Person();
tell(person);

第二种方法:

tell(new Person());

第二种方法的new Person()创建的对象就是一个匿名对象,这个对象没有具体的名称,并没有赋值给一个具体的变量。

匿名类

匿名类是指没有类名的内部类,匿名类可以继承一个给定的类,或者实现一个给定的接口。使用new运算符来创建匿名类。创建匿名类的语法如下:

new 类名称/接口名称()

{

    //类的主体

};

new运算符后面的“类名称/接口名称”可以是新定义类的名称、也可以是已有类的名称、也可以是要实现的接口名称。如果是新定义类的名称,new运算符会创建一个新的类并返回该类的对象引用;如果是已有类的名称,new运算符会创建一个已有类的子类;如果是接口名称,new运算符会创建一个实现该接口的类。

案例9:建立一个InfoEnter接口(学生信息录入接口),接口提供学生信息录入方法enter()。然后建立StudentManager类(学生信息管理类),在StudentManager类应用匿名类实现InfoEnter接口。

在PUnit8项目student包内新建InfoEnter接口。代码如下:

package student;
public interface InfoEnter {
    // 学生信息录入接口
    public void enter();
}

InfoEnter接口提供了enter()方法,用于学生信息的录入。

在student包内新建StudentManager类,在StudentManager类应用匿名类实现InfoEnter接口。代码如下:

package student;
 
public class StudentManager {
    // 实现InfoEnter接口
    public InfoEnter  infoenter = new InfoEnter() {
        @Override
        public void enter() {
            System.out.println("正在输入学生信息…………");
        }
 
    };
}

在StudentManager类内部使用new运算符创建了一个匿名类,该匿名类实现了InfoEnter接口,匿名类的对象引用赋值给InfoEnter类型的成员变量infoenter。

在student包内新建StudentManagerTest类,测试StudentManager类。代码如下:

package student;
public class StudentManagerTest {
    public static void main(String[] args) {
        // 实例化StudentManager对象
        StudentManager  manager = new StudentManager();
        // 调用接口的enter()方法
        manager.infoenter.enter();
 
    }
}

代码在线纠错(通义千问 qwen-max)

支持粘贴多个代码文件,提交后由阿里云通义千问自动分析代码漏洞、语法错误、逻辑问题并给出修改建议。
您已解锁 AI 代码纠错功能,可正常使用!

评论区

登录 后发表评论
暂无评论