反射(Reflection)
-
允许在程序运行状态中,可以获取任意类中的属性和方法,并且可以操作任意对象内部的属性和方法,这种动态获取类的信息及动态操作对象的属性和方法对应的机制称为反射机制
- 类的对象 —> 类的实例,基于定义好的类创建实例对象(new)
- 类对象 —> 类加载的产物,封装了该类的相关信息(包名、类名、接口、父类、属性、构造方法、成员方法等) —> 每个类的类对象只有一个
- 通过类对象产生的对象称为类的对象
-
通过反射的技术获取类对象
-
通过类的对象获取类对象 —> Class 类对象 = 类的对象 . getClass();
-
通过类名 . class获取类对象
-
通过Class类中的静态方法 forName ( 包名 . 类名 ) 获取类对象
—> Class 类对象 = Class.forName(“包名 . 类名”)
—> 包名 . 类名称为权限命名,简称全类名
-
-
通过Class类中方法获取类对象相关信息
-
Object newInstance —> 通过反射获取一个类的对象(实例)
Class c = Class.forName("day16.Student"); //获取类对象 Object o = c.newInstance(); //新的实例 通过newInstance方法获取实例对象,默认使用类中无参构造方法
-
public Constructor getConstructor(Class<?>… parameterTypes)
- 先获取对应参数构造方法,参数指定构造方法参数类型、个数、顺序
- Constructor里也提供了newInstance
//通过类对象,使用有参构造方法创建类的对象 Constructor c = c.getConstructor(String.class,Integer.class,Double.class); Object o = c.newInstance("hang",18,10.0);//借助有参数构造方法获取一个实例,给形参赋值
-
Method getDeclareMethod(String name,Class<>…parameterTypes) —> 方法名,可变长参数,返回值Method
- setAccessible设置访问权限
- Method中有invoke()方法,调用私有方法
-
public Package getPackage() —> Package下面由getName()方法
-
getName() —> 获取全类名
-
public Class<> getSupergetSuperclass() —> Class下的getName()方法
-
public Class<>[] getInterfaces() —> Class下的getName()方法,返回值为Class类型数组
-
public Field[] getFields() —> 返回Field类型数组,获取父类+本类中的公开属性,包括接口
-
getDeclareFields() —> 返回Field类型数组,获取自身定义的属性,包括非公开的
-
public Method[] getMethods —> 获取本类+父类中公开方法
-
Method[] getDeclaredMethods() —> 获取自定义的方法,包含非公开的
-
-
public final Class —> 对象建模的类的类型 —> java.lang.Object —> 由Class产生的对象称为类对象 —> 无构造方法,仅供jvm使用
-
反射技术的优缺点
优点 | 缺点 |
---|---|
利用反射技术进行程序设计,可以让程序更加的通用、灵活 反射技术通常用于底层设计,例如框架或工具类等 | 利用反射技术进行设计,可读性相对较差 |
反射可以打破封装,私有化的内容可以通过反射技术在类以外的地方使用 |
- 反射是用于底层设计的技术,封装是开发应用层设计的需求,应用层实体类要求封装
类加载的时机
- 第一次创建该类对象
- 第一次访问类中的静态成员(静态属性和静态方法)
- 子类类加载会导致其父类先类加载
- 通过反射技术会导致一个类进行类加载
设计模式(23种)
-
一套被反复使用、多数人知晓、经过分类编目的代码经验总结
-
单例设计模式 —> 基于定义好的一个类,jvm中只能存在该类的一个实例对象
单例实现方式:
//一、饿汉式 ---> 多线程并发获取时并发效率相对较高,空间利用率相对较低
class ClassA{
private static final ClassA ca = new ClassA();
private ClassA(){ }
public static ClassA getInstance(){
return ca;
}
}
//二、懒汉式 ---> 并发效率相对较低,空间利用率相对较高
class ClassA{
private static ClassA cb;
private ClassA(){ }
public synchronized static ClassA getInstance(){
if(cb == null)
cb = new ClassA();
return cb;
}
}
//第三种
class ClassA{
private ClassA(){ }
//外部类加载的时候,内部类不加载,节省空间
static class Inner{
static final ClassA c = new ClassA();//在类加载的时候初始化,所以安全性也保证了
}
public static ClassA getInstance(){
return Inner.c;
}
}
饿汉式 | 懒汉式 | |
---|---|---|
优点 | 多线程并发获取时,并发效率相对较高,且该单例对象是在该类类加载时完成的创建,保证了多个线程获取单一对象,保证了安全性 | 空间利用率相对较高,使用时才会创建对象 |
缺点 | 空间利用率相对较低,初始化时就创建了对象 | 方法为同步方法,并发效率相对较低 |
- 工厂设计模式 —> 工厂设计模式通常会借助反射技术提高通用性和灵活性,也通常使用properties加载配置文件 —> 借助文件将源文件中可变的内容从代码中抽取,放在文件中,利用IO流技术进行读取
- 主要解决对象创建的问题,将对象的创建和对象的使用者进行分离,提高代码的灵活性
- 开闭原则 —> 一个软件产品,应该对修改关闭,对功能的拓展设计打开
//第一种
class USBFactory{
public static USB getInstance(String className){
if("KeyBoard".equals(className))
return new KeyBoard();
else if("Mouse".equals(className))
return new Mouse();
else if("Fun".equals(className))
return new Fun();
else
return null;
}
}
//第二种
class USBFactory{
public static USB getUSBInstance(String className) throws Exception {
Class c = Class.forName(className);
Object o = c.newInstance();
return (USB)o;
}
}
//第三种
class USBFactory{
public static USB getUSBInstance() throws Exception {
//通过IO 读取文件获取想要的类名
FileReader fr = new FileReader("file/config.txt");
BufferedReader br = new BufferedReader(fr);
String str = br.readLine();
String[] s = str.split("=");
Class c = Class.forName(s[1]);
Object o = c.newInstance();
return (USB)o;
}
}
//第四种
class USBFactory{
public static USB getUSBInstance() throws Exception {
//通过IO 读取文件获取想要的类名
Properties pro = new Properties();
FileInputStream fis = new FileInputStream("file/config.txt");
pro.load(fis);
Class c = Class.forName(pro.getProperty("className"));
Object o = c.newInstance();
return (USB)o;
}
}
- Properties是Map实现类,key和value默认为String类型
- Properties中 load ( InputStream) / load ( Reader)自动将输入流指向文件加载到Properties中,文件中一行内容对应一个元素,同时自动以 ’ = ’ 或 ’ : ’ 做拆分,= 左侧作为key,右侧作为value
- Properties中String getProperty(String key) —> 根据键获取对应value