java第二十天 类加载器,反射,获取对象并调用,简易的Tomcat

1.类加载器

public class ClassLoaderDemo {
	public static void main(String[] args) {
		//public static ClassLoader getSystemClassLoader()返回委托的系统类加载器
		ClassLoader loader = ClassLoader.getSystemClassLoader();
		System.out.println(loader);//sun.misc.Launcher$AppClassLoader@73d16e93
		//public final ClassLoader getParent()返回委托的父类加载器
		System.out.println(loader.getParent());//sun.misc.Launcher$ExtClassLoader@15db9742
		System.out.println(loader.getParent().getParent());//null
	}
}

2.获取字节码文件对象的方式

public class GetClassDemo {
	public static void main(String[] args) throws Exception {
		//通过属性名获取:类名.class
		Class clazz = Person.class;
		//通过对象名获取:对象名.getClass()
		Class clazz2 = new Person().getClass();
		//通过Class的静态方法:Class.forName(类的全路径名);
		Class clazz3 = Class.forName("cn.edu360.Person");//动态的配置路径
		
		//一个字节码文件只会被加载一次
		System.out.println(clazz==clazz2);//true
		System.out.println(clazz==clazz3);//true
	}
}

3.反射的应用,获取

import java.lang.reflect.Method;

public class ReflectMethod {
	public static void main(String[] args) throws Exception {
		//1.获取字节码文件对象
		Class clazz = Class.forName("cn.edu360.Person");
		//2.获取所有的成员方法打印
		//public Method[] getMethods()返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
		Method[] methods = clazz.getMethods();
		//public Method[] getDeclaredMethods()返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
		methods = clazz.getDeclaredMethods();
		for (Method m : methods) {
			System.out.println(m);
		}
		System.out.println("--------------------------------------------------------");

		//3.获取指定的成员方法对象并调用
		Person p = (Person) clazz.newInstance();
		
		//获取公共成员方法对象并调用
		//public Method getMethod(String name,Class<?>... parameterTypes)返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
		Method m = clazz.getMethod("show", null);
		System.out.println(m);//public void cn.edu360.Person.show()
		//public Object invoke(Object obj,Object... args)对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
		m.invoke(p, null);//哈哈哈
		System.out.println("--------------------------------------------------------");
	
		//获取受保护的成员方法对象并调用
		m = clazz.getDeclaredMethod("getSum", int.class,int.class);
		System.out.println(m);//protected int cn.edu360.Person.getSum(int,int)
		Object value = m.invoke(p, 100,50);
		System.out.println(value);//150
		System.out.println("--------------------------------------------------------");
		
		//获取默认修饰符的成员方法对象并调用
		m = clazz.getDeclaredMethod("method", null);
		System.out.println(m);//java.lang.String cn.edu360.Person.method()
		value = m.invoke(p, null);
		System.out.println(value);//今天天气很好啊
		System.out.println("--------------------------------------------------------");
		
		//获取私有成员方法对象并调用
		m = clazz.getDeclaredMethod("test", null);
		System.out.println(m);//private void cn.edu360.Person.test()
		//暴力反射
		m.setAccessible(true);
		m.invoke(p, null);//呵呵呵呵
	}
}

4.反射获取方法,暴力破解

