1. TCP编程
1.1 TCP客户端
方法
构造方法 说明 public Socket(String ip,int port) 和服务端建立连接 参数一: 服务端ip地址(字符串) 参数二: 服务端端口号
方法 说明 public OutPutStream getOutPutStream() 获取网络字节输出流 public InputStream getInputStream() 获取网络字节输入流
步骤
创建Socket对象: 需要指定服务端的ip和端口号 获取字节输出流 写数据 释放资源
/*
TCP客户端程序
TCP在发送数据之前,确保连接已经建立
*/
public class Client {
public static void main(String[] args) throws IOException {
// 1.创建Socket对象 指定服务端ip和端口号 连接
Socket socket = new Socket("127.0.0.1",8888);
// 2.获取字节输出流
OutputStream os = socket.getOutputStream();
// 数据输出流: DataOutputStream .writeUTF(String)
DataOutputStream dos = new DataOutputStream(os); // 直接写中文
// 3.写数据
dos.writeUTF("你好吗?");
dos.flush(); // 真正将数据写出去
// 4.释放资源: socket关闭了 获取的输出流也会随之关闭
socket.close();
}
}
1.2 TCP服务端
方法
构造方法 说明 public ServerSocket(int port) 服务端ServerSocket对象,参数为服务端的端口号
方法 说明 public Socket accept() 等待客户端的连接,连接成功获取Socket对象
步骤
创建ServerSocket对象 等待客户端连接并获取Socket对象 Socket对象获取输入流 释放资源
/*
TCP服务端代码
*/
public class Server {
public static void main(String[] args) throws IOException {
// 1.创建ServerSocket,需要指定服务端端口号
ServerSocket ss = new ServerSocket(8888);
// 2.accept等待客户端连接,连接成功返回Socket对象
Socket socket = ss.accept();
// 3.获取字节输入流
InputStream is = socket.getInputStream();
// 使用数据输入流配合使用读取数据
DataInputStream dis = new DataInputStream(is);
String msg = dis.readUTF();
System.out.println(msg);
// 4.释放资源
socket.close(); // socket关闭,获取的字节输入流也会随之关闭
ss.close();
}
}
1.3 多发多收
步骤
服务端: 使用死循环包裹读数据的代码 客户端: 发送键盘录入的内容,使用死循环包裹写数据的代码,如果用户输入"886",结束循环
public class Client {
public static void main(String[] args) throws IOException {
// 1.创建Socket对象 指定服务端ip和端口号 连接
Socket socket = new Socket("127.0.0.1",8888);
// 2.获取字节输出流
OutputStream os = socket.getOutputStream();
// 数据输出流: DataOutputStream .writeUTF(String)
// 数据流的特点: 读写数据时,带着数据类型
DataOutputStream dos = new DataOutputStream(os);
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("请录入: ");
String s = sc.nextLine(); // 用户录入的数据
if ("886".equals(s)){
break;
}
// 3.写数据
dos.writeUTF(s);
dos.flush(); // 真正将数据写出去
}
// 4.释放资源: socket关闭了 获取的输出流也会随之关闭
socket.close();
}
}
public class Server {
public static void main(String[] args) throws IOException {
// 1.创建ServerSocket,需要指定服务端端口号
ServerSocket ss = new ServerSocket(8888);
// 2.accept等待客户端连接,连接成功返回Socket对象
Socket socket = ss.accept();
// 3.获取字节输入流
InputStream is = socket.getInputStream();
// 使用数据输入流配合使用读取数据
DataInputStream dis = new DataInputStream(is);
while (true) {
String msg = dis.readUTF();
// socket.getRemoteSocketAddress() 获取到客户端ip和端口号
System.out.println(socket.getRemoteSocketAddress() + ": "+msg);
}
// 4.释放资源
// socket.close(); // socket关闭,获取的字节输入流也会随之关闭
// ss.close();
}
}
问题
当客户端结束后,服务端会出现异常EOFException?
原因: 客户端结束了,服务端readUTF()方法,出现EOFException,表示没有数据可读 解决: 使用try…catch去捕获EOFException
public class Server {
public static void main(String[] args) throws IOException {
// 1.创建ServerSocket,需要指定服务端端口号
ServerSocket ss = new ServerSocket(8888);
// 2.accept等待客户端连接,连接成功返回Socket对象
Socket socket = ss.accept();
// 3.获取字节输入流
InputStream is = socket.getInputStream();
// 使用数据输入流配合使用读取数据
DataInputStream dis = new DataInputStream(is);
while (true) {
try {
// 出现EOFException,表示没数据可读了
String msg = dis.readUTF();
// socket.getRemoteSocketAddress() 获取到客户端ip和端口号
System.out.println(socket.getRemoteSocketAddress() + ": "+msg);
} catch (EOFException e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了");
socket.close(); // 客户端的socket已经断开连接,服务端获取到的socket也需要关闭
break;
}
}
// 4.释放资源
// socket.close(); // socket关闭,获取的字节输入流也会随之关闭
// ss.close();
}
1.4 实现多个客户端和服务端同时通信
public class Server {
public static void main(String[] args) throws IOException {
// 1.创建ServerSocket,需要指定服务端端口号
ServerSocket ss = new ServerSocket(8888);
while (true) {
System.out.println("等待接收客户端的连接");
Socket socket = ss.accept();
// 连接成功后,再开启线程 执行读数据
System.out.println(socket.getRemoteSocketAddress() + ": 上线了");
MyRunnable m = new MyRunnable(socket);
Thread t = new Thread(m);
t.start();
}
}
}
public class MyRunnable implements Runnable{
private Socket socket;
public MyRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// 接收客户端的连接
try {
// 获取字节流读数据
InputStream is = socket.getInputStream();
DataInputStream dis = new DataInputStream(is);
while (true) {
try {
String msg = dis.readUTF();
System.out.println(socket.getRemoteSocketAddress() + ":"+msg);
} catch (EOFException e) {
System.out.println(socket.getRemoteSocketAddress() + "下线了");
// 释放资源 socket资源
socket.close();
break;
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
1.5 练习
客户端上传文件到服务端
客户端: 从本地文件读数据,写到网络中, 循环读写 服务端: 从网络中读,写到本地文件,循环读写
/*
读取本地的文件 ,写到服务端
*/
public class Client {
public static void main(String[] args) throws IOException {
// 1.使用文件流读本地文件(缓冲流加速的效果)
BufferedInputStream bis = new BufferedInputStream(new FileInputStream("day15-code\\clientDir\\a.avi"));
Socket socket = new Socket("127.0.0.1",8888);
// 2.写到网络中
OutputStream os = socket.getOutputStream();
BufferedOutputStream bos = new BufferedOutputStream(os);
// 循环读写
int b;
while ((b = bis.read()) != -1){
bos.write(b);
}
bos.flush();
// bis本地文件流 单独的释放资源
// socket关闭,网络流也会自动跟着关闭
bis.close();
socket.close();
}
}
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8888);
Socket socket = ss.accept();
// 从网络中读
InputStream is = socket.getInputStream();
BufferedInputStream bis = new BufferedInputStream(is);
// 写到本地文件
BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream("day15-code\\serverDir\\a.avi"));
// 循环读写
int b;
while ((b = bis.read()) != -1){
bos.write(b);
}
bos.flush();
// 释放资源 本地字节输出流bos 网络中socket
bos.close();
socket.close();
ss.close();
}
1.6 实现BS架构
软件设计
C/S架构: Client(客户端) / Server服务端 B/S架构: Browser(浏览器) / Server服务端
原理
代码
/*
使用TCP编程,实现B/S 浏览器
在浏览器上输入 ip:端口就可以访问
*/
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8080);
// 能够接收多个浏览器连接
while (true){
Socket socket = ss.accept(); // 等待客户端连接
MyRunnable m = new MyRunnable(socket);
// 开启线程
Thread t = new Thread(m);
t.start();
}
}
}
public class MyRunnable implements Runnable{
private Socket socket;
public MyRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// 向浏览器写 "城市套路深,我要回农村" 文字
// 获取输出流
// try-with-resources
try(OutputStream os = socket.getOutputStream();) {
PrintStream ps = new PrintStream(os);
// 写数据的格式必须要按照HTTP要求的格式书写,否则浏览器不识别
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须要有空行
// 写内容(展示在浏览器中)
ps.println("<div style='color:red;font-size: 120px;text-align: center'>城市套路深,我要回农村</div>");
ps.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
HTTP协议规定的数据格式
1.7 线程池优化
每个连接都要创建新的线程对象,浪费资源,可以使用线程池(复用线程)
/*
使用TCP编程,实现B/S 浏览器
在浏览器上输入 ip:端口就可以访问
*/
public class Server {
public static void main(String[] args) throws IOException {
ServerSocket ss = new ServerSocket(8080);
// 创建线程池
// 最大线程数:
// CPU密集型: 和服务器CPU核心数量一致,保证CPU最大的使用率
// IO密集型: 比CPU核心数量多
// 队列的大小: 最大线程数量2倍
// 获取CPU最大支持线程数量
int num = Runtime.getRuntime().availableProcessors();
System.out.println(num);
ExecutorService pool = new ThreadPoolExecutor(
num / 2,
num,
10,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(num * 2),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy()
);
// 能够接收多个浏览器连接
while (true){
Socket socket = ss.accept(); // 等待客户端连接
MyRunnable m = new MyRunnable(socket);
// 开启线程,每个连接,创建线程对象,浪费性能,使用线程池优化(线程复用)
pool.execute(m);
}
}
}
public class MyRunnable implements Runnable{
private Socket socket;
public MyRunnable(Socket socket) {
this.socket = socket;
}
@Override
public void run() {
// 向浏览器写 "城市套路深,我要回农村" 文字
// 获取输出流
// try-with-resources
try(OutputStream os = socket.getOutputStream();) {
PrintStream ps = new PrintStream(os);
// 写数据的格式必须要按照HTTP要求的格式书写,否则浏览器不识别
ps.println("HTTP/1.1 200 OK");
ps.println("Content-Type:text/html;charset=UTF-8");
ps.println(); // 必须要有空行
// 写内容(展示在浏览器中)
ps.println("<div style='color:red;font-size: 120px;text-align: center'>城市套路深,我要回农村</div>");
ps.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
}
2. 反射
2.1 反射概述,获取Class对象
反射指的是什么?
加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。 反射学什么?
反射第一步是什么?
如何获取Class对象
Class c1 = 类名.class Class中的静态方法
Class c2 = Class.forName(“全类名”) Object类中提供的方法: public Class getClass();
Class c3 = 对象.getClass();
public class Student {
}
public class Demo {
public static void main(String[] args) throws ClassNotFoundException {
// 1.类名.class
Class<Student> c1 = Student.class;
// 2.Class类提供的静态方法 forName(全类名(包名+类名))
// idea 选择类,右键 Copy Reference 复制一个类的全类名
Class<?> c2 = Class.forName("com.itheima.d2_reflect.d1_start.Student");
// 3.Object类提供的方法 对象名.getClass()
Student stu = new Student();
Class<? extends Student> c3 = stu.getClass();
// 同一个类的字节码文件对象,只有一个
System.out.println(c1 == c2);
System.out.println(c2 == c3);
}
}
2.2 构造器(构造方法)
获取构造器
Class提供的方法 说明 Constructor<?>[] getConstructors() 获取全部构造器(只能获取public修饰的) Constructor<?>[] getDeclaredConstructors() 获取全部构造器(只要存在就能拿到) Constructor getConstructor(Class<?>… parameterTypes) 获取某个构造器(只能获取public修饰的) Constructor getDeclaredConstructor(Class<?>… parameterTypes) 获取某个构造器(只要存在就能拿到)
public class Student {
private String name;
private int age;
private Student() {
System.out.println("无参构造器执行了~~~~");
}
public Student(String name, int age) {
System.out.println("有参构造器执行了~~~~");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class Demo1 {
public static void main(String[] args) throws NoSuchMethodException {
// 0.获取Class对象
Class<Student> c = Student.class;
// 1.获取全部构造方法(只能获取public) 将所有构造方法 放到一个数组中返回
Constructor<?>[] arr1 = c.getConstructors();
for (Constructor<?> constructor : arr1) { // constructor表示每一个构造方法
System.out.println(constructor);
}
System.out.println("===================");
// 2.获取全部构造方法(任意修饰符)
Constructor<?>[] arr2 = c.getDeclaredConstructors();
for (Constructor<?> constructor : arr2) {
System.out.println(constructor);
}
System.out.println("===================");
// 3.获取单个构造方法(只能获取public修饰),参数类型的字节码文件对象,要和构造方法的参数一一对应
Constructor<Student> constructor1 = c.getConstructor(String.class, int.class);
System.out.println(constructor1);
System.out.println("===================");
// 4.获取单个构造方法(任意修饰符)
Constructor<Student> constructor2 = c.getDeclaredConstructor();
System.out.println(constructor2);
}
}
获取构造器的作用
Constructor中的方法 说明 T newInstance(Object… initargs) 调用此构造器对象表示的构造器,并传入参数,完成对象的初始化并返回 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
/*
获取构造器的作用: 创建该类的对象,类的初始化
*/
public class Demo2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1.获取Class对象
Class<Student> c = Student.class;
// 2.获取带参数的构造方法
Constructor<Student> constructor1 = c.getDeclaredConstructor(String.class, int.class);
Student stu1 = constructor1.newInstance("张三", 23);// 执行构造方法,给参数赋值
System.out.println(stu1);
// 3.获取空参的构造方法
Constructor<Student> constructor2 = c.getDeclaredConstructor();
constructor2.setAccessible(true); // 不检查访问权限,暴力反射
Student stu2 = constructor2.newInstance();
System.out.println(stu2);
}
}
2.3 成员变量
获取成员变量
Class提供的方法 说明 public Field[] getFields() 获取类的全部成员变量(只能获取public修饰的) public Field[] getDeclaredFields() 获取类的全部成员变量(只要存在就能拿到) public Field getField(String name) 获取类的某个成员变量(只能获取public修饰的) public Field getDeclaredField(String name) 获取类的某个成员变量(只要存在就能拿到)
public class Student {
public int a;
public static String school = "传智大学";
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
}
/*
获取成员变量Field
*/
public class Demo1 {
public static void main(String[] args) throws NoSuchFieldException {
// 1.获取Class对象
Class<Student> c = Student.class;
// 获取所有的成员变量(任意权限,只要存在就能获取)
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName()); // getName获取成员变量的名字
}
System.out.println("=====================");
// 通过成员变量的名字 获取指定的成员变量
Field school = c.getDeclaredField("school");
System.out.println(school.getName());
Field age = c.getDeclaredField("age");
System.out.println(age.getName());
}
}
获取成员变量的作用
Field中的方法 说明 void set(Object obj, Object value): 赋值 Object get(Object obj) 取值 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
public class Demo2 {
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
// 1.获取Class对象
Class<Student> c = Student.class;
// 2.获取成员变量
Field school = c.getDeclaredField("school");
Student stu = new Student();
// 参数一: 操作哪一个对象的成员变量
// 参数二: 给成员变量赋什么值
// 给school赋值,获取值
school.set(stu,"社大专修学院");
System.out.println(school.get(stu));
// 获取age成员变量
Field age = c.getDeclaredField("age");
// 给age赋值和获取值
age.setAccessible(true); // 如果成员变量是private 取消权限检查 暴力反射
age.set(stu,32);
System.out.println(age.get(stu));
}
}
2.4 成员方法
获取成员方法
Class提供的方法 说明 Method[] getMethods() 获取类的全部成员方法(只能获取public修饰的) Method[] getDeclaredMethods() 获取类的全部成员方法(只要存在就能拿到) Method getMethod(String name, Class<?>… parameterTypes) 获取类的某个成员方法(只能获取public修饰的) Method getDeclaredMethod(String name, Class<?>… parameterTypes) 获取类的某个成员方法(只要存在就能拿到)
public class Student {
public int a;
public static String school = "XX大学";
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Cat{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getA() {
return a;
}
public void setA(int a) {
this.a = a;
}
public void run() {
System.out.println("跑的快");
}
public void eat() {
System.out.println("吃的多");
}
private void eat(String name) {
System.out.println("最爱吃" + name);
}
}
public class Demo1 {
public static void main(String[] args) throws NoSuchMethodException {
//1.获取Class对象
Class<Student> c = Student.class;
// 2.获取所有的public方法(包括从父类中继承的)
Method[] methods1 = c.getMethods();
for (Method method : methods1) {
System.out.println(method.getName()); // 获取成员方法的名字
}
System.out.println("=====================");
Method[] arr2 = c.getDeclaredMethods();
for (Method method : arr2) {
System.out.println(method.getName());
}
System.out.println("=====================");
// 3.获取单个成员方法(方法名,参数类型)
Method run = c.getDeclaredMethod("run");
System.out.println(run);
Method eat = c.getDeclaredMethod("eat", String.class);
System.out.println(eat);
}
}
获取成员方法的作用
Field中的方法 说明 public Object invoke(Object obj, Object… args) 触发某个对象的该方法执行。 public void setAccessible(boolean flag) 设置为true,表示禁止检查访问控制(暴力反射)
/*
获取方法,并且执行方法
*/
public class Demo2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
// 1.获取Class对象
Class<Student> c = Student.class;
// 2.获取指定的成员方法
// 3.执行方法
Method run = c.getDeclaredMethod("run");
Student stu = new Student();
// 参数一: 具体的学生对象
// 参数二: 给方法的参数赋值
// 返回值和run方法的返回值一致
run.invoke(stu);
// 获取私有的eat方法
Method eat = c.getDeclaredMethod("eat", String.class);
eat.setAccessible(true); // 禁止权限访问检查,暴力反射
eat.invoke(stu,"重庆小面");
}
}
2.5 反射的作用和应用场景
反射的作用
基本作用:可以得到一个类的全部成分然后操作。 可以破坏封装性。(禁止检查访问控制) 最重要的用途是:适合做Java的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。
反射的应用场景
需求: 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去。 步骤:
①定义一个方法,可以接收任意对象。 ②每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量。 ③遍历成员变量,然后提取成员变量在该对象中的具体值。 ④把成员变量名、和其值,写出到文件中去即可。
public class Demo {
public static void main(String[] args) throws IllegalAccessException, FileNotFoundException {
Student stu = new Student("柳岩",40,'女',167.5,"女星");
show(stu);
Teacher t = new Teacher("肥仔",6000);
show(t);
}
// 1.定义一个方法,方法的参数接收任意的对象
public static void show(Object obj) throws IllegalAccessException, FileNotFoundException {
PrintStream ps = new PrintStream(new FileOutputStream("day15-code\\obj.txt",true));
// 2.通过对象 获取Class 对象名.getClass
Class<?> c = obj.getClass();
// getSimpleName() 获取类名 getName() 获取全类名
ps.println("==================="+c.getSimpleName()+"===================");
// 3.获取所有的成员变量 Field[]
Field[] fields = c.getDeclaredFields();
// 4.遍历数组 将成员变量名和成员的值 写入到一个文件中
for (Field field : fields) { // 获取每一个成员变量
// 获取成员变量名
String name = field.getName();
// 获取成员变量的值
field.setAccessible(true);
Object value = field.get(obj);
ps.println(name + "=" + value);
}
ps.close();
}
}
public class Student {
private String name;
private int age;
private char sex;
private double height;
private String hobby;
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
", sex=" + sex +
", height=" + height +
", hobby='" + hobby + '\'' +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
public Student(String name, int age, char sex, double height, String hobby) {
this.name = name;
this.age = age;
this.sex = sex;
this.height = height;
this.hobby = hobby;
}
public Student() {
}
}
public class Teacher {
private String name;
private double salary;
@Override
public String toString() {
return "Teacher{" +
"name='" + name + '\'' +
", salary=" + salary +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Teacher() {
}
public Teacher(String name, double salary) {
this.name = name;
this.salary = salary;
}
}
2.6 反射操作带有泛型的类
使用反射向List集合中添加任意类型的数据 反射操作带有泛型的类时,跳过泛型检查 泛型的原理: 泛型擦除,只在编译阶段有效,一旦编译成class文件 泛型就不存在了 反射获取字节码文件的对象
public class Demo {
/*
反射操作带有泛型的类时,跳过泛型检查
泛型的原理: 泛型擦除,只在编译阶段有效,一旦编译成class文件 泛型就不存在了
反射获取字节码文件的对象
*/
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<String> list = new ArrayList<>();
// 1.获取Class
Class<? extends List> c = list.getClass();
// 2.获取add方法
Method add = c.getDeclaredMethod("add", Object.class);
// 3.执行add方法
add.setAccessible(true);
add.invoke(list,"abc");
add.invoke(list,123);
// 使用反射操作带有泛型的类时,一定注意数据类型,有可能出现类型转换异常
for (String s : list) {
System.out.println(s);
}
}
}
2.7 反射练习
#name=com.itheima.d2_reflect.d7_test3.Student
#name=com.itheima.d2_reflect.d7_test3.Teacher
name=com.itheima.d2_reflect.d7_test3.Manager
需求:
properties文件中 记录的是什么类名,创建什么类的对象 记录的是什么方法,我就调用什么方法 有什么办法让学生类和老师类必须要有show方法 答案: 接口 接口: 制定规则
public class Teacher implements Inter{
public void show(){
System.out.println("老师教书");
}
}
public class Manager implements Inter{
@Override
public void show() {
System.out.println("管理班级");
}
}
public class Student implements Inter{
public void show(){
System.out.println("学生学习");
}
}
public interface Inter {
void show();
}
public class Demo {
/*
properties文件中
记录的是什么类名,创建什么类的对象
记录的是什么方法,我就调用什么方法
有什么办法让学生类和老师类必须要有show方法
答案: 接口
接口: 制定规则
*/
public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
// 1.读取properties中的内容
Properties prop = new Properties();
prop.load(new FileInputStream("day15-code\\obj.properties"));
String name = prop.getProperty("name"); // 获取的是全类名
// String method = prop.getProperty("method");// 获取方法名
// 2.通过全类名,获取Class
Class<?> c = Class.forName(name);
// 3.获取这个类的构造方法,创建对象
Constructor<?> constructor = c.getConstructor();
constructor.setAccessible(true);
Object obj = constructor.newInstance();
// 4.通过方法名获取方法
Method m = c.getDeclaredMethod("show");
// 5.运行这个方法
m.setAccessible(true);
m.invoke(obj);
}
}
3. 小结
3.1 网络编程之TCP编程
3.2 反射