CSDN出品:搞懂Java模糊概念,深入剖析匿名内联类等内容

原文:

CSDN出品:搞懂Java模糊概念,深入剖析匿名内联类等内容

译者是弯月,责编为屠敏,由 CSDN(ID:CSDNnews)出品。

每个人大概在学生时代就开始使用 Java 了。我们一直都在学习 Java 。然而,Java 中存在一些概念是含混不清的。无论是对初级程序员还是高级程序员来说,都是这样的情况。所以,这篇文章的目的就是要把这些概念弄清楚。

读完本文,你能对这些概念有更深入的认知,也能弄明白所有灰色的事物。在本书里,我们会对匿名内联类、多线程、同步以及序列化进行讨论。

匿名类

Java 匿名类与局部类或内联类较为相似,只是它没有名字。我们能够借助匿名类,既定义一个类又对其进行实例化。只有在局部类仅被使用一次的情况下,才应当采取这种做法。

匿名类不可以有明确给出的构造函数。与之相反,每一个匿名类都在暗中定义了一个匿名构造函数。

创建匿名类有两种方法:

扩展已有的类(可以是抽象类,也可以是具体类)创建接口

理解代码的最好方法就是先阅读,所以我们首先来看看代码。

匿名类能够在类和函数的代码块中被创建。你知晓,匿名类既可以借助接口来创建,又可以通过对抽象类或具体类进行扩展来创建。在上例当中,我首先创建了一个名为 Football 的接口,接着在类的作用域以及 main()方法内部实现了匿名类。Football 既可以是抽象类,也可以是与 interface 处于同等地位的顶层类。

Football可以是抽象类,请看下面的代码。

具有抽象特征的 Football 类。
{ 
 abstract void kick();
}

匿名类不仅可以是抽象类,还可以是具体类。

// normal or concrete class
public class Football 
{ public void kick(){}
}// end of class scope.

如果 Football 类不存在不带参数的构造方法,那该怎么办呢?我们是否能够在匿名类里访问类变量呢?我们是否有必要在匿名类中重载所有的方法呢?

创建匿名类时能够使用各种构造方法。需注意这里也运用了构造方法的参数。匿名类能够对顶层类进行扩展,还能实现抽象类或接口。因此,访问控制的规则依旧适用。我们可以访问 protected 变量,但若改成 private 则无法访问。因为上述代码中扩展了 Football 类,所以不需要重载所有方法。匿名类可以有静态成员变量,并且这些静态成员变量必须是常量。

匿名类的用途:

UI 事件监听器:在图形界面的应用程序里,匿名类最常见的用途是创建各种事件处理器。例如,像下面这样的代码:

button 设定了点击事件监听器,该监听器是一个新创建的 View.OnClickListener 实例,通过这种方式来处理按钮的点击操作。
 public void onClick(View v) {
 // your handler code here
 }
 });

我们创建了一个类,这个类是匿名类。它实现了 setOnClickListener 接口。当用户点击按钮的时候,就会引发这个类的 onClick 方法。

多线程

Java 中的多线程具备同时执行多个线程的能力。线程属于轻量级的子进程,并且是处理的最小单位。使用多线程的主要目标是将 CPU 的使用率最大化。我们会选择使用多线程而非多进程,原因在于线程更加轻量化,并且能够共享同一个进程内的内存空间。多线程被用于实现多任务。

线程的生命周期

如上图所呈现的那样,线程的整个生命历程主要包含 5 种状态。接下来我们逐一对每个状态进行解释。

创建线程的实例后,其会处于 new 状态,这是初始状态,然而此时线程尚未准备好运行。当调用线程类的 start()方法时,状态会从 new 转变为 Runnable,这表明线程可以运行了,但实际上其开始运行的时间取决于 Java 线程调度器,因为调度器可能正忙于执行其他线程。线程调度器会从线程池中以 FIFO(先进先出)的方式挑选一个线程。Blocked 状态的情况有很多,比如等待 I/O 操作,或者等待网络连接等。并且,优先级较高的线程能够使当前正在运行的线程变为 Blocked 状态。Waiting 状态时,线程可以调用 wait()来进入该状态。当其他线程调用 notify() 这个方法时,线程会回到 runnable 状态。当 start() 方法退出的时候,线程就会进入 terminated 状态。

为什么使用多线程?

Java 应用程序使用线程能够同时进行多件事情,以此加快运行速度。从技术层面来讲,线程可以在 Java 程序里实现并行操作。因为现代的 CPU 速度很快,并且可能包含多个核心,所以仅拥有一个线程就无法使用所有的核心。

需要记住的要点

创建线程的方法主要有两种:

扩展Thread类实现Runnable接口

通过扩展Thread类来创建线程

创建一个类去扩展 Thread 类。这个类需要重载 Thread 类里的 run()方法。线程是在 run()方法中开始其生命周期的。我们创建新类的对象,接着调用 start()方法来让线程开始执行。在 Thread 对象中,start()会去调用 run()。