public class ReflectConstructor {
	public static void main(String[] args) throws Exception {
		//1.获取字节码文件对象
		Class clazz = Class.forName("cn.edu360.Person");
		//2.获取所有的构造方法
		//public Constructor<?>[] getConstructors()返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
		Constructor[] constructors = clazz.getConstructors();
		//public Constructor<?>[] getDeclaredConstructors()返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。
		constructors = clazz.getDeclaredConstructors();
		for (Constructor c : constructors) {
			System.out.println(c);
		}
		System.out.println("--------------------------------------------------------");
		
		//3.获取指定的构造方法并创建对象
		
		//获取公共的无参构造方法并创建对象
		//public Constructor<T> getConstructor(Class<?>... parameterTypes)返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
		Constructor c = clazz.getConstructor(null);
		System.out.println(c);//public cn.edu360.Person()
		//public T newInstance(Object... initargs)使用此 Constructor 对象表示的构造方法来创建该构造方法的声明类的新实例,并用指定的初始化参数初始化该实例。
		Object obj = c.newInstance(null);
		System.out.println(obj);//Person [name=null, age=0, sex=
		//当类中有空参构造方法时,可以直接使用字节码文件对象的newInstance
		//public T newInstance()创建此 Class 对象所表示的类的一个新实例
		obj = clazz.newInstance();
		System.out.println(obj);//Person [name=null, age=0, sex=
		System.out.println("--------------------------------------------------------");
		
		//获取受保护的构造方法并创建对象
		c = clazz.getDeclaredConstructor(String.class);
		System.out.println(c);//protected cn.edu360.Person(java.lang.String)
		obj = c.newInstance("张三");
		System.out.println(obj);//Person [name=张三, age=0, sex=
		System.out.println("--------------------------------------------------------");
		
		//获取默认修饰符构造方法并创建对象
		c = clazz.getDeclaredConstructor(String.class,int.class);
		System.out.println(c);//cn.edu360.Person(java.lang.String,int)
		obj = c.newInstance("张三",18);
		System.out.println(obj);//Person [name=张三, age=18, sex=
		System.out.println("--------------------------------------------------------");
		
		//获取私有构造方法并创建对象
		c = clazz.getDeclaredConstructor(String.class,int.class,char.class);
		System.out.println(c);//private cn.edu360.Person(java.lang.String,int,char)
		//public void setAccessible(boolean flag)将此对象的 accessible 标志设置为指示的布尔值。值为 true 则指示反射的对象在使用时应该取消 Java 语言访问检查。值为 false 则指示反射的对象应该实施 Java 语言访问检查。 
		c.setAccessible(true);//暴力反射
		obj = c.newInstance("张三",18,'男');
		System.out.println(obj);//Person [name=张三, age=18, sex=男, address=null]
		System.out.println("--------------------------------------------------------");
		
		//获取私有构造方法并创建对象
		c = clazz.getDeclaredConstructor(String.class,int.class,char.class,String.class);
		System.out.println(c);//private cn.edu360.Person(java.lang.String,int,char,java.lang.String)
		//取消java语法检查
		c.setAccessible(true);
		obj = c.newInstance("张三",18,'男',"北京");
		System.out.println(obj);
	}
}

5.获取指定字段的对象并赋值取值

import java.lang.reflect.Field;

public class ReflectField {
	public static void main(String[] args) throws Exception {
		//1.获取字节码文件对象
		Class clazz = Class.forName("cn.edu360.Person");
		//2.获取全部的字段打印
		//public Field[] getFields()返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段
		Field[] fields = clazz.getFields();
		//public Field[] getDeclaredFields()返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。包括公共、保护、默认(包)访问和私有字段,但不包括继承的字段。
		fields = clazz.getDeclaredFields();
		for (Field f : fields) {
			System.out.println(f);
		}
		System.out.println("--------------------------------------------------------");
		
		//3.获取指定的字段对象并取值和赋值
		Person p = (Person) clazz.newInstance();
		System.out.println(p);
		System.out.println("--------------------------------------------------------");
		
		//获取公共的字段并取值和赋值
		//public Field getField(String name)返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
		Field field = clazz.getField("name");
		System.out.println(field);//public java.lang.String cn.edu360.Person.name
		//public Object get(Object obj)返回指定对象上此 Field 表示的字段的值。
		Object value = field.get(p);//获取p对象上面的field字段表示的值
		System.out.println(value);//null
		//public void set(Object obj,Object value)将指定对象变量上此 Field 对象表示的字段设置为指定的新值
		field.set(p, "李四");//将p对象上面field表示的字段值设置为"李四"
		System.out.println(p);
		System.out.println("--------------------------------------------------------");

		//获取受保护的字段并取值和赋值
		field = clazz.getDeclaredField("age");
		System.out.println(field);//protected int cn.edu360.Person.age
		System.out.println(field.get(p));//0
		field.set(p, 20);
		System.out.println(p);//Person [name=李四, age=20, sex=
		System.out.println("--------------------------------------------------------");
		
		//获取默认修饰符的字段并取值和赋值
		field = clazz.getDeclaredField("sex");
		System.out.println(field);//char cn.edu360.Person.sex
		System.out.println(field.get(p));//
		field.set(p, '女');
		System.out.println(p);//Person [name=李四, age=20, sex=女, address=null]
		System.out.println("--------------------------------------------------------");
		
		//获取私有字段并取值和赋值
		field = clazz.getDeclaredField("address");
		System.out.println(field);//private java.lang.String cn.edu360.Person.address
		//取消java语法检查
		field.setAccessible(true);
		System.out.println(field.get(p));//null
		field.set(p, "上海");
		System.out.println(p);//Person [name=李四, age=20, sex=女, address=上海]
		
	}
}
public class Person {
	public String name;
	protected int age;
	char sex;
	private String address;

