0303 TCP多线程上传文件,类加载,反射
已经写过单线程的上传文件的方法,那我们怎么样实现多个客户端同时链接服务器上传文件呢
代码展示 服务器端
public class UPload implements Runnable{ private Socket socket; public UPload(Socket socket) { super(); this.socket = socket; } public UPload() { super(); } public void run() { //明确数据源 //读取客户端发送过来的数据 try { InputStream in = socket.getInputStream(); //明确目的地文件的位置 File file=new File("F:\\io1127\\server"); //如果文件夹不存在 就创建 if(!file.exists()){ file.mkdirs(); } //明确文件名 String filename="oracle"+System.currentTimeMillis()+new Random().nextInt(9999)+".jpg"; //明确目的地 FileOutputStream fos=new FileOutputStream(file+File.separator+filename); //开始复制 byte[] bytes=new byte[1024]; int len=0; while((len=in.read(bytes))!=-1){ fos.write(bytes,0,len); } //回复客户端 //获取字节输出流 OutputStream out=socket.getOutputStream(); //回复内容 out.write("收到".getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } }
代码展示服务器
public class TCPSever { public static void main(String[] args) throws IOException { //创建服务器对象 ServerSocket server=new ServerSocket(8888); while(true){ //创建连接 Socket socket=server.accept(); //创建线程并开启 new Thread(new UPload(socket)).start(); } } }
代码展示客户端(客户端代码没有改变)
public class TCPlient { public static void main(String[] args) throws UnknownHostException, IOException { //创建客户端对象明确服务器端的ip和端口号 Socket socket=new Socket("192.168.1.171",8888); //明确读取数据的数据源 FileInputStream fis=new FileInputStream("F:\\io1127\\3.jpg"); //明确目的地 获得字节输出流 OutputStream out=socket.getOutputStream(); int len=0; byte[] bytes=new byte[1024]; while((len=fis.read(bytes))!=-1){ out.write(bytes,0,len); } //告知服务器端结束 socket.shutdownOutput(); //接收服务器端的回复 InputStream in=socket.getInputStream(); len=in.read(bytes); System.out.println("服务器端回复:"+new String(bytes,0,len)); //释放资源 socket.close(); } }
1、类加载
当程序使用某个类的时候,如果该类未被加载到内存中,则系统就会通过加载,链接,初始化三个步骤进行类的初始化
(1)加载,就是将class文件读入内存,并为之创建一个Class对象,在任何一个类被使用的时候会创建一个Class对象,该文件叫字节码文件
图解:
(2)链接,
验证,是否有真做正确的内部结构,与其他类协调一致
准备,负责为类的静态成员分配内存,并设置默认初始化值
解析,将二进制中的符号引用替换为直接引用
(3)初始化,
类的初始化机制(什么时候类被加载到内存)
1、创建类对象
2、类的静态变量或者为静态变量赋值
3、类的静态方法
4、反射
5、初始化某个子类
6、直接使用java.exe运行某个主类
是谁让让类加载到内存中,并为之生成class对象呢,就是类的加载器
类的加载器将.class文件加载到内存中,并为之生成class文件
(1)根类加载器,跟类加载器用于加载jdk中写好的一些类,例如String System类
(2)扩展类加载器,就是加载那些我们引入的那些jar包 jdbc驱动包啊,commensIO之类的jar包
(3)系统类加载器,一般加载我们自定义的类,加载java命令的class文件
那么类已经加载到内存了,那我们如何获得这个Class类的字节码文件,并获得里边的多有内容呢
获取字节码文件对象,获取这个类所有的成员变量也好成员方法也好等等这些东西,这个过程就叫做反射。
获取Class类字节码文件的方式 三种
先创建一个Person类
public class Person { private int age; String name; public Person() { System.out.println("public person()"); } private Person(String name) { System.out.println("private person(String name)"); } public void eat(){ System.out.println("public void eat()"); } public void sleep(String name){ System.out.println("public void sleep(String name)"); } }
创建测试类 获取字节码文件
public static void main(String[] args) throws ClassNotFoundException { //通过object中getclass方法 获取字节码对象 Person p=new Person(); Class c=p.getClass(); System.out.println(c); //通过类名调用class属性获取 Class c2=Person.class; System.out.println(c2); //forname 方法 Class c3=Class.forName("com.oracle.demo02.Person"); System.out.println(c3); }
‘
能够获取到字节码文件 怎样获取里边的构造方法并且使用呢
在反射机制中,把类中的成员(构造方法、成员方法、成员变量)都封装成了对应的类进行表示
构造方法使用类Constructor表示
这个构造方法类中提供了返回构造方法的方法,我们先看返回一个构造方法的方法
public Constructor<T> getConstructor(Class<?>... parameterTypes)获取public修饰指定参数类型的构造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)获取指定参数类型的构造方法(公有和私有都包括在内)
构造方法类Constructor中有一个public T newInstance(Object... initargs) 方法 创建一个构造方法类对象
代码展示
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { //获取字节码文件对象 Class c=Class.forName("com.oracle.demo02.Person"); //获取字节码文件对象构造方法 公共 Constructor con=c.getConstructor(); System.out.println(con); //创建对象 Person p=(Person)con.newInstance(); p.eat(); }