反射
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<T> 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结构体系->代码调优
ClassLoader:
所有程序都由“.class"字节码文件储存,JDK执行时每个类都会存在相应的类加载器,获得这些类加载器依据Class类,Class类的方法:
Module [java.base] Package [java.lang] public ClassLoader getClassLoader()
ClassLodaer是一个抽象类
String系统类的getClassLoader()是个null,原因null是由JVM来实现的类加载器,我们的程序无法得到这个类加载器
自定义中的类加载器:
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 ; //返回二进制数据
}
}