也可以通过接口创建类。

以下代码创建了一个类,此类别实现了 java.lang.Runnable 接口并且重载了 run() 方法。接着我们创建了一个 Thread 对象的实例,并且调用该对象的 start() 方法。

Thread类与Runnable接口

同步

同步指的是多线程的同步情况。synchronized 的代码块在某一特定时刻仅能被一个线程执行。Java 中同步是个极为重要的概念,原因在于 Java 是多线程语言,多个线程能够并行执行。在多线程的环境里,Java 对象的同步以及 Java 类的同步都非常关键。

为什么要同步?

如果代码是在多线程的环境里执行的,那么在多个线程当中共享的那些对象之间就需要进行同步。这样做是为了避免破坏状态,同时也能避免造成任何难以预料的行为。

在深入同步的概念之前先来理解一下这个问题。

class Table {
定义一个名为 printTable 的方法,该方法接受一个整数参数 n。此方法未进行同步处理。
 for (int i = 1; i <= 5; i++) {
 System.out.print(n * i+" ");
 try {
 Thread.sleep(400);
 } catch (Exception e) {
 System.out.println(e);
 }
 }
 }
}
class MyThread1 extends Thread {
 Table t;
 MyThread1(Table t) {
 this.t = t;
 }
 public void run() {
 t.printTable(5);
 }
}
class MyThread2 extends Thread {
 Table t;
 MyThread2(Table t) {
 this.t = t;
 }
 public void run() {
 t.printTable(100);
 }
}
class TestSynchronization1 {
 public static void main(String args[]) {
 Table obj = new Table();//only one object 
 MyThread1 t1 = new MyThread1(obj);
 MyThread2 t2 = new MyThread2(obj);
 t1.start();
 t2.start();
 }
}

运行这段代码后,会注意到输出结果很不稳定,原因是没有进行同步。接下来我们来看一下程序的输出。

输出:

100 有 5 个,200 有 10 个,300 有 15 个,20 有 400 个,500 有 25 个。

给 printTable()方法加上 synchronized 后,synchronized 的方法在执行结束之前,不会让其他线程进入。这样一来,下面的输出结果就会非常稳定。

输出:

10 之后依次是 15、20、25,接着有 100、200、300、400、500 ,还有 5 和 20 。

类似地,Java的类和对象也可以同步。

我们并非一定要同步整个方法。有时最好只是同步方法的一小部分。Java 的 synchronized 代码段能够做到这一点。

序列化

Java 中的序列化这一机制,能够把对象的状态写入到字节流当中。与之相反的操作被称作反序列化,它可以把字节流转变为对象。

序列化的过程是平台无关的,在一个平台上可以进行对象的序列化。反序列化的过程也是平台无关的,在另一个平台上可以对之前序列化的对象进行反序列化。

在进行序列化操作时,会调用 ObjectOutputStream 的 writeObject()方法;而在进行反序列化操作时,会调用 ObjectInputStream 类的 readObject()方法。

下图中,Java 对象会被转化为字节流,接着被存储在各种形式的存储里,此过程被称作序列化。在图的右侧,内存里的字节流会被转化为 Java 对象,这个过程叫做反序列化。

为什么要序列化

显然,在程序执行结束或中止后,创建的 Java 类中的对象会被销毁。为避免此问题,Java 提供了序列化功能。利用该功能,能够将对象存储起来,也能够将对象的状态进行持久化,以便后续使用,或者在其他平台上使用。

下面的代码演示了该过程。

输出:

输出:

从 Employee.ser 文件中恢复序列化数据。
Name of employee is : Aman
Salary of employee is : 0

需要记住的重点

如果父类实现了 Serializable 接口,那么子类无需再实现。不过,反过来的情况并非必然成立。在序列化过程中,只有非静态数据成员能够被保存下来。而静态数据成员以及临时数据成员不会被保存。因此,倘若不想保存某个非静态数据成员,就可以将其设置为 transient。在反序列化过程中,不会调用对象的构造函数。关联对象必须实现Serializable接口。

总结

1、首先我们解释了匿名类,以及用途和使用方法。

其次我们对 Java 中的多线程进行了讨论,包括线程的生命周期以及其用途。

同步有这样的规定,只允许一个线程能够进入到同步的方法或者代码块中去访问资源,而其他的线程就必须在队列里等待着。

4、序列化就是存储对象状态供以后使用的过程。

你可能想看:
« 上一篇
下一篇 »

相关推荐

java中什么是冒泡,冒泡算法

2026年09月06日

27阅读

java中冒号,java双冒号

2026年09月06日

26阅读

java中的->,java中的是什么意思

2026年09月06日

24阅读

java中的super用法,Java中super的说明

2026年09月06日

28阅读

java中反射的应用,java中反射的应用场景

2026年09月06日

25阅读

java中开关的定义,Java关键字有哪些

2026年09月06日

25阅读