綠 青 色

UDP和反射

ThreadLocal

局部线程变量:每个线程都拥有共享资源的副本,其中一个线程修改了共享资源的副本不会影响其他线程

Tomcat、JDBC、微服务

ThreadLocal常用方法:initialValue() 为共享资源赋初始值

​ get():获取共享资源

 public T get() {
     	//获取当前线程
        Thread t = Thread.currentThread();
     	//以当前线程为key获取ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //条件成立表示:ThreadLocalMap已经被创建了
        if (map != null) {
            //获取Entry(Key 就是当前线程,Value就是共享资源),以当前对象作为参数
            ThreadLocalMap.Entry e = map.getEntry(this);
            //条件成立:Entry的值,也就是共享资源
            if (e != null) {
                @SuppressWarnings("unchecked")
                T result = (T)e.value;
                return result;
            }
        }
     //ThreadLocalMap内部类没有被创建,设置初始值
        return setInitialValue();
    }

 private T setInitialValue() {
     //调用被覆盖的方法
        T value = initialValue();
     //获取当前线程
        Thread t = Thread.currentThread();
     //获取静态内部类ThreadLocalMap对象
        ThreadLocalMap map = getMap(t);
     //条件成立:表示静态内部类创建成功,将键值对设置到静态内部类ThreadLocalMap
        if (map != null)
            map.set(this, value);
     //条件不成立:创建静态内部类ThreadLocalMap,将键值对设置到静态内部类ThreadLocalMap
        else
            createMap(t, value);
        return value;
    }

​ set(T) : 设置共享资源

    public void set(T value) {
        Thread t = Thread.currentThread();
        //获取当前线程的ThreadLocalMap
        ThreadLocalMap map = getMap(t);
        //条件成立:设置键值对,条件不成立:创建ThreadLocalMap,设置键值对
        if (map != null)
            map.set(this, value);
        else
            createMap(t, value);
    }

​ remove() sinceJDK1.5

ThreadLocalMap是ThreadLocal的静态内部类,也是ThreadLocal的核心,共享资源的数据就存储在该内部类中,Key是当前线程,Value就是你指定的共享资源对象

1.3Java网络编程

TCP:面向连接的协议,先连接在发送和接受数据
TCP三次握手
Java的TCP协议:全部封装为Socket(客户端套接字)和ServerSocket(服务器套接字)
new Socket(ip,port);
new ServerSOcket(port);
客户端和服务器通信,端口必须一致
每当客户端向服务器发送一次请求都会创建一个Socket对象,也就是说SOcket对象可能被创建有一次,也有可能别创建多次。
ServerSOcket只创建一次
服务器必须知道是哪个客户端发起的请求  accept();该方法是一个阻塞式的方法,返回一个客户端套接字对象
Socket很单纯:getInputStream()  获取套接字的输入流
    		 getOutputStream() 获取套接字的输出流
    		 客户端和服务器使用上述方法来发送和接受数据

2Socket的字节流传输

场景:客户端上传文件到服务器端

步骤:

package com.whsxt.day16.upload;

import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
	public static void main(String[] args) {
		try(
				ServerSocket ss = new ServerSocket(12345);
				) {
			Server server =new Server();
			server.receiveClientData(ss);
			
		} catch (Exception e) {
			System.err.println("服务器下载失败");
			e.printStackTrace();
		}
	}
	
	/**
	 * 接受客户端数据
	 * @param ss
	 * @throws Exception
	 */
	public void receiveClientData(ServerSocket ss)throws Exception{
		try(
				Socket socket = ss.accept();
				InputStream in = socket.getInputStream();
				DataInputStream dis = new DataInputStream(in);
				//存储客户端接受的数据
				ByteArrayOutputStream bos = new ByteArrayOutputStream();
				){
			//接受客户端文件的后缀 .png
			String stuff = dis.readUTF();
			//接受客户端上传的文件数据
			int length = 0;
			byte [] buf = new byte[1024];
			//使用服务器套接字的输入管道读取客户端上传的数据
			while((length=dis.read(buf))!=-1) {
				//读取的数据写入到内存流
				bos.write(buf, 0, length);
			}
			bos.flush();
			//使用FileOutputStream将内存流的数据写入磁盘
			try(
					//服务器磁盘路径:当前时间的毫秒数+客户端上传的文件名后缀
					FileOutputStream fis = new FileOutputStream(System.currentTimeMillis()+stuff);
					BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()))
					){
				fis.write(bos.toByteArray());
				fis.flush();
				//服务器向客户端发送上传成功
				bw.write("上传成功");
				bw.newLine();
				bw.flush();
			}
		}
	}
}
package com.whsxt.day16.upload;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;

