Java编程中的Native方法、this关键字及Swing框架介绍
1. Native方法
在Java编程中,虽然不常见,但有时你可能希望调用用非Java语言编写的子程序,这些子程序通常以本地代码的形式存在,也就是适用于你当前CPU和运行环境的可执行代码。例如,为了获得更快的执行时间,或者使用一些专门的第三方库(如统计软件包)。
然而,Java程序编译成字节码后,由Java运行时系统解释(或即时编译)执行,看起来似乎无法在Java程序中调用本地代码子程序。但实际上,Java提供了
native
关键字来声明本地代码方法。声明后,就可以像调用其他Java方法一样在Java程序中调用这些本地方法。
声明本地方法时,在方法前添加
native
修饰符,但不需要定义方法体。示例代码如下:
public native int meth();
声明本地方法后,需要提供本地方法的具体实现,并遵循一系列复杂的步骤将其与Java代码链接起来。
2.
this()
关键字的使用
在Java中,
this()
这种形式可以让一个构造函数调用同一个类中的另一个构造函数。其一般形式为:
this(arg-list)
当执行
this()
时,会先执行与
arg-list
参数列表匹配的重载构造函数。然后,如果原构造函数中有其他语句,再继续执行这些语句。需要注意的是,
this()
调用必须是构造函数中的第一条语句。
以下是一个简单的示例:
class MyClass {
int a;
int b;
// Initialize a and b individually.
MyClass(int i, int j) {
a = i;
b = j;
}
// Use this() to initialize a and b to the same value.
MyClass(int i) {
this(i, i); // invokes MyClass(i, i)
}
}
在
MyClass
类中,只有第一个构造函数会实际为
a
和
b
赋值,第二个构造函数只是调用了第一个构造函数。当执行以下语句时:
MyClass mc = new MyClass(8);
调用
MyClass(8)
会导致
this(8, 8)
被执行,进而转化为对
MyClass(8, 8)
的调用。
通过
this()
调用重载构造函数可以避免代码的不必要重复,但需要注意的是,调用
this()
的构造函数执行速度会比包含内联初始化代码的构造函数稍慢,因为调用和返回机制会增加额外的开销。如果类需要创建大量对象,就需要仔细权衡代码简洁性和对象创建时间的关系。
使用
this()
还有两个限制:
- 不能在
this()
调用中使用构造函数所在类的任何实例变量。
- 不能在同一个构造函数中同时使用
super()
和
this()
,因为它们都必须是构造函数中的第一条语句。
3. 相关问题与挑战
以下是一些相关的问题及挑战,可用于进一步巩固和拓展知识:
1. 当小程序首次开始运行时会调用什么方法?当小程序从系统中移除时会调用什么方法?
2. 解释为什么小程序如果需要持续运行就必须使用多线程。
3. 增强
Try This 15 - 1
,使其显示作为参数传递给它的字符串,并添加第二个参数指定每次旋转之间的时间延迟(以毫秒为单位)。
4. 额外挑战:创建一个小程序,每秒更新一次并显示当前时间。可以使用
java.util
包中的
Calendar
对象来获取当前时间。
5. 简要解释Java的委托事件模型。
6. 事件监听器必须向事件源注册自己吗?
7. 额外挑战:使用
Graphics
类的
drawLine()
方法编写一个程序来跟踪鼠标移动。当鼠标按钮按下时,程序应绘制一条连续的线,直到鼠标按钮释放。
8. 简要描述
assert
关键字。
9. 举例说明本地方法对某些类型的程序有什么用处。
10. 额外挑战:尝试为“使用委托事件模型”部分中的
MouseEvents
小程序添加对
MouseWheelEvent
的支持。需要实现
MouseWheelListener
接口,并使用
addMouseWheelListener()
将小程序添加为该事件的监听器。
4. Swing框架简介
4.1 Swing的重要性
除了之前提到的小程序示例,大多数Java程序都是基于控制台的,即不使用图形用户界面(GUI)。虽然基于控制台的程序对于学习Java基础知识和编写某些类型的程序(如服务器端代码)很有用,但大多数实际应用程序都是基于GUI的。目前,Swing是Java中使用最广泛的GUI框架。
Swing定义了一系列类和接口,支持丰富的可视化组件,如按钮、文本字段、滚动面板、复选框、树和表格等。这些组件可以组合使用,构建强大且易于使用的图形界面。因此,所有Java程序员都应该熟悉Swing。
4.2 Swing的起源和设计理念
Swing并非Java早期就存在的,它是为了解决Java原始GUI子系统——抽象窗口工具包(AWT)的不足而出现的。AWT定义了一组基本组件,支持可用但功能有限的图形界面。AWT组件将各种可视化组件转换为相应的特定平台对等物,这意味着AWT组件的外观和感觉由平台决定,而不是Java。由于AWT组件使用本地代码资源,被称为重量级组件。
使用本地对等物导致了一些问题:
- 不同操作系统之间,组件的外观甚至行为可能不同,这威胁到了Java“一次编写,到处运行”的理念。
- 每个组件的外观和感觉是固定的,难以(或无法轻松)更改。
- 重量级组件存在一些限制,例如总是不透明的。
为了解决这些问题,1997年引入了Swing,它是Java基础类(JFC)的一部分。最初,Swing作为一个单独的库供Java 1.1使用,从Java 1.2开始,Swing(以及JFC的其他部分)被完全集成到Java中。
Swing通过两个关键特性解决了AWT组件的局限性:轻量级组件和可插拔的外观和感觉。
-
轻量级组件
:除极少数情况外,Swing组件都是轻量级的,即完全用Java编写,不依赖特定平台的对等物。轻量级组件具有高效和灵活的优点,并且每个组件的外观和感觉由Swing决定,而不是底层操作系统,这使得每个组件在所有平台上都能以一致的方式工作。
-
可插拔的外观和感觉
:由于每个Swing组件由Java代码渲染,而不是特定平台的对等物,因此可以将组件的外观和感觉与组件的逻辑分离。Java提供了一些外观和感觉,如
metal
和
Nimbus
,其中
metal
也称为Java外观和感觉,是所有Java执行环境中都可用的平台独立外观和感觉,也是默认的外观和感觉。
Swing使用了改进版的经典模型 - 视图 - 控制器(MVC)架构,将视图和控制器组合成一个称为UI委托的逻辑实体,因此Swing的方法也被称为模型 - 委托架构或可分离模型架构。虽然在学习Swing的过程中可能不会直接使用模型或UI委托,但它们在背后起着重要作用。
4.3 Swing的组件和容器
Swing GUI由组件和容器两个关键部分组成,但这种区分主要是概念上的,因为所有容器也是组件。它们的区别在于用途:
-
组件
:通常指独立的可视化控件,如按钮、文本字段等。一般来说,Swing组件继承自
JComponent
类(四个顶级容器除外)。
JComponent
提供了所有组件共有的功能,如支持可插拔的外观和感觉,并且继承了AWT的
Container
和
Component
类,因此Swing组件基于AWT组件并与之兼容。所有Swing组件的类都定义在
javax.swing
包中,部分组件类名如下表所示:
| 组件类名 | 说明 |
| ---- | ---- |
|
JApplet
| 小程序 |
|
JButton
| 按钮 |
|
JCheckBox
| 复选框 |
|
JCheckBoxMenuItem
| 复选框菜单项 |
|
JColorChooser
| 颜色选择器 |
|
JComboBox
| 下拉框 |
|
JComponent
| 组件基类 |
|
JDesktopPane
| 桌面面板 |
|
JDialog
| 对话框 |
|
JEditorPane
| 编辑器面板 |
|
JFileChooser
| 文件选择器 |
|
JFormattedTextField
| 格式化文本字段 |
|
JFrame
| 窗口 |
|
JInternalFrame
| 内部窗口 |
|
JLabel
| 标签 |
|
JLayer
| 层 |
|
JLayeredPane
| 分层面板 |
|
JList
| 列表 |
|
JMenu
| 菜单 |
|
JMenuBar
| 菜单栏 |
|
JMenuItem
| 菜单项 |
|
JOptionPane
| 选项面板 |
|
JPanel
| 面板 |
|
JPasswordField
| 密码字段 |
|
JPopupMenu
| 弹出菜单 |
|
JProgressBar
| 进度条 |
|
JRadioButton
| 单选按钮 |
|
JRadioButtonMenuItem
| 单选菜单项 |
|
JRootPane
| 根面板 |
|
JScrollBar
| 滚动条 |
|
JScrollPane
| 滚动面板 |
|
JSeparator
| 分隔符 |
|
JSlider
| 滑块 |
|
JSpinner
| 微调器 |
|
JSplitPane
| 分割面板 |
|
JTabbedPane
| 选项卡面板 |
|
JTable
| 表格 |
|
JTextArea
| 文本区域 |
|
JTextField
| 文本字段 |
|
JTextPane
| 文本面板 |
|
JTogglebutton
| 切换按钮 |
|
JToolBar
| 工具栏 |
|
JToolTip
| 工具提示 |
|
JTree
| 树 |
|
JViewport
| 视口 |
|
JWindow
| 窗口 |
可以看到,所有组件类名都以字母
J
开头。本章主要介绍了五个常用的Swing组件:
JLabel
、
JButton
、
JTextField
、
JCheckBox
和
JList
。掌握它们的基本操作后,学习其他组件会更容易。
-
容器
:Swing定义了两种类型的容器。
-
顶级容器
:包括
JFrame、JApplet、JWindow和JDialog。这些容器不继承JComponent,但继承了AWT的Component和Container类。与其他Swing组件不同,顶级容器是重量级的,是Swing组件库中的特殊情况。顶级容器必须位于包含层次结构的顶部,不能包含在其他容器中,并且每个包含层次结构都必须从顶级容器开始。其中,JFrame常用于应用程序,JApplet用于小程序。 -
轻量级容器
:继承自
JComponent,如JPanel、JScrollPane和JRootPane。轻量级容器常用于组织和管理一组相关组件,因为它可以包含在其他容器中,从而可以创建包含在外部容器中的相关控件子组。
-
顶级容器
:包括
4.4 顶级容器的面板
每个顶级容器都定义了一组面板,层次结构的顶部是
JRootPane
实例。
JRootPane
是一个轻量级容器,用于管理其他面板,还可以帮助管理可选的菜单栏。组成根面板的面板包括玻璃面板、内容面板和分层面板。
-
玻璃面板
:是顶级面板,位于所有其他面板之上并完全覆盖它们。玻璃面板可用于管理影响整个容器的鼠标事件,或在其他组件上绘制图形等。在大多数情况下,不需要直接使用玻璃面板。
-
分层面板
:允许为组件指定深度值,该值决定哪个组件覆盖另一个组件(即可以为组件指定Z顺序,但通常不需要这样做)。分层面板包含内容面板和(可选)菜单栏。虽然玻璃面板和分层面板对顶级容器的操作至关重要,但它们的许多功能是在幕后实现的。
-
内容面板
:是应用程序与顶级容器交互最多的面板,因为要添加的可视化组件都添加到内容面板中。也就是说,当向顶级容器添加组件(如按钮)时,实际上是将其添加到内容面板中。因此,内容面板包含用户与之交互的组件。
综上所述,Swing虽然包含复杂的设计概念,但使用起来很方便,它使开发程序用户界面这一通常困难的任务变得易于管理,让开发者可以专注于GUI本身,而不是实现细节。同时,虽然Swing是一个强大的GUI框架,但新的GUI框架JavaFX也已出现,它提供了更强大、更简化和灵活的方法来创建视觉上令人兴奋的GUI,未来Java程序员可能会同时使用Swing和JavaFX。
5. Swing组件的使用示例
5.1 创建简单的Swing应用程序
下面是一个简单的Swing应用程序示例,展示了如何创建一个包含按钮的窗口:
import javax.swing.*;
public class SimpleSwingApp {
public static void main(String[] args) {
// 创建JFrame实例
JFrame frame = new JFrame("Simple Swing App");
// 设置窗口关闭时的操作
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 创建JButton实例
JButton button = new JButton("Click me");
// 获取内容面板
JPanel panel = new JPanel();
// 将按钮添加到面板
panel.add(button);
// 将面板添加到窗口的内容面板
frame.getContentPane().add(panel);
// 设置窗口大小
frame.setSize(300, 200);
// 显示窗口
frame.setVisible(true);
}
}
上述代码的执行流程如下:
1. 创建
JFrame
对象,这是一个顶级容器,用于表示窗口。
2. 设置窗口关闭时的操作,这里设置为退出程序。
3. 创建
JButton
对象,即按钮组件。
4. 创建
JPanel
对象,作为轻量级容器,用于组织组件。
5. 将按钮添加到面板,再将面板添加到窗口的内容面板。
6. 设置窗口大小并显示窗口。
5.2 使用JTextField和JLabel
以下示例展示了如何使用
JTextField
和
JLabel
组件:
import javax.swing.*;
import java.awt.*;
public class TextFieldLabelExample {
public static void main(String[] args) {
JFrame frame = new JFrame("TextField and Label Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JLabel label = new JLabel("Enter your name:");
JTextField textField = new JTextField(20);
frame.add(label);
frame.add(textField);
frame.setSize(300, 100);
frame.setVisible(true);
}
}
这个示例的操作步骤如下:
1. 创建
JFrame
并设置关闭操作和布局管理器。
2. 创建
JLabel
用于显示提示信息。
3. 创建
JTextField
用于用户输入,指定列数为20。
4. 将标签和文本字段添加到窗口。
5. 设置窗口大小并显示。
5.3 创建JCheckBox
下面是一个创建
JCheckBox
的示例:
import javax.swing.*;
import java.awt.*;
public class CheckBoxExample {
public static void main(String[] args) {
JFrame frame = new JFrame("CheckBox Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JCheckBox checkBox = new JCheckBox("Check me");
frame.add(checkBox);
frame.setSize(200, 100);
frame.setVisible(true);
}
}
操作步骤为:
1. 创建
JFrame
并设置相关属性。
2. 创建
JCheckBox
组件。
3. 将复选框添加到窗口。
4. 设置窗口大小并显示。
5.4 使用JList
以下是使用
JList
的示例:
import javax.swing.*;
import java.awt.*;
public class ListExample {
public static void main(String[] args) {
JFrame frame = new JFrame("List Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
String[] items = {"Item 1", "Item 2", "Item 3", "Item 4"};
JList<String> list = new JList<>(items);
frame.add(list);
frame.setSize(200, 200);
frame.setVisible(true);
}
}
其步骤如下:
1. 创建
JFrame
并设置属性。
2. 定义一个字符串数组作为列表项。
3. 创建
JList
并传入列表项数组。
4. 将列表添加到窗口。
5. 设置窗口大小并显示。
6. 事件处理
6.1 匿名内部类处理事件
在Swing中,可以使用匿名内部类来处理事件。以下是一个按钮点击事件处理的示例:
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
public class AnonymousInnerClassEventExample {
public static void main(String[] args) {
JFrame frame = new JFrame("Anonymous Inner Class Event Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JButton button = new JButton("Click me");
button.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(frame, "Button clicked!");
}
});
frame.add(button);
frame.setSize(200, 100);
frame.setVisible(true);
}
}
操作步骤:
1. 创建
JFrame
和
JButton
。
2. 为按钮添加
ActionListener
,使用匿名内部类实现
actionPerformed
方法。
3. 在
actionPerformed
方法中显示消息对话框。
4. 将按钮添加到窗口,设置窗口大小并显示。
6.2 Lambda表达式处理事件
从Java 8开始,也可以使用Lambda表达式处理事件,示例如下:
import javax.swing.*;
import java.awt.event.ActionEvent;
public class LambdaEventExample {
public static void main(String[] args) {
JFrame frame = new JFrame("Lambda Event Example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new FlowLayout());
JButton button = new JButton("Click me");
button.addActionListener((ActionEvent e) -> {
JOptionPane.showMessageDialog(frame, "Button clicked using Lambda!");
});
frame.add(button);
frame.setSize(200, 100);
frame.setVisible(true);
}
}
步骤如下:
1. 创建
JFrame
和
JButton
。
2. 为按钮添加
ActionListener
,使用Lambda表达式实现事件处理逻辑。
3. 将按钮添加到窗口,设置窗口大小并显示。
7. Swing Applet
创建Swing Applet与创建普通Swing应用程序类似,但需要继承
JApplet
类。以下是一个简单的Swing Applet示例:
import javax.swing.*;
import java.awt.*;
public class SwingAppletExample extends JApplet {
@Override
public void init() {
try {
SwingUtilities.invokeAndWait(() -> {
setLayout(new FlowLayout());
JLabel label = new JLabel("This is a Swing Applet!");
add(label);
});
} catch (Exception e) {
e.printStackTrace();
}
}
}
操作步骤:
1. 继承
JApplet
类。
2. 重写
init
方法。
3. 在
init
方法中使用
SwingUtilities.invokeAndWait
确保在事件调度线程中执行UI操作。
4. 设置布局管理器,创建
JLabel
并添加到Applet。
8. 总结
8.1 Swing的优势
- 丰富的组件 :Swing提供了大量的可视化组件,如按钮、文本字段、复选框等,可以方便地构建各种复杂的GUI界面。
- 可移植性 :轻量级组件使得Swing应用程序在不同平台上具有一致的外观和行为,符合Java“一次编写,到处运行”的理念。
- 可插拔外观和感觉 :可以轻松更改组件的外观和感觉,满足不同用户的需求。
- 事件处理机制 :支持多种事件处理方式,如匿名内部类和Lambda表达式,方便开发者处理用户交互。
8.2 与其他GUI框架的比较
虽然Swing是一个成熟且广泛使用的GUI框架,但新的JavaFX框架也有其优势。JavaFX提供了更强大、更简化和灵活的方法来创建视觉上令人兴奋的GUI,并且在动画、多媒体等方面有更好的支持。不过,由于Swing存在大量的遗留代码,在未来一段时间内,两者可能会同时存在于Java开发中。
8.3 学习建议
对于初学者来说,建议先掌握Swing的基础知识,包括组件的使用、布局管理器、事件处理等。可以通过阅读相关文档、参考示例代码和进行实践项目来逐步提高。随着对Swing的熟悉,可以进一步学习JavaFX,了解其新特性和优势,为开发更复杂的应用程序做好准备。
8.4 后续展望
随着Java技术的不断发展,GUI框架也会不断演进。未来可能会出现更高效、更易用的GUI开发方式,开发者需要持续学习和关注新技术的发展,以适应不断变化的市场需求。
以下是一个简单的Swing开发流程的mermaid流程图:
graph LR
A[创建顶级容器] --> B[设置布局管理器]
B --> C[创建组件]
C --> D[添加组件到容器]
D --> E[设置事件处理]
E --> F[显示窗口或Applet]
总之,Swing是Java开发中一个重要的GUI框架,掌握它对于开发实际应用程序具有重要意义。同时,了解其他GUI框架的发展趋势,也有助于开发者在不同场景下做出更合适的选择。
超级会员免费看
1488

被折叠的 条评论
为什么被折叠?



