【JavaSE】反射

反射

package Review;  
import java.lang.reflect.Constructor;  
/*反射1  
* 使用Class类对象,实例化某个类对象——不用使用关键字new  
* 步骤一:获取Class对象的三种方式:  
* 1.利用Object中的getClass();  
* 2.使用“所需实例类.class;:”  
* 3.Class类提供的forName("类完整名称"):Class.forName();  
* 注意:此返回的是Class类型的实例 ,例Class clazz = Person.class;  
* 步骤二:  
* 实例化类对象 Object obj = clazz.getDeclaredConstructor().nweInstance();* */  
  
  
/*反射2  
* 利用Class对象获取有关类信息  
* 1.获取有关所属包信息 java.lang.Class getPackage()* 2.获取有关构造方法 :步1:获取构造方法,步2:这些构造方法 用java.lang.reflect.Constructor类的实例表示  
* 3.获取有关方法:Method  
* 4.获取有关成员属性:Field*/  

class Mail {  
    private String msg ;  
    public Mail() {}  
    public Mail(String msg) {  
        System.out.println("【构造方法】");  
        this.msg = msg;  
    }  
  
    @Override  
    public String toString() {  
        return "Mail{" +  
                "msg='" + msg + '\'' +  
                '}';  
    }  
}  
  
public class ReflectTest {  
    public static void main(String[] args) throws Exception {  
        Class<?> cls = Mail.class ;  
        Constructor<?> constructors[] = cls.getDeclaredConstructors(); //获取全部构造  
        for (Constructor<?> cons : constructors) {  
            System.out.println(cons);  
        }  
        Constructor<?> cons = cls.getDeclaredConstructor(String.class);  
        Object obj = cons.newInstance("www.hhh.com");  //Constructure中的  
        System.out.println(obj);  
        }  
}


类加载器

类加载器->JVM结构体系->代码调优
【JavaSE】反射_第1张图片

ClassLoader:
所有程序都由“.class"字节码文件储存,JDK执行时每个类都会存在相应的类加载器,获得这些类加载器依据Class类,Class类的方法:
Module [java.base] Package [java.lang] public ClassLoader getClassLoader()
ClassLodaer是一个抽象类
String系统类的getClassLoader()是个null,原因null是由JVM来实现的类加载器,我们的程序无法得到这个类加载器
自定义中的类加载器:

【JavaSE】反射_第2张图片

Bootstrap:专门加载系统类;
AppfoemClassLoader:应用程序类加载器,用户自己定义的加载器,
PlatformClassLoader:普通类加载器
为何区分出多个类加载器?
原因:实现“双亲加载”,为了提高类加载器的安全级别,系统类使用系统类加载器,用户自定义使用自定义加载器,防止恶意程序与系统类重名所造成的恶意加载

package Review;  
class Book {}  
public class ClassLoaderTest {  
    public static void main(String[] args) {  
        Class<?> clazz = Book.class ;  
        System.out.println(clazz.getClassLoader());  
        System.out.println(clazz.getClassLoader().getParent());  
        System.out.println(clazz.getClassLoader().getParent().getParent());  
    }  
}

输出:
jdk.internal.loader.ClassLoaders$AppClassLoader@66d3c617
jdk.internal.loader.ClassLoaders$PlatformClassLoader@119d7047
null

自定义类加载器:
为什么要自定义类加载器?
答:Java中提供CLASSPATH属性,类加载的时候需要将类名称保存在包目录结构才可以加载,如果希望直接加载磁盘类文件,就需要自定义类加载器。
步骤1:自定义加载器类继承ClassLoader父类且依据方法调用
步骤2:定义要加载的字节码文件所处的绝对路径,必须通过File进行路径的拼凑。
步骤3:加载ClassLoader里的方法defineClass()

protected final Class defineClass(String name, byte[] b, int off, int len)  
    throws ClassFormatError  
{  
    return defineClass(name, b, off, len, null);  
}
//接受参数:
“String name”:要加载的类名称
“byte[] b”:要加载类文件的字节信息
“int off”:字节数组的开始位置
“int len” :最终有多少个字节需要参与到此次加载
例:
package Review;  
  
import java.io.*;  
  
//自定义类加载器必须继承“ClassLoader”父类,依据方法调用  
public class FileClassLoader extends ClassLoader {  //创建专属文件加载器  
    //定义要加载的字节码文件所处的绝对路径,必须通过File进行路径的拼凑  
    private static final String CLASS_FILE_PATH = "" + File.separator + "";  
    //自定义类加载的方法,此方法不可以重名  
    public Class<?> loadData(String className) throws Exception {  
        byte data [] =this.loadFileClassData() ; //加载要使用的类文件  
        if (data != null) {  //若类成功加载  
            return super.defineClass(className, data, 0, data.length) ;  
        }  
        return null ;  
    }  
    //自定义新方法,将根据给定的文件路径进行加载,为了简化没有一个的异常控制  
    private byte[] loadFileClassData() throws Exception{  
        //获取要加载文件的二进制字节输入流对象  
        InputStream input = new FileInputStream(new File(CLASS_FILE_PATH)) ;  
        //最终需要将所有的数据保存在内存之中,并且利用文字数组返回  
        ByteArrayOutputStream bos = new ByteArrayOutputStream() ; //内存输出流  
        input.transferTo(bos) ; //解决字节数据的读取  
        byte data [] = bos.toByteArray();  //获取全部的Class文件数据  
        input.close() ;  
        bos.close();  
        return data ;  //返回二进制数据  
    }  
}

你可能感兴趣的:(java)