TCP协议:
TCP协议客户端程序编写:
1、创建客户端的Socket对象
2、创建BufferedReader读取本地文件
3、获取通道中的字节输出流对象
4、读取数据并写入到通道中
5、释放资源
public class UploadClient {
public static void main(String[] args) throws Exception {
//创建客户端的Socket对象
Socket s = new Socket("192.168.10.112", 12345);
//创建字符缓冲输入流
BufferedReader br = new BufferedReader(new FileReader("b.txt"));
//获取通道中的字节输出流对象
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
String line = null;
while ((line = br.readLine()) != null) {
bw.write(line);
bw.newLine();
bw.flush();
}
//告诉服务器你别等了,我没有数据可以过来了
s.shutdownOutput();
//接收服务器的反馈
BufferedReader br2 = new BufferedReader(new InputStreamReader(s.getInputStream()));
String s1 = br2.readLine();
System.out.println("服务器反馈:" + s1);
//释放资源
br.close();
s.close();
}
}
服务器端程序编写
1、创建服务器端的ServerSocket对象
2、监听客户端的连接
3、获取通道中字节输入流对象
4、创建字符输出流对象(由于是本地模拟,为了防止文件名冲突,我就以时间戳命名)
5、向文件中写入数据
6、获取通道中的字节输出流对象,给客户端一个反馈
7、释放资源
public class UploadServer {
public static void main(String[] args) throws Exception {
//创建服务器端的ServerSocket对象
ServerSocket ss = new ServerSocket(12345);
//监听客户端的连接
Socket s = ss.accept();
//获取通道中字节输入流对象
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
Date date = new Date(System.currentTimeMillis());
SimpleDateFormat sdf = new SimpleDateFormat("yyyy_MM_dd_HH_mm_ss");
String format = sdf.format(date);、
//创建字符输出流对象
BufferedWriter bw = new BufferedWriter(new FileWriter(format + ".txt"));
String line = null;
while ((line=br.readLine())!=null){
bw.write(line);
bw.newLine();
bw.flush();
}
//向客户端写一个反馈
BufferedWriter bw2 = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw2.write("文件上传成功!");
bw2.newLine();
bw2.flush();
//释放资源
bw.close();
s.close();
}
}
反射:
反射:通过一个Class文件对象去使用或者修改文件对象中的成员变量,构造方法,成员方法(无论是否私有,都能获取并使用)
我们在使用成员之前,得先有一个java文件,然后在实例化的时候,new一下就完事了。
Person p = new Person();
p.eat("汉堡");
总归来说,无论是调用什么成员,都是有个对象,归根结底,对象是根据类来的,实际上底层是依赖一个class文件。对于java程序来说,依赖的是这个class文件对应的Class文件对象。
class类:
成员变量:Field
构造方法:Constructor
成员方法:Method
如何获取一个类对应的Class文件对象呢?
--方式1:通过Object类中的getClass()方法,返回此Object类的运行时的类
Person person = new Person();
Class<? extends Person> c1 = person.getClass();
Person person1 = new Person();
Class<? extends Person> c2 = person1.getClass();
System.out.println(c1==c2);
--方式2:在不new的前提下,获取该类的class文件对象,java中每一个类都有一个静态的属性class
Class<Person> c3 = Person.class;
System.out.println(c1==c3);
System.out.println(c2==c3);
--方式3:Class类中有一个静态的方法,获取该类的class文件对象 (最常用的)
//static Class<?> forName(String className) --返回与给定字符串名称的类或接口相关联的 类对象。
try {
Class<?> c4 = Class.forName("com.shujia.wyh.day28.Person");
System.out.println(c1==c4);
System.out.println(c2==c4);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
如何通过反射获取Class文件对象并使用其中的构造方法创建对象呢?
//获取Person类的Class文件对象
Class<?> c1 = Class.forName("com.shujia.wyh.day28.Person");
//获取Class文件对象中的所有公共构造方法
//public Constructor<?>[] getConstructors() throws SecurityException
//返回一个包含Constructor对象的数组,反映由此Constructor对象表示的类的所有公共类函数
Constructor<?>[] cons = c1.getConstructors();
for (Constructor c : cons) {
System.out.println(c);
}
//获取单个构造方法
//Constructor<T> getConstructor(类<?>... parameterTypes)
//返回一个Constructor对象,该对象反映Constructor对象表示的类的指定的公共类函数。
Constructor<?> con1 = c1.getConstructor(String.class);
System.out.println(con1);
//获取单个私有的带参数的构造方法
Constructor<?> con2 = c1.getDeclaredConstructor(String.class, int.class);
System.out.println(con2);
//使用公共的构造方法创建对象
//T newInstance(Object... initargs)
--使用此 Constructor对象表示的构造函数,使用指定的初始化参数来创建和初始化构造函数的声明类的新实例。
Object o = con1.newInstance("张三");
System.out.println(o);
//向下转型
Person p = (Person) o;
p.eat("汉堡");
通过反射获取Class文件对象中私有的构造方法并创建对象:
//获取Person类的Class文件对象
Class<?> c1 = Class.forName("com.shujia.wyh.day28.Person");
//获取私有的构造方法
Constructor<?> con1 = c1.getDeclaredConstructor(String.class, int.class);
//暴力访问
con1.setAccessible(true); --如果这里的值是true的化,表示反射对象在使用的时候,取消Java语言的访问检查
Object o = con1.newInstance("李四", 18);
System.out.println(o);
//向下转型
Person p = (Person) o;
p.eat("汉堡");
反射获取类Class文件对象中的成员变量并使用:
//获取Class文件对象
Class<?> c1 = Class.forName("com.shujia.wyh.day28.Person");
//Field[] getFields()
--返回包含一个数组Field对象反射由此表示的类或接口的所有可访问的公共字段类对象。
//获取当前类所有被public修饰的成员变量
Field[] fields = c1.getFields();
for (Field f : fields) {
System.out.println(f);
}
//Field[] getDeclaredFields()
--返回的数组Field对象反映此表示的类或接口声明的所有字段类对象。
//获取当前类中所有的成员变量,包括私有的,公共的,被保护的,默认的字段,不包括继承的字段。
Field[] fields2 = c1.getDeclaredFields();
for (Field field : fields2) {
System.out.println(field);
}
//获取单个的成员变量
Field id = c1.getField("id");
//void set(Object obj, Object value)
--将指定对象参数上的此 Field对象表示的字段设置为指定的新值。
id.set(o,"1001"); --给对象o中的成员变量id赋值为"1001"
System.out.println(o);
//获取私有的成员变量并赋值
Field name = c1.getDeclaredField("name");
System.out.println(name);
//暴力访问
name.setAccessible(true);
name.set(o,"王五");
System.out.println(o);
//默认修饰符的成员变量,不需要暴力访问
Field age = c1.getDeclaredField("age");
age.set(o,18);
System.out.println(o);
//被保护修饰的成员变量,也不需要暴力访问
通过反射获取Class文件对象中的成员方法并使用:
//获取Person类的Class文件对象
Class<?> c1 = Class.forName("com.shujia.wyh.day28.Person");
//获取方法
Method[] getMethods()
--返回包含一个数组方法对象反射由此表示的类或接口的所有公共方法 类对象,包括那些由类或接口和那些从超类和超接口继承的声明。
//获取本类以及父类中所有的公共方法(被public所修饰的方法)
Method[] methods = c1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
//获取本类中的所有方法,包括私有的,被保护的,默认的,公共的。不获取继承关系父类中的方法
Method[] declaredMethods = c1.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
System.out.println(declaredMethod);
}
Constructor<?> con1 = c1.getConstructor();
Object o = con1.newInstance();
//获取单个方法并使用
//Object invoke(Object obj, Object... args)
--在具有指定参数的 方法对象上调用此 方法对象表示的底层方法。
Method fun1 = c1.getMethod("fun1");
fun1.invoke(o);
//获取私有的成员方法并使用
Method fun2 = c1.getDeclaredMethod("fun2", String.class);
//暴力访问
fun2.setAccessible(true); --只有私有的成员方法通过反射调用的时候,需要暴力访问
fun2.invoke(o,"你好");
public void setProperty(Object obj, String propertyName, Object value){},
--此方法可将obj对象中名为propertyName的属性的值设置为value。
//通过反射获取对象对应的字节码文件对象
Class<?> c = obj.getClass();
//通过字节码文件对象获取对应的成员变量形成一个对象
try {
Field field = c.getDeclaredField(propertyName);
//设置暴力访问
field.setAccessible(true);
field.set(obj, value);
} catch (Exception e) {
e.printStackTrace();
}
--真实的开发场景不应该就输出一句话就完事了
--更多的是操作数据库
--通常在操作完数据库前后都有额外的步骤,在操作之前一般都会有一个权限校验,不是任何人都可以操作的
--操作完后一般会留下日志记录
--通过我们简单的分析并改动后,虽然实现了我们想要的功能,但是也仅限于这个案例
--如果在其他很多案例中也涉及到了权限校验和日志记录
--还是以这样的方式进行修改,会显得非常麻烦和繁琐
public void add(){
System.out.println("增加数据");
}
public void delete(){
System.out.println("删除数据");
}
public void update(){
System.out.println("更新数据");
}
public void select(){
System.out.println("查询数据");
}