	public Person() {

	}

	protected Person(String name) {
		this.name = name;
	}

	Person(String name, int age) {
		this.name = name;
		this.age = age;
	}

	private Person(String name, int age, char sex) {
		this.name = name;
		this.age = age;
		this.sex = sex;
	}
	
	private Person(String name, int age, char sex, String address) {
		this.name = name;
		this.age = age;
		this.sex = sex;
		this.address = address;
	}

	public void show() {
		System.out.println("哈哈哈");
	}

	protected int getSum(int a, int b) {
		return a + b;
	}

	String method() {
		return "今天天气很好啊";
	}

	private void test() {
		System.out.println("呵呵呵呵");
	}

	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", sex=" + sex + ", address=" + address + "]";
	}
}


6.获取受保护的方法

import java.lang.reflect.Method;

public class ReflectMethod {
	public static void main(String[] args) throws Exception {
		//1.获取字节码文件对象
		Class clazz = Class.forName("cn.edu360.Person");
		//2.获取所有的成员方法打印
		//public Method[] getMethods()返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法
		Method[] methods = clazz.getMethods();
		//public Method[] getDeclaredMethods()返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
		methods = clazz.getDeclaredMethods();
		for (Method m : methods) {
			System.out.println(m);
		}
		System.out.println("--------------------------------------------------------");

		//3.获取指定的成员方法对象并调用
		Person p = (Person) clazz.newInstance();
		
		//获取公共成员方法对象并调用
		//public Method getMethod(String name,Class<?>... parameterTypes)返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
		Method m = clazz.getMethod("show", null);
		System.out.println(m);//public void cn.edu360.Person.show()
		//public Object invoke(Object obj,Object... args)对带有指定参数的指定对象调用由此 Method 对象表示的底层方法。
		m.invoke(p, null);//哈哈哈
		System.out.println("--------------------------------------------------------");
	
		//获取受保护的成员方法对象并调用
		m = clazz.getDeclaredMethod("getSum", int.class,int.class);
		System.out.println(m);//protected int cn.edu360.Person.getSum(int,int)
		Object value = m.invoke(p, 100,50);
		System.out.println(value);//150
		System.out.println("--------------------------------------------------------");
		
		//获取默认修饰符的成员方法对象并调用
		m = clazz.getDeclaredMethod("method", null);
		System.out.println(m);//java.lang.String cn.edu360.Person.method()
		value = m.invoke(p, null);
		System.out.println(value);//今天天气很好啊
		System.out.println("--------------------------------------------------------");
		
		//获取私有成员方法对象并调用
		m = clazz.getDeclaredMethod("test", null);
		System.out.println(m);//private void cn.edu360.Person.test()
		//暴力反射
		m.setAccessible(true);
		m.invoke(p, null);//呵呵呵呵
	}
}

7.反射的案例

(1)

public class Monday implements WeekInter{

	@Override
	public void say() {
		System.out.println("周一特价菜是红烧肉");
	}

	@Override
	public void howMuch() {
		System.out.println("只要25块钱");
	}
	
}

(2)

public class Tuesday implements WeekInter{

	@Override
	public void say() {
		System.out.println("周二特价菜是毛血旺");
	}

	@Override
	public void howMuch() {
		System.out.println("只要18块钱");
	}

}

(3)

public class Wednesday implements WeekInter{

	@Override
	public void say() {
		System.out.println("周三的特价菜是水煮肉");
	}

	@Override
	public void howMuch() {
		System.out.println("只要20块钱");
	}

}

(4)

public interface WeekInter {
	void say();

	void howMuch();
}

(5)

import java.io.FileReader;
import java.io.Reader;
import java.lang.reflect.Method;
import java.util.Properties;