public class Client {
	public static void main(String[] args) {
		Client client = new Client();
		try {
			client.upLoad();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void upLoad()throws Exception{
		try(
				Socket socket = new Socket("localhost", 12345);
				InputStream in = socket.getInputStream();
				OutputStream out = socket.getOutputStream();
				//创建管道读取客户端磁盘数据
				BufferedInputStream input = new BufferedInputStream(new FileInputStream("ThreadLocal.png"));
				//创建输出管道将读取的数据发送到服务器,参数就是套接字的输出流对象
				DataOutputStream dos = new DataOutputStream(out);
				BufferedReader br = new BufferedReader(new InputStreamReader(in));
				){
			//向服务器发送后缀
			dos.writeUTF(".png");
			int length =0;
			byte [] buf =new byte[1024];
			//读取客户端磁盘数据,发送数据到服务器,每次发送1024bytes
			while((length = input.read(buf))!=-1) {
				//读取的数据使用套接字的输出管道发送到服务器
				dos.write(buf, 0, length);
			}
			dos.flush();
			//向服务器发送结束标志,告诉服务器所有的数据全部发送完毕
			//断开和服务器的输出管道   向服务器发送-1
			socket.shutdownOutput();
			//接受服务器发送的相应结果
			String responseMsg = br.readLine();
			System.out.println(responseMsg);
		}
	}
}

UDP

数据报协议:无连接协议

没有客户端和服务器的说法

只有发送方(发送数据)和接收方(接受发送方的数据)

UDP传输数据比TCP快,不要等待对方的连接

特征:UDP以包为介质进行数据传输

​ TCP以流为介质传输数据

DatagramSocket:UDP套接字

DatagramPackage: UDP传输数据的包,UDP发送方的数据和接收方的数据都封装在该包中

场景:发送方发送数据,接收方接收数据

接收方步骤:

1 创建UDP数据报套接字

2 创建UDP包

3 调用UDP包对象的接收方法来接收数据

4 转换数据并且打印接收的数据

package com.whsxt.day16.receive;

import java.net.DatagramPacket;
import java.net.DatagramSocket;

/**
 * @author caojie
 * UDP 接收方
 */
public class Receive {
	public static void main(String[] args) {
		try(
				DatagramSocket socket = new DatagramSocket(23456);
				){
			//创建数据报的包来接受数据
			//UDP是一个无连接协议,所以接收方不用知道发送方是谁
			//参数1:发送方的数据  参数2:从第几个偏移量开始读取 参数3:读取长度
			byte [] buf = new byte[1024];
			DatagramPacket pck =new DatagramPacket(buf, 0, buf.length);
			//使用套接字接收数据,将接受的数据存储到buf
			socket.receive(pck);
			//转换buf的数据为String 参数1:接收方数据报包的数据, 数据报包的偏移量,数据报包的长度
			String str = new String(pck.getData(), pck.getOffset(),pck.getLength());
			System.out.println(str);
		}catch(Exception e) {
			e.printStackTrace();
		}
	}
}

发送方步骤:

1创建UDP数据报套接字

2 定义要发送的内容

3 创建UDP包

4 发送数据

package com.whsxt.day16.receive;

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;

/**
 * @author caojie
 * UDP 发送方
 */
public class Send {
	public static void main(String[] args) {
		try(
				DatagramSocket socket = new DatagramSocket();
				) {
			String msg="我的J0812";
			//InetAddress.getLocalHost() 自己给自己发送接收接受
			//InetAddress.getByName("https://www.baidu.com") 发送给百度
			
			DatagramPacket pck = new DatagramPacket(msg.getBytes(),msg.getBytes().length, InetAddress.getLocalHost(), 23456);
			socket.send(pck);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

读取配置文件

package com.whsxt.day16.utils;

import java.io.InputStream;
import java.util.Properties;

/**
 * @author caojie
 * 将磁盘配置文件的数据加载到 Propertis缓存中
 */
public class J0812Properties {
	
	private static Properties props = new Properties();
	
	static {
		//Thread.currentThread().getContextClassLoader() 当前线程的类加载器加载配置文件到InputStream管道
		try(InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("j0812.properties")) {
			if(null ==in) {
				throw new RuntimeException("配置文件加载失败");
			}
			//将管道的数据加载到缓存Properties
			props.load(in);
		} catch (Exception e) {
			e.printStackTrace();
			throw new RuntimeException("配置文件初始化失败");
		}
	}
	
	public static String getString(String key) {
		return props.getProperty(key);
	}
	
	public static int getInt(String key) {
		String value = props.getProperty(key);
		return Integer.parseInt(value);
	}
}

# 配置文件
ipaddress=localhost
port=23456

4反射(重点)

4.1生活中的反射

4.2为什么学习反射

一个项目有很多个功能,你并不知道客户会使用哪个功能,如果客户选择使用功能1,你会通过反射加载功能1,然后再使用反射创建该类型的对象。

在程序执行期根据客户的选择去加载类型,使用反射创建对象,目的就是让你的程序更加灵活,避免硬编码

4.3概念

程序在执行期动态获取Class类型的信息.

反射的前提入射:一个class文件通过ClassLoader加载到JVM,会为class文件在内存产生唯一的一个Class类型对象.

4.4ClassLoader

类加载器

有哪些类加载器:

package com.whsxt.day16.reflect;

public class TestClassLoader {
	public static void main(String[] args) {
		//sun.misc.Launcher$AppClassLoader@73d16e93
		//加载我们应用程序classpath(存放字节码路径)下面的class文件(字节码)
		//我们当前程序的classpath相对路径为day16/bin,所以说AppClassLoader加载day16/bin路径下面所有的文件
		ClassLoader loader = TestClassLoader.class.getClassLoader();
		System.out.println(loader);
		//sun.misc.Launcher$ExtClassLoader@15db9742
		//ExtClassLoader:加载那些呢路径下面的文件?\jdk1.8.0_101\jre\lib\ext路径下面所有的文件
		ClassLoader extClassLoader =loader.getParent();
		System.out.println(extClassLoader);
		//ExtClassLoader的父加载器是BootstrapClassLoader
		ClassLoader bootClassLoader = extClassLoader.getParent();
		//BootstrapClassLoader用C++编写的,所以打印结果无法显示
		System.out.println(bootClassLoader);
		String classPath =System.getProperty("sun.boot.class.path");
		/*
		 BootstrapClassLoader加载那些路径下面的文件
		 D:\Program Files\Java\jdk1.8.0_101\jre\lib\resources.jar;
		 D:\Program Files\Java\jdk1.8.0_101\jre\lib\rt.jar;
		 D:\Program Files\Java\jdk1.8.0_101\jre\lib\sunrsasign.jar;
		 D:\Program Files\Java\jdk1.8.0_101\jre\lib\jsse.jar;
		 D:\Program Files\Java\jdk1.8.0_101\jre\lib\jce.jar;
		 D:\Program Files\Java\jdk1.8.0_101\jre\lib\charsets.jar;
		 D:\Program Files\Java\jdk1.8.0_101\jre\lib\jfr.jar;
		 D:\Program Files\Java\jdk1.8.0_101\jre\classes
		 * */
		System.out.println(classPath);
	}
}

小结:ClassLoader(类加载器)唯一职责就是将classpath路径下面的class文件和其他文件加载到JVM中

类加载器顺序:BootstarpClassLoader ---->ExtClassLoader----->AppClassLoader

4.5Class类型

每个class文件加载到JVM中就会在堆内存中创建一个Class类型的对象,该对象就是反射的入口

注意:Class类型的对象不是我创建的是JVM在程序运行期帮我们创建的

如何获取Class类型的对象?三种方式

package com.whsxt.day16.reflect;

public class TestClass {
	public static void main(String[] args) {
		//第一种方式获取Class类型的对象: 类型的class属性
		Class<?> clazz =String.class;
		//class java.lang.String
		System.out.println(clazz);
		//////////////////////////
		//第二种方式获取Class类型的对象:类型对象的getClass()方法
		String name="Tomson";
		Class<?> _class = name.getClass();
		System.out.println(_class);
		/////////////////////////////////
		//声明ClassNotFoundException异常所有,必须处理异常
		try {
			//第一种方式获取Class类型的对象  Class类型的静态方法forName("");
			Class<?> classes = Class.forName("java.lang.String");
			System.out.println(classes);
			//小结:String类型的Class对象不管调用多少次,
			//总是得到相同的内存地址,也就意味着在内存中只有一份java.lang.String
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

4.6获取Class类型对象的信息

4.6.1包信息
4.6.2类型信息

4.6.3类型修饰符信息

4.6.4父类型信息

4.6.5接口信息

package com.whsxt.day16.reflect;

import java.lang.reflect.Modifier;
import java.util.ArrayList;

public class TestArrayList {
	public static void main(String[] args) {
		Class<?> clazz =ArrayList.class;
		Package pck = clazz.getPackage();
		String packageName = pck.getName();
		//ArrayList在java.util包下面
		//获取类型信息名称
		//java.util.ArrayList  包名+类名=全名 
		String className = clazz.getName();
		//ArrayList 没有包名称的类名称信息
		String simpleName =clazz.getSimpleName();
		//获取访问修饰符信息
		int modify = clazz.getModifiers();
		String modifier = Modifier.toString(modify);
		//判断clazz是接口还是类
		String type = clazz.isInterface()?" interface ":" class ";
		StringBuilder sb= new StringBuilder(50);
		sb.append("package ").append(packageName).
		append(".").append(simpleName).append(";\r\n")
		.append(modifier).append(type).append(simpleName);
		//获取父类型信息
		Class<?> superClass = clazz.getSuperclass();
		//父类型类名称
		String superName = superClass.getSimpleName();
		sb.append(" extends ").append(superName);
		//获取接口信息
		Class<?> interfaceClass []=clazz.getInterfaces();
		sb.append(" implements ");
		//一个类可能实现一个接口可能实现多个接口,也可能无接口
		//遍历ArrayList实现的接口Class对象
		for (Class<?> interClass : interfaceClass) {
			//ArrayList接口Class对象的名称
			String interfaceName = interClass.getSimpleName();
			sb.append(",").append(interfaceName);
		}
		sb.append("{");
		String typeInfo = sb.toString();
		typeInfo = typeInfo.replaceFirst(",", "");
		System.out.println(typeInfo);
	}
}

4.7获取属性(字段)信息

前提:获取Class类型的对象,它是反射的入口

注意:一个类可能有一个属性信息,也可能有多个属性信息,还有可以无属性

package com.whsxt.day16.reflect;

import java.lang.reflect.Field;
import java.util.ArrayList;


/**
 * @author caojie
 *  程序运行时使用反射获取ArrayList类型的属性信息
 */
public class TestArrayListField {
	public static void main(String[] args) {
		Class<?> clazz= ArrayList.class;
		//Field 菲尔德  Declared 声明
		// 获取ArrayList所有的声明字段
		Field [] fields =clazz.getDeclaredFields();
		/**
		 private static final long java.util.ArrayList.serialVersionUID
		 private static final int java.util.ArrayList.DEFAULT_CAPACITY
		 private static final java.lang.Object[] java.util.ArrayList.EMPTY_ELEMENTDATA
		 private static final java.lang.Object[] java.util.ArrayList.DEFAULTCAPACITY_EMPTY_ELEMENTDATA
		 transient java.lang.Object[] java.util.ArrayList.elementData
		 private int java.util.ArrayList.size
		 private static final int java.util.ArrayList.MAX_ARRAY_SIZE
		 
		  private static final修饰符 
		  long 数据类型
		  java.util.ArrayList.serialVersionUID 属性名称=包名+类名+属性名
		 * */
		for(Field field : fields) {
			System.out.println(field);
		}
	}
}

如何获取Filed的修饰符、数据类型、名称

package com.whsxt.day16.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.ArrayList;

/**
 * @author caojie
 * 获取ArrayList的Filed详细信息
 */
public class TestArrayListFileDetails {
	public static void main(String[] args) {
		//<?> 任意类型
		Class<?> clazz=ArrayList.class;
		Field [] fields=clazz.getDeclaredFields();
		for(Field field : fields) {
			//获取修饰符
			int modifer =field.getModifiers();
			String modify = Modifier.toString(modifer);
			/**
			 * 26	private static final
			 * 128	transient
			 * 2	private
			 * 1    public
			 * */
			//获取字段的数据类型信息
			Class<?> fieldType = field.getType();
			//属性类型信息的类型名称(没有包名)
			String fieldTypeName=fieldType.getSimpleName();
			//获取字段名称
			String name = field.getName();
			System.out.println(modify+" "+fieldTypeName+" "+name+";");
		}
	}
}

4.8获取方法信息

前提:获取Class类型的对象,它是反射的入口

注意:一个类可能有一个方法信息,也可能有多个方法信息,还有可以无方法

package com.whsxt.day16.reflect;

import java.lang.reflect.Method;
import java.util.ArrayList;

/**
 * @author caojie
 * 获取ArrayList的方法签名信息
 * public boolean java.util.ArrayList.add(java.lang.Object)
public void java.util.ArrayList.add(int,java.lang.Object)
public boolean java.util.ArrayList.remove(java.lang.Object)
public java.lang.Object java.util.ArrayList.remove(int)
public java.lang.Object java.util.ArrayList.get(int)
public java.lang.Object java.util.ArrayList.clone()
public int java.util.ArrayList.indexOf(java.lang.Object)
public void java.util.ArrayList.clear()
public boolean java.util.ArrayList.contains(java.lang.Object)
public boolean java.util.ArrayList.isEmpty()
public java.util.Iterator java.util.ArrayList.iterator()
public int java.util.ArrayList.lastIndexOf(java.lang.Object)
public void java.util.ArrayList.replaceAll(java.util.function.UnaryOperator)
public int java.util.ArrayList.size()
public java.util.List java.util.ArrayList.subList(int,int)
public java.lang.Object[] java.util.ArrayList.toArray(java.lang.Object[])
public java.lang.Object[] java.util.ArrayList.toArray()
public java.util.Spliterator java.util.ArrayList.spliterator()
static int java.util.ArrayList.access$100(java.util.ArrayList)
public boolean java.util.ArrayList.addAll(int,java.util.Collection)
public boolean java.util.ArrayList.addAll(java.util.Collection)
private void java.util.ArrayList.readObject(java.io.ObjectInputStream) throws java.io.IOException,java.lang.ClassNotFoundException
private void java.util.ArrayList.writeObject(java.io.ObjectOutputStream) throws java.io.IOException
public void java.util.ArrayList.forEach(java.util.function.Consumer)
public java.lang.Object java.util.ArrayList.set(int,java.lang.Object)
public void java.util.ArrayList.ensureCapacity(int)
public void java.util.ArrayList.trimToSize()
private void java.util.ArrayList.ensureCapacityInternal(int)
java.lang.Object java.util.ArrayList.elementData(int)
private void java.util.ArrayList.grow(int)
private static int java.util.ArrayList.hugeCapacity(int)
public java.util.ListIterator java.util.ArrayList.listIterator(int)
public java.util.ListIterator java.util.ArrayList.listIterator()
public boolean java.util.ArrayList.removeAll(java.util.Collection)
public boolean java.util.ArrayList.removeIf(java.util.function.Predicate)
protected void java.util.ArrayList.removeRange(int,int)
public boolean java.util.ArrayList.retainAll(java.util.Collection)
public void java.util.ArrayList.sort(java.util.Comparator)
private java.lang.String java.util.ArrayList.outOfBoundsMsg(int)
private void java.util.ArrayList.rangeCheckForAdd(int)
private boolean java.util.ArrayList.batchRemove(java.util.Collection,boolean)
private void java.util.ArrayList.ensureExplicitCapacity(int)
private void java.util.ArrayList.fastRemove(int)
private void java.util.ArrayList.rangeCheck(int)
static void java.util.ArrayList.subListRangeCheck(int,int,int)

private (访问)修饰符
void 返回类型
rangeCheck方法名称
(int,int,int) 参数类型
 */
public class TestArrayListMethod {
	public static void main(String[] args) {
		Class<?> clazz =ArrayList.class;
		//获取ArrayList的所有声明的方法信息
		Method methods[]=clazz.getDeclaredMethods();
		for (Method method : methods) {
			System.out.println(method);
		}
	}
}

获取方法信息Method的详细信息:修饰符、返回类型、方法名称、参数类型

package com.whsxt.day16.reflect;

import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.Parameter;
import java.util.ArrayList;

/**
 * @author caojie
 *获取方法信息Method的详细信息:修饰符、返回类型、方法名称、参数类型
 *0 friendly
 *1 public
 *2 private
 *4 protected
 *8 static
 *10 private static
 *4104 static
 */
public class TestArrayListMethodDetails {
	public static void main(String[] args) {
		Class<?> clazz=ArrayList.class;
		Method methods[] =clazz.getDeclaredMethods();
		//遍历所有的方法签名信息
		for(Method method : methods) {
		    //获取方法修饰符
			int modify = method.getModifiers();
			String mod =Modifier.toString(modify);
			//获取方法返回类型的Class信息
			Class<?> returnType =method.getReturnType();
			//返回类型的名称
			String returnTypeName=returnType.getSimpleName();
			//获取方法名称
			String methodName =method.getName();
			//获取参数类型的Class信息 SinceJDK1.8
			Parameter params [] = method.getParameters();
			//使用StringBuilder拼接参数类型
			StringBuilder sb = new StringBuilder(30);
			sb.append("(");
			//获取每个方法签名的参数类型(有的方法是无参,不用遍历)
			for(Parameter param :params) {
				//返回方法参数的修饰符,但是绝大多数方法的参数没有修饰符
				//int methodModify = param.getModifiers();
				//String methodMod= Modifier.toString(methodModify);
				//System.out.println(methodModify+" "+methodMod);
				Class<?> paramType =param.getType();
				//获取参数类型
				String paramSimpleType=paramType.getSimpleName();
				//参数名称
				String paramName =param.getName();
				sb.append(",").append(paramSimpleType).append(" ").append(paramName);
			}
			sb.append(")");
			String paramsName =sb.toString();
			//参数列表的第一个逗号替换为空格
			paramsName = paramsName.replaceFirst(",", "");
			//遗留问题:方法声明的异常信息没有完成,作为作业
			System.out.println(mod+" "+returnTypeName+" "+methodName+" "+paramsName);
		}
	}
}

4.9获取构造方法信息

package com.whsxt.day16.reflect;

import java.lang.reflect.Constructor;
import java.util.ArrayList;

/**
 * @author caojie
 * 获取ArrayList构造方法信息
 * public java.util.ArrayList(java.util.Collection)
   public java.util.ArrayList()
   public java.util.ArrayList(int)
 */
public class TestArrayListConstructor {
	public static void main(String[] args) {
		Class<?> clazz=ArrayList.class;
		try {
			Constructor<?> constructors[] = clazz.getDeclaredConstructors();
			for (Constructor<?> constructor : constructors) {
				System.out.println(constructor);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
posted @ 2020-03-25 20:15  LYANG-A  阅读(227)  评论(0编辑  收藏  举报