summarize
反射可以理解为是解剖,把文件所有的内容地毯式的查看,通过暴力反射将私有的内容进行呈现,想解剖一个类,就得获取此类字节码文件对象,同时可以通过反射进行对象的创建。要知晓类的加载形成.class文件最先执行(在类进内存的时候),然后再执行静态内容。通过反射获取成员变量、方法或构造方法都有四种方法,可利用泛型擦除和反射在集合中添加任意类型的元素,也可以利用反射配置文件,运行指定类的指定方法
多线程针对于服务端(只修改服务端就可以让N个客户端对服务端进行上传)
package com.oracle.demo05; //文件上传多线程,服务端 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.ServerSocket; import java.net.Socket; //让它实现Runnable public class Upload implements Runnable{ private Socket socket=null; // 创建一个空参构造 public Upload(){} // 创建一个有参构造 public Upload(Socket socket){ this.socket=socket; } public void run() { FileOutputStream fos=null; try{ // 3.明确目的地 File file=new File("f:\java\nihao"); // 加个判定 如果该目录不存在,则创建 if(!file.exists()){ file.mkdirs(); } // 给文件加上条件,让它不会重复 String filename="oracle"+System.currentTimeMillis()+".txt"; // 明确目的地 fos=new FileOutputStream(file+File.separator+filename); // 明确数据源 InputStream in=socket.getInputStream(); // 开始复制 int len=0; byte[] bytes=new byte[1024]; while((len=in.read())!=-1){ fos.write(bytes, 0, len); } // 回复客户端 // 获取字节输出流,回复客户端 OutputStream out=socket.getOutputStream(); out.write("上传很成功".getBytes()); }catch(IOException ex){ ex.printStackTrace(); }finally{ // 释放资源 try{ fos.close(); }catch(IOException e){ e.printStackTrace(); } } } }
类加载器
类的加载: 当程序要使用某个类时,如果该类还未被加载到内存中,则系统会通过加载,连接,初始化三步来实现对这个类进行初始化。
加载:就是指将class文件读入内存,并为之创建一个Class对象。任何类被使用时系统都会建立一个Class对象
连接:验证 :是否有正确的内部结构,并和其他类协调一致
准备 :负责为类的静态成员分配内存,并设置默认初始化值
解析 :将类的二进制数据中的符号引用替换为直接引用
初始化:以前讲过的初始化步骤
类初始化时机:(进内存)
①. 创建类的实例
②. 类的静态变量,或者为静态变量赋值
③. 类的静态方法
④. 使用反射方式来强制创建某个类或接口对应的java.lang.Class对象
⑤. 初始化某个类的子类
⑥. 直接使用java.exe命令来运行某个主类
类加载器
负责将.class文件加载到内存中,并生成对应的Class对象。
类加载器的组成
①、Bootstrap ClassLoader 根类加载器:也称为引导类加载器,负责Java核心类的加载 比如System,String等。在JDK中JRE的lib目录下rt.jar文件中
②、Extension ClassLoader 扩展类加载器:负责JRE的扩展目录中jar包的加载 在JDK中JRE的lib目录下ext目录
③、 System ClassLoader 系统类加载器 :负责在JVM启动时加载来自java命令的class文件,以及classpath环境变量所指定的jar包和类路径
反射
反射: JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
Class类: Class
没有公共构造方法。Class对象是在加载类时由 Java 虚拟机以及通过调用类加载器中的 defineClass
方法自动构造的。
获取字节码的三种方式:
①、通过object类中的getobject()方法
②、通过 类名.class获取到字节码文件对象(任意数据类型都具备一个class静态属性)
③、通过Class类中的方法(将类名作为字符串传递给Class类中的静态方法forName即可)
package com.oracle.demo01; public class Person { private String name; public int age; public Person(){ System.out.println("public Person()"); } public Person(String name){ this.name=name; System.out.println("public Person(String name)"); } @Override public String toString() { return "Person [name=" + name + ", age=" + age + "]"; } private Person(int age){ this.age=age; System.out.println("private Person(int age)"); } static{ System.out.println("静态代码块"); } public void sleep(String name,int age){ System.out.println(name+"..."+age); System.out.println("public void sleep()"); } // 公有空参 public void eat(){ System.out.println("public void eat()"); } // 公有有参 public void sleep(String name){ System.out.println("public void sleep(String name)"); } // 私有有参 private void smoke(int age){ System.out.println("private void smoke(int age)"); } } --------------------------------------------------- package com.oracle.demo01; //获取类名三种方式 public class Demo01 { public static void main(String[] args) throws ClassNotFoundException { // 获取字节码文件对象 // 1.通过对象获取 Class c1=new Person().getClass(); System.out.println(c1); // 2.通过类名获取 Class c2=Person.class; System.out.println(c2); System.out.println(c1==c2);//双 = 比的是地址 // 3.通过Class类的静态方法获取 Class c3=Class.forName("com.oracle.demo01.Person");//forname在JDBC出现过 } }
通过反射获取构造方法并使用
构造方法使用类Constructor表示。可通过Class类中提供的方法获取构造方法:
1、返回一个构造方法
public Constructor<T> getConstructor(Class<?>... parameterTypes) 获取public修饰, 指定参数类型所对应的构造方法
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型所对应的构造方法(包含私有的)
2、 返回多个构造方法
public Constructor<?>[] getConstructors() 获取所有的public 修饰的构造方法
public Constructor<?>[] getDeclaredConstructors() 获取所有的构造方法(包含私有的)
package com.oracle.demo02; //通过反射获取构造方法并使用 import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import com.oracle.demo01.Person; public class Demo01 { public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { method02(); } public static void method01() throws ClassNotFoundException{ // 获取字节码文件对象 Class c=Class.forName("com.oracle.demo01.Person"); // 获取所有公共构造方法数组 //Constructor[] cons=c.getConstructors(); // System.out.println(cons);//重写toString方法得到地址 // 获取所有构造方法 Constructor[] cons=c.getDeclaredConstructors(); for(Constructor con:cons){ System.out.println(con); } } public static void method02() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ // 获取字节码文件对象 Class c=Class.forName("com.oracle.demo01.Person"); // 获取空参构造方法对象 Constructor con=c.getConstructor(); // 调用构造方法创建对象 Object obj=con.newInstance(); // 向下转型 Person p=(Person)obj; p.eat(); } public static void method03() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ // 获取字节码文件对象 Class c=Class.forName("com.oracle.demo01.Person"); // 获取有参构造方法对象 Constructor con=c.getConstructor(String.class); // 调用构造方法创建对象 Object obj=con.newInstance("张三"); // 向下转型 Person p=(Person)obj; p.eat(); }
通过反射,获取构造方法,创建对象
通过构造方法类Constructor中的方法,创建对象
public T newInstance(Object... initargs)
// 获得私有构造 // 暴力反射:相当于抢银行 违反我们面向对象的封装思想,破坏了程序的安全性。(不推荐使用) public static void method04() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{ // 获取字节码文件对象 Class c=Class.forName("com.oracle.demo01.Person"); // 获取有参构造方法对象 Constructor con=c.getConstructor(int.class); // 暴力反射:取消java语言,检测访问 con.setAccessible(true); // 调用构造方法创建对象 Object obj=con.newInstance("18"); // 向下转型 Person p=(Person)obj; p.eat(); } }
通过反射获取成员变量并使用
在反射机制中,把类中的成员变量使用类Field(成员变量类)表示。可通过Class类中提供的方法获取成员变量:
1、 返回一个成员变量
public Field getField(String name) 获取指定的 public修饰的变量
public Field getDeclaredField(String name) 获取指定的任意变量
2、 返回多个成员变量
public Field[] getFields() 获取所有public 修饰的变量
public Field[] getDeclaredFields() 获取所有的 变量 (包含私有)
package com.oracle.demo02; import java.lang.reflect.Field; public class Demo02 { public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException { method02(); } public static void method01() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException { // 获取字节码文件对象 Class c = Class.forName("com.oracle.demo01.Person"); // 获取公共的成员变量 Field f = c.getField("age"); // System.out.println(f); //快速创建对象----只能是空参的! Object obj=c.newInstance(); //给对象的成员变量赋值 f.set(obj, 18); System.out.println(obj); } public static void method02() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException { // 获取字节码文件对象 Class c = Class.forName("com.oracle.demo01.Person"); // 获取私有的成员变量 Field f = c.getDeclaredField("name"); // System.out.println(f); //暴力反射 f.setAccessible(true); //快速创建对象----只能是空参的! Object obj=c.newInstance(); //给对象的成员变量赋值 f.set(obj, "张三"); System.out.println(obj); } }
通过反射获取成员方法并使用
在反射机制中,把类中的成员方法使用类Method表示。可通过Class类中提供的方法获取成员方法:
1、返回获取一个方法:
public Method getMethod(String name, Class<?>... parameterTypes)
获取public 修饰的方法
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
获取任意的方法,包含私有的
参数1: name 要查找的方法名称; 参数2: parameterTypes 该方法的参数类型
2、 返回获取多个方法:
public Method[] getMethods() 获取本类与父类中所有public 修饰的方法
public Method[] getDeclaredMethods() 获取本类中所有的方法(包含私有的)
public Object invoke(Object obj, Object... args)
执行指定对象obj中,当前Method对象所代表的方法,方法要传入的参数通过args指定。
泛型擦除
泛型擦除:(注释和泛型不进class文件) 程序编译后产生的.class文件中是没有泛型约束的,这种现象我们称为泛型的擦除。那么,我们可以通过反射技术,来完成向有泛型约束的集合中,添加任意类型的元素
package com.oracle.demo03; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; //泛型擦除 import java.util.ArrayList; public class Demo01 { public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { // 泛型擦除 ArrayList<String> arr=new ArrayList<String>(); // arr.add(123);//不能进calss文件:1注释2泛型 // 反射 Class c=arr.getClass();//获得字节码文件对象 Method method=c.getMethod("add",Object.class); // 调用 method.invoke(arr, 123); System.out.println(arr); } }
反射配置文件
通过反射配置文件,运行配置文件中指定类的对应方法
读取Properties.txt文件中的数据,通过反射技术,来完成Person对象的创建
package com.oracle.demo04; //反射配置文件 import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Properties; public class Demo { public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { // 准备Properties集合存储键值对 Properties pro=new Properties(); // 明确数据源 FileReader fr=new FileReader("src/pro.properties"); // 将Properties文件中的键值对读取到Properties集合中 pro.load(fr); // 从properties结合中读取完整的包名+类名 String className=pro.getProperty("className"); // 从properties结合中读取方法名 String methodName=pro.getProperty("methodName"); // 获取字节码文件对象 Class c=Class.forName(className); // 快速创建对象 Object obj=c.newInstance(); // 获取成员方法对象 Method method=c.getMethod(methodName); // 调用方法 method.invoke(obj); // 释放资源 fr.close(); } }