public class ReflectTest {
	public static void main(String[] args) {
		// 1.将配置文件中的类名和方法名读取出来
		Properties p = new Properties();
		try (Reader reader = new FileReader("D:/week.txt");) {
			// 2.将文件内容加载到p中
			p.load(reader);
			// 3.取出类名
			String className = p.getProperty("className");
			// 4.取出方法名
			String s = p.getProperty("methodName");
			String[] arr = s.split(",");
			String methodName1 = arr[0];
			String methodName2 = arr[1];
			// 5.通过反射动态的调用方法
			Class clazz = Class.forName(className);
			Object obj = clazz.newInstance();// 创建一个对应类的对象

			Method method1 = clazz.getMethod(methodName1, null);
			method1.invoke(obj, null);// 执行方法

			Method method2 = clazz.getMethod(methodName2, null);
			method2.invoke(obj, null);// 执行方法
		} catch (Exception e) {
			e.printStackTrace();
		}

	}
}

(6)

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

public class ReflectTest2 {
	public static void main(String[] args) throws Exception {
		// 我给你ArrayList<String>的一个对象,我想在这个集合中添加一个整型数据,如何实现呢?
		ArrayList<String> list = new ArrayList<String>();
		list.add("哈哈哈");
		list.add("嘿嘿嘿");
		// list.add(11);//因为定义了明确的泛型是String,所以只能添加String类型,我们想添加int类型的值就需要绕过泛型
		System.out.println(list);// [哈哈哈, 嘿嘿嘿]

		// 泛型只存在编译时期,编译成.class文件之后就会消失,所以我们可以使用反射的方式往list集合中添加内容

		// 1.获取ArrayList的字节码文件对象
		Class clazz = list.getClass();
		// 2.获取add方法对象
		Method add = clazz.getMethod("add", Object.class);
		// 3.执行add方法
		add.invoke(list, 120);
		add.invoke(list, 12.12);
		add.invoke(list, true);

		System.out.println(list);// [哈哈哈, 嘿嘿嘿, 120, 12.12, true]
	}
}

(7)

import java.lang.reflect.Field;

public class ReflectTest3 {
	public static void main(String[] args) {
		Person p = new Person();
		setProperty(p,"age",18);
		System.out.println(p.getAge());//18
	}

	//内省的原理
	
	// 写一个方法,此方法可将obj对象中名为propertyName的属性的值设置value
	public static void setProperty(Object obj, String propertyName, Object value) {
		//1.获取obj对象对应的字节码文件对象
		Class clazz = obj.getClass();
		try {
			//2.获取propertyName属性对应的对象
			Field field = clazz.getDeclaredField(propertyName);
			//3.设置值
			field.setAccessible(true);//取消java语法检查
			field.set(obj, value);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}

class Person {
	private int age;

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}
}

7.动态代理

(1)

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/*
 * java中使用动态代理,被代理的类必须有实现的接口,代理类只能代理接口中的方法
 */
public class ProxyDemo {
	public static void main(String[] args) {
		StudentDao dao = new StudentDao();
		dao.insert();
		dao.update();
		dao.query();
		dao.delete();
		System.out.println("---------------------------");
		
		/*
		 * public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
		 *	loader - 定义代理类的类加载器
			interfaces - 代理类要实现的接口列表
			h - 指派方法调用的调用处理程序 
		 */
		Object instance = Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new MyInvocationHandler(dao));
		
		//想代理TableInter里面的方法,就将instance强转成TableInter对象
		TableInter ti = (TableInter) instance;
		ti.insert();
		ti.update();
		ti.query();
		ti.delete();
		
		//想代理InterTest里面的方法,就将instance强转成InterTest对象
		InterTest it = (InterTest) instance;
		it.show("哈哈哈哈哈");
	}
}

// InvocationHandler 是代理实例的调用处理程序 实现的接口
class MyInvocationHandler implements InvocationHandler {
	// 传入被代理的对象
	private Object obj;

	public MyInvocationHandler(Object obj) {
		this.obj = obj;
	}

