一、认识反射
1.定义
反射指的是对象的反向处理,根据对象倒推类的组成。
核心类为Class类(专门描述其他类的组成)
Class类描述接口与类的组成,class对象在JVM第一次加载类时产生,并且全局唯一。
2.class对象的三种实例化模式
1.调用对象.getClass()取得其class对象;
2.类名称.class取得class对象;
3.Class.forName(类全名称);
通过反射实例化对象:public T newInstance(){}
实际上调用类中的无参构造,若类中没有无参构造或者权限不是public,此方法无法使用。
Class <Date> cls = Date.class;
Date date = cls.newInstance();
3.反射与工厂设计模式
interface IFruit{
void eat();
}
class Apple implements IFruit{
@Override
public void eat() {
System.out.println("eat an apple");
}
}
class Orange implements IFruit{
@Override
public void eat() {
System.out.println("eat an orange");
}
}
class Factory{
public static IFruit getInstanceof(String fruitName)throws Exception{
IFruit fruit = null;
Class<?> cls = Class.forName(fruitName);
fruit = (IFruit) cls.newInstance();
return fruit;
}
}
public class Test {
public static void main(String[] args) throws Exception {
IFruit fruit = Factory.getInstanceof("com.test.Reflect.Orange");
fruit.eat();
}
}
引入反射后,每当新增接口子类,无需去修改工厂类代码就可以很方便的进行接口子类扩容。以上这种工厂类代码我们称之为简单工厂模式。
二、反射与类操作
1.取得父类&父接口信息
取得包信息
public Package getPackage(){} //Package类用来描述包信息
取得父类的Class对象
public native Class<? super T> getSuperclass(){}
取得父接口的Class对象
public Class<?>[] getInterfaces() {}
interface IFruit1{}
interface IMess{}
class clson{}
class Cls extends clson implements IFruit1,IMess{}
public class test8_2 {
public static void main(String[] args) {
Class <?> cls = Cls.class;//取得Class类对象
System.out.println(cls.getPackage().getName());//取得包名称
System.out.println(cls.getSuperclass().getName());//父类的class类对象
Class<?> [] arr = cls.getInterfaces();
for (Class<?> a:arr) {
System.out.println(a.getName());//取得父接口的Class类对象
}
}
}
2.反射调用构造
取得类中指定参数类型的构造方法
public Constructor<T> getConstructor(Class<?> ...parameterTypes){}
public Constructor<T> getDeclaredConstructor(Class<?> ...parameterTypes){}
取得类中所有构造方法
public Constructor<?>[] getConstructors() throws SecurityException{ } //public权限
public Constructor<?>[] getDeclaredConstructors() throws SecurityException{} //所有权限
Constructor中实例化对象方法:
public T newInstance(Object ... initargs) throws
InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException{}
//若类中没有无参构造,只能调用Constructor类
//提供的newInstance方法使用有参构造实例化对象。
3.反射调用普通方法
取得类中指定名称与参数的普通方法
public Method getMethod(String name, Class<?>... parameterTypes)
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
取得全部普通方法
public Method[] getMethods() throws SecurityException
//取得本类以及父类所有public方法(包括静态方法)
public Method[] getDeclaredMethods() throws SecurityException
//取得本类中任意权限的所有方法
调用普通方法
public Object invoke(Object obj, Object... args)throws IllegalAccessException, IllegalArgumentException,InvocationTargetException
class Person1{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class test8_1 {
public static void main(String[] args) throws Exception {
//取得class对象
Class<Person> cls = Person.class;
//取得Method对象
String setMethodName = "setName";
String getMethodName = "getName";
Method setMethod = cls.getMethod(setMethodName,String.class);
Method getMethod = cls.getMethod(getMethodName);
//取得实例化对象
Person per = cls.newInstance();
setMethod.invoke(per,"张三");
System.out.println(getMethod.invoke(per));
}
4.反射调用类中属性
取得类中指定名称属性
public Field getField(String name){}
public Field getDeclaredField(String name){}
取得类中所有属性
public Field[] getField()//本类及父类publlic权限的所有属性
public Field[] getDeclaredField()//本类所有属性
设置与取得值
public void set(Object obj,Object value)
pulic Object get(Object obj)
取得属性类型:public Class<?> getType()
动态破坏封装(反射特性)
Constructor、Method、Field类都继承了AccessibleObject类,此类中有一个破坏封装的方法:
public void setAccessible(boolean flag)throws SecurityException
class test1{
private int age;
}
public class test8_2 {
public static void main(String[] args) throws Exception, IllegalAccessException, InstantiationException {
Class<?> cls = test1.class;
Object obj = cls.newInstance();
Field field = cls.getDeclaredField("age");
field.setAccessible(true);
field.set(obj,20);
System.out.println(field.get(obj));
}
}
三、ClassLoader类加载器
1.定义
通过一个类的全名称来获取此类的二进制字节流
2.JDK内置的三大类加载器
(1)BootStrap–启动类加载器
使用c++实现,是JVM自身的一部分,独立于JVM外部,并且无法被Java程序直接调用;
负责将存放于JAVA_HOME\lib目录下的能被JVM识别的所有库类加载到JVM中。
(2)ExtClassLoader–扩展类加载器
使用Java语言实现,可以被Java程序直接引用;
负责将存放于JAVA_HOME\lib\ext(xml文件解析类,界面框架类)目录下能被JVM识别的所有类库加载到JVM中。
(3)AppClassLoader–应用程序类加载器
使用Java程序实现,若用户没有自定义类加载器,则它为程序中默认的类加载器;
负责加载用户ClassPath指定的类库。
3.类加载器的双亲委派模型
(1)定义
四种类加载器的层次关系称为类加载器的双亲委派模型。
(2)工作流程
如果一个类加载器收到了类加载的请求,首先自己不会去尝试加载此类,而是将类加载请求委托给父类加载器完成,每一层的类加载器都是如此。只有当父加载器无法加载此类时,子加载器才会尝试自己去加载。
(3)意义
双亲委派模型对于java程序稳定运行十分重要。例如Java.lang.Object,他存放在rt.jar中,由于双亲委派模型的存在,无论在哪一类类加载器要加载此类,最终都是委派给处于顶端的启动类加载器进行加载,因此,Object类在程序的各种类加载器环境中都是一个类。
比较两个类是否相等的前提条件:这两个类是由同一个类加载器加载的。否则即使两个类来源于同一个class文件,被同一个JVM加载,只要加载这两个类的类加载不同,这两个类注定不相等。