首页 > 编程语言 >第八章《Java高级语法》第6节:匿名类

第八章《Java高级语法》第6节:匿名类

时间:2022-12-31 11:31:14浏览次数:76  
标签:Java 定义 构造方法 创建 08 第八章 匿名 public

​所谓匿名类就是没有名称的类,Java语言允许把一个类的子类定义成匿名类。很多读者都会有疑问:定义一个类的时候必须要写上类的名称,没有名称怎么能定义出一个类呢?下面的【例08_17】展示了如何把一个类的子类定义成匿名类。

【例08_17 定义匿名类】

A.java​

public abstract class A{
public abstract void pirnt();
}

Exam08_17.java​

public class Exam08_17 {
public static void main(String[] args) {
//奇怪代码从下一行开始
A a = new A()
{//①
public void pirnt() {
System.out.println("Hello");
}
};//②
//奇怪代码到上一行结束
a.pirnt();
}
}

在【例08_17】中出现了一段很奇怪的代码,为了方便读者快速找到它,注释中特意标出了奇怪代码的位置。下面就来解释一下这段奇怪的代码是什么意思。我们都知道:定义一个类需要一对大括号,类的属性和方法都被定义在这对大括号当中。在奇怪代码中,被标记为①和②的那对大括号之间定义了一个完整的print()方法。因为方法只能被定义到类当中,所以被标记为①和②的那对大括号其实就是用来定义类的那对大括号。可以看到:这对大括号的前面没有类的名称,所以由这对大括号所定义的类其实就是一个匿名类。​

在标记为①的大括号上面一行出现了“new A()”,这也是一个很奇怪的操作。因为按照之前所学的知识来理解,“new A()”的作用是创建一个A类的对象。但A是一个抽象类,Java语言根本就不允许抽象类创建对象,那么“new A()”到底起什么作用呢?其实代码中“new A()”所创建的并不是抽象类A的对象,而是创建了那个匿名类的对象。可是创建匿名类对象为什么要用A的构造方法呢?Java语言中,构造方法的名称与类的名称相同,而匿名类根本没有名称,所以它也没有构造方法,没有构造方法就无法创建对象。为了解决匿名类无法创建对象的问题,Java语言规定:匿名类创建对象时要借助它父类的构造方法来完成。匿名类前面调用了哪个类的构造方法,匿名类就自动成为这个类的子类,不需要用extends关键字作特别声明。所以“new A()”出现在匿名类之前能起到两个作用:一、表明A是匿名类的父类,二、创建出一个匿名类的对象。​

虽然定义匿名类的操作出现在创建对象的操作之后,但是虚拟机在执行代码时,是先定义出匿名类,然后再创建它的对象。很多读者都会问:为什么要把定义匿名类的操作和创建它对象的操作放在同一条语句中执行呢?就是因为匿名类没有构造方法,我们也就无法在程序的其他位置调用它的构造方法来创建对象,因此只能在定义这个匿名类的同时就把它的对象创建出来,并且创建对象的操作还要借助父类的构造方法才能完成。​

弄清楚这一系列问题之后,我们现在就可以重新解读一下【例08_17】中这段奇怪的代码。这段代码的含义是:定义了一个A的匿名子类,在这个匿名子类中实现了A类的抽象方法print(),并且在定义这个匿名子类的同时创建出了它的对象。由于定义匿名类和创建它的对象是在同一条语句中完成的,所以直到在代码的最后才出现了表示语句结束的分号。读者亲自可以运行一下【例08_17】,可以看到运行结果是:在控制台上输出了“Hello”,这也足以证明通过“new A()”所创建出的并不是A类的对象,而是它匿名子类的对象。因为抽象类A根本没有实现print()方法,只有在它匿名子类中重写过的print()方法中才会输出“Hello”。​

定义匿名类的语法格式很冗长也很奇怪,初学者往往一开始都不习惯这种语法格式。从JDK1.8开始,Java语言引入了一种叫做Lambda表达式的语法格式,通过这种格式能够对特定形态的匿名类实现简化定义,本章的8.12小节将专门介绍Lambda表达式的相关知识。​

通过【例08_17】的代码以及对代码的解读可以总结出匿名类具有以下特点。​

(1)匿名类在被定义时同时要创建对象。​

(2)匿名类都是以子类或实现类的形式出现的。​

(3)一个匿名类只能创建一个对象。​

(4)匿名类必然是内部类。​

这4个特点中,前3个都比较好理解,第4个特点需要稍加解释。因为匿名类在被定义时必须同时创建出它的对象,换句话说:定义匿名类和创建它的对象是在同一条语句中完成的,而创建对象的语句只能出现在某一个类当中,所以可以肯定:匿名类也是在某个类中被定义的,它一定是一个内部类。​

在【例08_17】中,当创建匿名类对象时调用了父类A的无参数构造方法。其实,如果匿名类的父类有多个造方法,在创建匿名类对象时可以调用父类的任何一个构造方法。下面的【例08_18】展示了如何调用父类有参数的构造方法来创建匿名类对象。​

【例08_18 调用父类有参数构造方法创建匿名类对象】

A.java​

public abstract class A{
int x ;
public A() {

}
public A(int x) {
this.x = x;
}
public abstract void pirnt();
}

Exam08_18.java​

public class Exam08_18 {
public static void main(String[] args) {
A a = new A(3)//调用有参数的构造方法创建匿名类对象
{
public void pirnt() {
System.out.println("x的值为:"+x);
}
};
a.pirnt();
}
}

【例08_18】修改了【例08_17】中抽象类A的源代码,为它增加了一个int型属性x以及一个有参数的构造方法,在main()方法中创建匿名类对象时就调用了A类有参数的构造方法。main()方法中定义的匿名类中实现了print()方法,但本例中实现的print()方法不是输出“Hello”,而是输出了匿名类继承而来的x属性。读者可以自行运行【例08_18】并观察运行结果。​

通过学习,各位读者可以发现匿名类使用起来并不方便。它没有构造方法,所以不能通过构造方法来完成初始化属性的操作,同时也不能在程序的任意位置创建对象。既然有这么多缺陷, Java语言为什么还要设计出匿名类这种奇怪的东西呢?其实,匿名类使用起来虽然不方便,但它有两大特点:首先匿名类是内部类,这决定了它可以很容易的访问其包围类的属性。其次,匿名类没有名称,这导致它不能被随意的、反复的创建对象,但这也恰好保证了匿名类对象中的方法不能被随意调用,这样能够大大提高代码的安全性。正是因为匿名类有这些特点,在实际开发中,监听器以及执行并行任务的线程往往都是用匿名类对象来实现的。关于监听器、线程等知识将在本书后面的章节中进行讲解。

除此文字版教程外,小伙伴们还可以点击这里观看我在本站的视频课程学习Java。

标签:Java,定义,构造方法,创建,08,第八章,匿名,public
From: https://blog.51cto.com/mugexuetang/5982079

相关文章