	/*
	 * proxy-代理实例对象 method-就是我们代理的方法 args-调用方法时传递的参数
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object value;
		//判断如果method方法是show方法,就不需要检查权限和记录日志
		if(method.getName().equals("show")){
			 value = method.invoke(obj, args);//被代理的方法执行
		}else{
			//在方法执行之前做一些事情
			System.out.println("检查权限");

			value = method.invoke(obj, args);//被代理的方法执行
			
			//在方法执行之后做一些事情
			System.out.println("记录日志");
			System.out.println("---------------------------");
		}
		return value;
	}

}

(2)

public class StudentDao implements TableInter,InterTest {

	@Override
	public void insert() {
		System.out.println("插入学生信息...");
		
	}

	@Override
	public void update() {
		System.out.println("更新学生信息...");
	}

	@Override
	public void delete() {
		System.out.println("删除学生信息...");
	}

	@Override
	public void query() {
		System.out.println("查询学生信息...");
	}

	@Override
	public void show(String msg) {
		System.out.println(msg);
	}

}

(3)

//CRUD:增删改查
public interface TableInter {
	void insert();
	void update();
	void delete();
	void query();
}

(4)

public interface InterTest {
	void show(String msg);
}

8.手动开发一个Tomcat

(1)

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;

public class Tomcat {
	public static void main(String[] args) throws Exception {
		// 1.创建ServerSocket对象并监听指定的端口
		ServerSocket ss = new ServerSocket(8888);
		// 2.循环接收客户端的请求
		while (true) {
			Socket s = ss.accept();
			// 3.打印一下客户端的请求数据
			// 将字节读取流包装成字符缓冲读取流
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			String line = br.readLine();// GET /register.html HTTP/1.1

			System.out.println(line);
			// 4.拼接资源的路径
			String resourcePath = "webapps" + line.split(" ")[1];
			System.out.println(resourcePath);

			// 5.将访问的资源页面返回给浏览器
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(resourcePath));
			BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());

			// 把响应行返回给浏览器,告诉浏览器你访问成功了
			bos.write("HTTP/1.1 200 ok\r\n\r\n".getBytes());

			// 循环读写
			byte[] buf = new byte[1024];
			int len;
			while ((len = bis.read(buf)) != -1) {
				bos.write(buf, 0, len);
			}
			bos.flush();// 将数据刷新到浏览器端
			// 6.关闭资源
			bis.close();
			s.close();
		}
	}
}

(2)

import java.net.ServerSocket;
import java.net.Socket;

public class Tomcat2 {
	public static void main(String[] args) throws Exception {
		// 1.创建ServerSocket对象并监听指定的端口
		ServerSocket ss = new ServerSocket(8888);
		// 2.循环接收客户端的请求
		while (true) {
			Socket s = ss.accept();
			// 接收到一个请求之后,就将请求任务交给子线程来处理
			ThreadPoolUtils.execute(new TomcatRunnable(s));
		}
	}
}

(3)

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.net.Socket;

public class TomcatRunnable implements Runnable {
	private Socket s;

	public TomcatRunnable(Socket s) {
		super();
		this.s = s;
	}

	@Override
	public void run() {
		// 3.打印一下客户端的请求数据
		// 将字节读取流包装成字符缓冲读取流
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
			String line = br.readLine();// GET /register.html HTTP/1.1

			System.out.println(line);
			// 4.拼接资源的路径
			String resourcePath = "webapps" + line.split(" ")[1];
			System.out.println(resourcePath);

			// 5.将访问的资源页面返回给浏览器
			BufferedInputStream bis = new BufferedInputStream(new FileInputStream(resourcePath));
			BufferedOutputStream bos = new BufferedOutputStream(s.getOutputStream());

			// 把响应行返回给浏览器,告诉浏览器你访问成功了
			bos.write("HTTP/1.1 200 ok\r\n\r\n".getBytes());

			// 循环读写
			byte[] buf = new byte[1024];
			int len;
			while ((len = bis.read(buf)) != -1) {
				bos.write(buf, 0, len);
			}
			bos.flush();// 将数据刷新到浏览器端
			// 6.关闭资源
			bis.close();
			s.close();
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

}

(4)

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ThreadPoolUtils {
	private static ExecutorService threadPool = Executors.newCachedThreadPool();

	public static void execute(Runnable command) {
		threadPool.execute(command);
	}
}

反射图解介绍



服务器图解



请求


响应




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值