Map接口
Map接口
-
Map是Java中用于存储键值对
(key-value pairs)
的接口,每个键(key)
对应一个值(value)
。它不允许重复的键,但允许不同的键映射相同的值。 -
关键特点:
-
键值对存储:每个
key
对应一个值,使用key
来获取对应的值; -
不允许重复
key
:一个key
只能存在一次,重复key
会覆盖旧值; -
常用实现类:
HashMap
、TreeMap
、LinkedHashMap
等。
-
-
常用方法:
-
put(K key, V value)
:插入键值对; -
get(Object key)
:根据key获取对应的值; -
remove(Object key)
:根据key删除对应的键值对; -
containsKey(Object key)
:检查是否包含指定key; -
keySet()
:返回所有key的集合。
-
-
Map
是一个非常灵活的接口,广泛用于需要通过唯一key
快速访问数据的场景。
package Day21;
import java.util.HashMap;
import java.util.Map;
/**
* java.util.Map 查找表
*/
public class MapDemo1 {
public static void main(String[] args) {
// Map创建时要分别指定key和value的类型
Map<String, Integer> map = new HashMap<>();
/*
put(K k, V v):返回一个value值
向Map中保存一组键值对
由于Map要求key不允许重复,如果使用重复的key存入新的value,那么则是替换value操作,
如果此Map中不包含该key的映射关系,则返回null。
此时put方法会把被替换下来的value返回。否则返回值为null。
*/
Integer value = map.put("语文", 100);
System.out.println(value);
map.put("数学", 100);
map.put("外语", 100);
map.put("物理", 100);
map.put("化学", 100);
System.out.println(map);
value = map.put("语文", 66); // 会将“语文”原本的99替换掉
System.out.println(value); // 99
System.out.println(map);
// int valuePoint = map.put("语文", 100);
// System.out.println(valuePoint); // 空指针异常
System.out.println("");
/**
* get(Object key) 返回value类型
* 根据给定的key提取对应的value
* 如果给定的key在Map中不存在则返回值为null
*/
value = map.get("语文");
System.out.println(value);
value = map.get("体育");
System.out.println(value);
System.out.println("");
/**
* size(): 返回int类型
* 返回Map中键值对的个数
*/
int size = map.size();
System.out.println("size=" + size);
System.out.println("");
/**
* remove() 返回value类型
* 根据给定的key删除对应的键值对,并且会将该key对应的value返回
*/
value = map.remove("数学");
System.out.println(value); // 数学对应的value值:98
System.out.println(map);
System.out.println("");
/**
* isEmpty() 返回boolean类型
* 检查是否为空Map(Map中不含有任何键值对)
*/
boolean isEmpty = map.isEmpty();
System.out.println("是否为空Map" + isEmpty);
System.out.println("");
/**
* containsKey(key) 返回boolean类型
* containsValue(Value) 返回boolean类型
* 判断Map中是否包含指定的key或value
* 底层还是利用equals方法比较
*/
boolean containsKey = map.containsKey("语文");
System.out.println("是否包含key:" + containsKey);
boolean containsValue = map.containsValue(100);
System.out.println("是否包含value:" + containsValue);
System.out.println("");
/**
* clear()
* 清空Map
*/
map.clear();
System.out.println(map);
}
}
Map的遍历
常用实现类
-
遍历<key,value>:
-
使用
entrySet()
方法,获取键值对的集合。 -
示例:
package Day21; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo2 { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("语文", 100); map.put("数学", 90); map.put("英语", 80); map.put("化学", 100); map.put("物理", 100); System.out.println(map); /** * entrySet() 返回所有的键值对 * 将当前Map中所有的键值对以若干的Entry实例表示,并将他们以一个Set集合的形式返回 */ Set<Map.Entry<String, Integer>> entrySet = map.entrySet(); for (Map.Entry<String, Integer> entry : entrySet) { System.out.println("entry:" + entry); } } }
-
-
遍历key:
-
使用
keySet()
方法,获取键的集合。 -
示例:
package Day21; import java.util.HashMap; import java.util.Map; import java.util.Set; public class MapDemo2 { public static void main(String[] args) { Map<String, Integer> map = new HashMap<>(); map.put("语文", 100); map.put("数学", 90); map.put("英语", 80); map.put("化学", 100); map.put("物理", 100); System.out.println(map); /** * keySet() 返回所有的key * 将当前Map中所有的key以一个Set集合的形式返回 */ Set<String> keySet = map.keySet(); for (String key : keySet) { System.out.println("key:" + key); } } }
-
-
遍历value:
-
使用
values()
方法,获取所有值的集合。 -
示例:
for (V value : map.values()) { // 处理值 }
-
forEach方法
-
forEach
方法forEach
是 Java 8 引入的一个方法,用于遍历集合或流中的每个元素,通常与 Lambda 表达式结合使用。
-
用法示例
List<String> list = Arrays.asList("a", "b", "c"); // 使用 forEach 方法遍历列表 list.forEach(element -> { System.out.println(element); });
-
关键特点
-
简洁:用 Lambda 表达式直接在遍历时定义要执行的操作。
-
灵活:可以传递方法引用,如
list.forEach(System.out::println);
。 -
适用范围:适用于所有实现了
Iterable
接口的集合,如List
、Set
,以及Stream
流。 -
forEach
方法简化了遍历过程,特别适合在函数式编程风格中使用。
-
小练习
package Day21;
import java.util.HashMap;
import java.util.Map;
/**
* 编写程序,统计字符串中每个字符出现的次数
*/
public class Test {
public static void main(String[] args) {
/*
输出的结果,要求看到每个字符出现的次数。
例如
h:2
e:2
l:4
xx:xx
思路:
1:创建一个Map用来保存统计结果
key:出现的每种字符 value:该字符出现的次数
2:
2.1:遍历line中的每一个字符
String有一个方法:charAt(int index) 根据下标提取对应的元素
下标范围:0-字符串的length
2.2:将该字符作为key存入到map中,这是会有两种情况
Map的containsKey()方法
2.2.1:如果这个字符作为key在map中不存在,将字符作为key,value存入1(第一次出现)
2.2.3:如果该字符作为key在map中存在,说明该字符之前出现过,此时将value+1
2.3:遍历完毕相当于统计完毕,将map输出看结果即可
注意:char类型对应的包装类是Character
*/
String line = "Patiention! Is key in life! Just be patient!";
Map<Character, Integer> map = new HashMap<>();
for (int i = 0; i < line.length(); i++) {
char c = line.charAt(i);
if (map.containsKey(c)) {
map.put(c, map.get(c) + 1);
} else {
map.put(c, 1);
}
}
System.out.println(map);
}
}
聊天室v3.0
Client.java
package Day21;
import java.io.*;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.Scanner;
/**
* 客户端
*/
public class Client {
/**
* java.net.Socket:套接字
* 它封装了TCP协议的通信细节,使用它可以和服务器建立连接并进行交互
* 可以理解为是电话
*/
private Socket socket;
public Client() {
// 实例化Socket对象,就是与远端计算机建立连接的过程
// 需要传递两个对数:
// 1.远端计算机的IP地址,用于找到网络上对方的计算机
// 2.远端计算机的端口号,用于找到对方计算机中的应用程序
try {
System.out.println("正在连接服务端......");
/**
实例化Socket对象,就是与远端计算机建立连接的过程
需要传入两个对数:
1.服务端的IP地址,用于找到网络上对方的计算机
2.服务端口,用于找到服务端计算机上的应用程序
查看IP操作:
Windows: win+r,输入cmd,回车,输入ipconfig,IPv4就是IP地址
Mac:触控板上五指向中间抓,选择"终端"程序打开,输入/sbin/ifconfig查看IP地址
创建Socket对象向服务端发送请求时,会进行三次握手
*/
socket = new Socket("localhost", 8888);
System.out.println("连接成功!");
} catch (IOException e) {
e.printStackTrace();
}
}
// 该方法用于启动客户端程序的执行
public void start() {
/*
Socket提供了一个方法:
OutputStream getOutputStream()
通过socket获取输出流,将写出的信息发送给服务端
*/
try {
OutputStream outputStream = socket.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
PrintWriter printWriter = new PrintWriter(bufferedWriter,true); // 自动行刷新
// 输入昵称
Scanner scanner01 = new Scanner(System.in);
while (true) {
System.out.println("请输入昵称:");
// 要求:昵称不能为空或者只有空格都不可以,如果发生则提示用户重新输入
String nickname = scanner01.nextLine();
if (nickname.trim().isEmpty()){
System.out.println("昵称不能为空,请重新输入!");
}else {
printWriter.println(nickname);
System.out.println("昵称设置成功!欢迎您:" + nickname);
break;
}
}
// 启动用于读取服务端消息的线程
ServerHandler serverHandler = new ServerHandler();
Thread thread = new Thread(serverHandler);
// 如果我们输入exit想结束聊天,这个线程依然活着,所以我们想让他和主线程一起死,于是我们设计这个线程为守护线程
thread.setDaemon(true);
thread.start();
Scanner scanner = new Scanner(System.in);
while (true) {
String line = scanner.nextLine();
if ("exit".equalsIgnoreCase(line)) {
break;
}
printWriter.println(line); // 发送消息给服务端
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
socket.close(); // 进行四次挥手
} catch (IOException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Client client = new Client();
client.start();
}
// 处理回复消息,创建回复接口:该线程任务负责读取来自服务端发送过来的消息并输出到控制台上
private class ServerHandler implements Runnable {
@Override
public void run() {
try {
// 通过Socket提供的方法InputStream getInputStream(),获取输入流,将服务端发送的消息读取出来
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
// 循环读取来自服务端发送过来的消息并输出到客户端控制台上
String message;
while ((message = bufferedReader.readLine()) != null) {
System.out.println(message);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
server.java
package Day21;
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 服务端
*/
public class Server {
/**
* java.net.ServerSocket:
* 运行在服务端,主要作用有两个:
* 1.像系统申请服务端口,客户端通过该端口与服务端建立连接
* 2.监听服务端口,一旦有客户链接了,就会立即创建一个Socket对象与客户端进行交互
* 如果将Socket比喻为“电话”,那ServerSocket就相当于客户中心的“总机”。
* 解决方法:
* 1.更换端口号;
* 2.杀死占用该端口的进行(通常由于服务端启动了两次导致)
*/
// key:用户的昵称 value:该客户端的输出流
private Map<String, PrintWriter> allOut = new HashMap<>();
private ServerSocket serverSocket;
// private List<PrintWriter> allOut = new ArrayList<>();
public Server(){
try {
System.out.println("正在启动服务端......");
/**
* 创建ServerSocket对象时,会申请一个端口
* 如果该端口被其它程序占用,会抛出异常:
* java.net.BindException: Address already in use:
* 解决办法:
* 1.更换端口号
* 2.杀死占用该端口的进行(通常由于服务端启动两次导致)
*/
serverSocket = new ServerSocket(8888);
System.out.println("服务端启动完成!");
} catch (IOException e) {
e.printStackTrace();
}
}
// 启动服务端方法:
/**
* accept():
* 用于接收客户端连接,并返回一个Socket对象与所连接的客户端进行交互
* 该方法是一个阻塞方法,调用后程序会“卡住”,直到一个客户端连接为止
*/
public void start(){
try {
while (true){
System.out.println("服务端正在等待客户端连接......");
Socket socket = serverSocket.accept();
System.out.println("一个客户端连接了!");
// 启动单独的线程来处理与客户端的通信
Runnable clientHandler = new ClientHandler(socket);
Thread thread = new Thread(clientHandler);
thread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
server.start();
}
/**
* 该线程任务用于负责与指定的客户端通信
*/
private class ClientHandler implements Runnable{
private Socket socket;
private String host; // 记录客户端的IP地址
private String nickname;
public ClientHandler(Socket socket) {
this.socket = socket;
// 通过socket获取客户端ip地址
host = socket.getInetAddress().getHostAddress();
}
@Override
public void run() {
PrintWriter printWriter = null;
try {
//接收客户端发送过来的消息
/*
Socket提供了一个方法:
InputStream getInputStream()
通过socket获取输入流,用于读取客户端发送过来的数据
*/
InputStream inputStream = socket.getInputStream();
InputStreamReader inputStreamReader = new InputStreamReader(inputStream, StandardCharsets.UTF_8);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
// 读取客户端发送过来的第一行字符串一定是客户端的昵称
nickname = bufferedReader.readLine();
// 通过Socket获取输出流,用于将消息发送给该客户端
OutputStream outputStream = socket.getOutputStream();
OutputStreamWriter outputStreamWriter = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8);
BufferedWriter bufferedWriter = new BufferedWriter(outputStreamWriter);
printWriter = new PrintWriter(bufferedWriter,true);
// 将对应该客户端的输出流存入到共享集合allOut中
synchronized (allOut) {
allOut.put(nickname, printWriter);
}
// 广播该客户端上线了
broadcast(nickname + "["+host+"]上线了!当前在线人数:" + allOut.size());
/*
当我们通过br.readLine()读取客户端发送过来的数据时,
客户端如果调用socket.close()时(进行四次挥手),正常与我们断开连接
那么readLine()会返回null
若客户端异常中断(强制杀死进程),此时readLine()会抛出异常
注意:这种情况咱们服务端是没有办法的
*/
String message;
while ((message = bufferedReader.readLine()) != null) { // 读取客户端发送过来的消息
if(message.startsWith("@")) {
// 如果消息是以@开头,说明是私聊消息
sendMessageToSomeone(message);
}else{
broadcast(nickname + "[" +host + "]说:" + message);
}
}
} catch (IOException e) {
} finally {
// 处理该客户端断开连接后的操作
// 将该客户端的输出流从共享集合allOut中删除
synchronized (allOut) {
// allOut.remove(printWriter);
allOut.remove(nickname);
}
// 广播消息,告知所有客户端该用户下线了
broadcast(nickname + "[" + host + "]下线了!当前在线人数:" + allOut.size());
try { // 进行四次挥手
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
/**
* 将消息发送给所有客户端
* @param message
*/
private void broadcast(String message){
System.out.println(message);
synchronized (allOut) {
// for (PrintWriter writer : allOut) {
// writer.println(message);
// }
for (PrintWriter writer : allOut.values()){
writer.println(message);
}
}
}
/**
* 私聊功能,将消息发送给某个人
* @param message
*/
public void sendMessageToSomeone(String message){
/*
过程:
私聊消息的格式-->@对方昵称:聊天消息
1:截取出对方的昵称
substring()->截"@"到":"之间的内容
2:从allOut中使用对方的昵称作为key提取到对应的输出流
map.get(对方昵称)
3:将聊天消息通过该输出流发送给对方
聊天消息substring()->":"后面的内容
然后通过输出流发送给对象
*/
// 首先验证私聊消息是否为正确的格式:@xxx:xxx
if (message.matches("@.+:.+")) {
//1
String toNickName = message.substring(1, message.indexOf(":"));
if (allOut.containsKey(toNickName)) {
//2
PrintWriter printWriter = allOut.get(toNickName);
//3
String toMessage = message.substring(message.indexOf(":") + 1);
printWriter.println(nickname + "悄悄对你说:" + toMessage);
}else {
PrintWriter printWriter = allOut.get(nickname);
printWriter.println("私聊对象不存在!");
}
} else {
// 如果格式不对,给当前用户提示私聊格式不正确
PrintWriter printWriter = allOut.get(nickname);
printWriter.println("私聊消息格式不正确,私聊的格式应当为:@对方昵称:私聊消息");
}
}
}
}
-
接下来将Client.java客户端内全部代码发送给GPT,请求生成一个可视化界面,GPT语言:
这是一个多人在线聊天室的客户端代码,请根据Client.java中的Client类的代码内容,生成图形化的界面,对输入昵称可以单独创建界面,聊天界面要求要在窗口的下方生成文本框,用于获取用户输入的聊天消息发送给服务端,包括上方存在一个文本框用来获取服务器发送来的聊天记录信息,下方具有发送按钮,发送可以使用enter键触发,字体也可以进行修改,界面内部使用中文布局,可以参考其他在线聊天室软件的界面布局,还有就是将字的大小改为24,聊天界面按钮别搞那么长,把聊天框放大一些,把界面做的更复杂一些
package Day21; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.io.*; import java.net.Socket; import java.nio.charset.StandardCharsets; public class ClientGUI { private Socket socket; private String nickname; private JTextArea chatArea; private JTextField inputField; public ClientGUI() { connectToServer(); createNicknameFrame(); } // 连接服务器 private void connectToServer() { try { socket = new Socket("localhost", 8888); System.out.println("连接成功!"); } catch (IOException e) { e.printStackTrace(); } } // 昵称输入界面 private void createNicknameFrame() { JFrame nicknameFrame = new JFrame("输入昵称"); nicknameFrame.setSize(500, 250); nicknameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); nicknameFrame.setLayout(new BorderLayout()); JPanel panel = new JPanel(new GridBagLayout()); JLabel label = new JLabel("请输入昵称:"); label.setFont(new Font("宋体", Font.PLAIN, 24)); JTextField nicknameField = new JTextField(15); nicknameField.setFont(new Font("宋体", Font.PLAIN, 24)); JButton confirmButton = new JButton("确认"); confirmButton.setFont(new Font("宋体", Font.PLAIN, 24)); confirmButton.addActionListener(e -> { String inputNickname = nicknameField.getText().trim(); if (inputNickname.isEmpty()) { JOptionPane.showMessageDialog(nicknameFrame, "昵称不能为空,请重新输入!"); } else { nickname = inputNickname; sendNicknameToServer(); nicknameFrame.dispose(); createChatFrame(); } }); GridBagConstraints gbc = new GridBagConstraints(); gbc.insets = new Insets(10, 10, 10, 10); gbc.gridx = 0; gbc.gridy = 0; panel.add(label, gbc); gbc.gridx = 1; panel.add(nicknameField, gbc); gbc.gridx = 0; gbc.gridy = 1; gbc.gridwidth = 2; panel.add(confirmButton, gbc); nicknameFrame.add(panel, BorderLayout.CENTER); nicknameFrame.setVisible(true); } // 发送昵称给服务器 private void sendNicknameToServer() { try { PrintWriter writer = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)), true); writer.println(nickname); System.out.println("昵称设置成功!欢迎您:" + nickname); } catch (IOException e) { e.printStackTrace(); } } // 主聊天界面 private void createChatFrame() { JFrame chatFrame = new JFrame("聊天室 - " + nickname); chatFrame.setSize(800, 600); chatFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); chatFrame.setLayout(new BorderLayout()); chatArea = new JTextArea(); chatArea.setEditable(false); chatArea.setFont(new Font("宋体", Font.PLAIN, 24)); JScrollPane chatScrollPane = new JScrollPane(chatArea); inputField = new JTextField(); inputField.setFont(new Font("宋体", Font.PLAIN, 24)); inputField.setPreferredSize(new Dimension(600, 50)); JButton sendButton = new JButton("发送"); sendButton.setFont(new Font("宋体", Font.PLAIN, 24)); sendButton.setPreferredSize(new Dimension(150, 50)); // 按下发送按钮或回车键发送消息 sendButton.addActionListener(e -> sendMessage()); inputField.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { if (e.getKeyCode() == KeyEvent.VK_ENTER) { sendMessage(); } } }); JPanel inputPanel = new JPanel(new BorderLayout()); inputPanel.add(inputField, BorderLayout.CENTER); inputPanel.add(sendButton, BorderLayout.EAST); chatFrame.add(chatScrollPane, BorderLayout.CENTER); chatFrame.add(inputPanel, BorderLayout.SOUTH); chatFrame.setVisible(true); // 启动接收服务器消息的线程 new Thread(new ServerHandler()).start(); } // 发送消息到服务器 private void sendMessage() { String message = inputField.getText().trim(); if (!message.isEmpty()) { try { PrintWriter writer = new PrintWriter(new BufferedWriter( new OutputStreamWriter(socket.getOutputStream(), StandardCharsets.UTF_8)), true); writer.println(message); inputField.setText(""); } catch (IOException e) { e.printStackTrace(); } } } // 处理服务器消息 private class ServerHandler implements Runnable { @Override public void run() { try { BufferedReader reader = new BufferedReader( new InputStreamReader(socket.getInputStream(), StandardCharsets.UTF_8)); String message; while ((message = reader.readLine()) != null) { chatArea.append(message + "\n"); } } catch (IOException e) { e.printStackTrace(); } } } public static void main(String[] args) { new ClientGUI(); } }
Java的反射机制
反射机制
什么是反射机制
-
Java的反射机制是一种让程序在运行时动态获取类、接口、方法、属性等信息的能力。通过反射,程序可以在不知道类的情况下创建对象、调用方法、或访问属性。这种机制允许程序在运行时检查和操作代码结构,而不需要在编译时知道具体的类型。
-
简而言之,反射使得代码能够“自我检查”和“自我修改”。这对于编写更灵活、通用的代码非常有用,比如框架、工具库、或一些需要处理未知类型对象的程序。
-
Java的反射机制就像是你手中的一面“魔法镜子”(反射API)。当你面对一扇门(类)时,不用打开门就能通过这面魔法镜子看到门后面的所有东西(类的结构),比如房间里的家具(属性)、开关(方法)等等。你甚至可以通过镜子直接操作这些东西,比如打开开关(调用方法)或移动家具(修改属性),而不需要知道这个房间具体是什么样的。
反射API
什么是Class类?
-
Class
类是Java反射机制的核心。它是一个用来表示类或接口的字节码文件在JVM中的对象。通过Class
类,程序可以在运行时获取关于类的各种信息,比如类的名称、修饰符、构造方法、方法、字段等。 -
每个Java类在加载时,JVM都会为其生成一个对应的
Class
对象,这个对象包含了该类的所有元数据信息。开发者可以通过这个Class
对象使用反射机制来操作这个类。
获取类对象
-
Class.forName("类的全限定名")
-
用法: 通过类的全限定名(即包名+类名)来获取
Class
对象。 -
适用场景: 当你知道类的名称,并且希望在运行时动态加载类时,这种方法最为常用。
-
示例:
Class class1 = Class.forName("java.util.String");
-
-
类名.class
-
用法: 直接通过类的名字获取
Class
对象。 -
适用场景: 当你在编译时就已经知道类的具体类型时,这种方法更简洁。
-
示例:
String name = class1.getName();
-
-
对象.getClass()
-
用法: 通过一个已实例化的对象来获取它的
Class
对象。 -
适用场景: 当你有一个对象的实例,但不确定它的具体类型时,这种方法可以动态获取该对象的
Class
对象。 -
示例:
String string = new String(); Class class1 = string.getClass();
-
获取类信息
-
获取类的完全限定名
-
方法:
getName()
-
示例:
System.out.println(class1.getName());
-
-
获取当前类名
-
方法:
getSimpleName()
-
示例:
System.out.println(class1.getSimpleName());
-
-
获取构造方法
-
方法:
getConstructors()
,getDeclaredConstructors()
-
示例:
Constructor[] constructors = class1.getConstructors(); for (Constructor constructor : constructors) { System.out.println("Constructor: " + constructor); } // 获取所有声明的构造方法(包括私有构造方法) Constructor[] declaredConstructors = class1.getDeclaredConstructors(); for (Constructor constructor : declaredConstructors) { System.out.println("Declared Constructor: " + constructor); }
-
-
获取方法
-
方法:
getMethods()
,getDeclaredMethods()
-
示例:
Method[] methods = class1.getMethods(); for (Method method : methods) { System.out.println("Method: " + method); } // 获取所有声明的方法(包括私有方法) Method[] declaredMethods = class1.getDeclaredMethods(); for (Method method : declaredMethods) { System.out.println("Declared Method: " + method); }
-
-
获取字段
-
方法:
getFields()
,getDeclaredFields()
-
示例:
Field[] fields = class1.getFields(); for (Field field : fields) { System.out.println("Field: " + field); } // 获取所有声明的字段(包括私有字段) Field[] declaredFields = class1.getDeclaredFields(); for (Field field : declaredFields) { System.out.println("Declared Field: " + field); }
-
-
获取父类
-
方法:
getSuperclass()
-
示例:
Class superClass = class1.getSuperclass(); System.out.println("Superclass: " + superClass);
-
-
获取接口
-
方法:
getInterfaces()
-
示例:
Class[] interfaces = class1.getInterfaces(); for (Class iface : interfaces) { System.out.println("Interface: " + iface); }
-
-
获取类加载器
-
方法:
getClassLoader()
-
示例:
ClassLoader classLoader = class1.getClassLoader(); System.out.println("ClassLoader: " + classLoader);
-
Package类
-
java.lang.Package,用于获取包内的数据,每一个实例都用于表示一个包的信息,通过类对象的getPackage()方法获取一个类的包信息。
Class class1 = ArrayList.class; Package pack = class1.getPackage(); // 通过包对象获取它表示的包的名字 String packName = pack.getName(); System.out.peintln(packName); // 输出java.util
对象实例化
-
我们提前创建一个Person类,顺便将其配置好:
package day21; import java.util.Objects; public class Person { private String name; private int age; public Person() { } public Person(String name) { this.name = name; } public Person(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public boolean equals(Object object) { if (this == object) return true; if (object == null || getClass() != object.getClass()) return false; Person person = (Person) object; return age == person.age && Objects.equals(name, person.name); } @Override public int hashCode() { return Objects.hash(name, age); } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
-
使用
new
关键字- 这是最常见和直接的对象实例化方法,通过
new
关键字可以创建类的实例:
// 程序写死,那么只能实例化ArrayList ArrayList arrayList = new ArrayList();
- 这种方式在编译时需要知道类的具体类型,并且只能用于类的公共无参构造函数。
- 这是最常见和直接的对象实例化方法,通过
-
使用
Class
类的newInstance()
方法-
Class
类提供了newInstance()
方法来创建对象实例。这种方法允许你通过反射在运行时动态创建类的实例: -
方法:
Class.newInstance()
-
用法: 调用
Class
对象的newInstance()
方法,创建一个该类的实例。 -
示例:
// 1.获取要实例化的类的对象 // 反射机制实例化对象 Scanner scanner = new Scanner(System.in); // 反射机制可以运行起来根据需要去实例化的对象 System.out.println("请输入一个类的名字:"); String className = scanner.next(); Class cls = Class.forName(className); /* 2.类对象 */ Object obj = cls.newInstance(); System.out.println(obj);
-
注意:
newInstance()
方法已被标记为过时(deprecated),主要因为它不能处理构造函数的异常。建议使用Constructor
类的方法来替代。
-
-
使用
Constructor
类-
Constructor
类提供了更灵活的方式来创建对象实例。可以通过Constructor
对象调用构造函数来创建实例: -
获取
Constructor
对象: 使用Class
类的getConstructor()
或getDeclaredConstructor()
方法获取构造函数。 -
创建实例: 使用
Constructor
对象的newInstance()
方法创建对象。 -
示例:
package day21; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; public class ReflectDemo3 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException { Person person = new Person("张禹垚", 21); System.out.println(person); // 获取类对象 Class cls = Class.forName("day21.Person"); // Person(String) Constructor constructor = cls.getConstructor(String.class); // new Person("刘备"); Object obj = constructor.newInstance("刘备"); System.out.println(obj); Class cls1 = Class.forName("day21.Person"); Constructor constructor1 = cls1.getConstructor(String.class, int.class); Object obj1 = constructor1.newInstance("关羽", 33); System.out.println(obj1); } }
-