目录
一. 认识反射
1. 初识反射
反射指的是对象的反向处理,即根据对象倒推类的组成。
我们正常的关于对象的处理流程:根据包名.类名找到类。
这个“反”指的是根据对象来取得对象的来源信息,反射核心处理就在于Object类的一个方法:
取得Class对象:
该方法返回的是一个Class类对象,这个Class描述的就是类。
在反射的世界里面,看重的不再是一个对象,而是对象身后的组成(类、构造、普通、成员等)。
2. Class对象的三种实例化方式
任何一个类的Class对象由JVM加载类时产生(该对象在JVM中全局唯一),用户只能采用指定方法来取得该对象。
Class类对象的产生模式:
- 任何类的对象可以通过调用Object类提供的getClass()取得该类的Class对象。(对象.getClass())
- “类名称.class”可以直接根据某个具体类来取得其Class对象。
- 调用Class类的静态方法Class.forName(String className)传入类的全名称来取得其Class对象。 推荐
举例:
import java.util.Date;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
//正向产生对象
Date date = new Date();
//1.通过“类对象.getClass()”
System.out.println(date.getClass());
//2.通过“类名称.getClass"
System.out.println(Date.class);
//3.通过调用class类提供的静态方法forName(String className)
System.out.println(Class.forName("java.util.Date"));
}
}
取得一个类的class对象后,可以通过反射来实例化对象。
在Class类中有如下方法:
例:
3. 反射与工厂设计模式
简单工厂模式:
package www.like.java;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
interface IFruit{
void eat();
}
class Apple implements IFruit{
@Override
public void eat() {
System.out.println("eat an apple");
}
}
class Banana implements IFruit{
@Override
public void eat() {
System.out.println("eat a banana");
}
}
class Orange implements IFruit{
@Override
public void eat() {
System.out.println("eat an orange");
}
}
//工厂方法
class Factory{
private Factory(){}
//工厂方法模式
public static IFruit getInstance(String className){
IFruit fruit = null;
try{
//取得任意子类反射对象
Class<?> cls = Class.forName(className);
//通过反射取得实例化对象
fruit = (IFruit) cls.newInstance();
}catch (Exception e){
e.printStackTrace();
}
return fruit;
}
}
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
IFruit fruit = Factory.getInstance("www.like.java.Apple");
fruit.eat();
}
}
二. 反射与类操作
1. 反射取得父类、父接口信息
取得类的包名称:
取得父类的Class对象:(类只能单继承)
取得实现的父接口:(接口可以多继承)
基本数据类型在JVM中也有Class对象:
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
Class<?> cls1 = int.class;
Class<?> cls2 = Integer.class;
System.out.println(cls1);
System.out.println(cls2);
}
}
2. 反射调用类中构造方法
取得类中指定参数类型的构造:
只能取得类中public权限的构造方法
可以取得类中全部构造方法,包含私有构造
取得类中所有构造方法:
只能取得类中public权限的构造方法
可以取得类中所有构造方法(包含私有构造)
Constructor类提供了实例化对象的方法:
public T newInstance(Object ... initarges):可以调用类中其他有参构造
例:
package www.like.java;
import java.lang.reflect.Constructor;
class Person{
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) throws Exception {
Class<?> cls = Person.class;
Constructor constructor = cls.getConstructor(String.class,int.class);
Person person = (Person) constructor.newInstance("张三",20);
System.out.println(person);
}
}
3. 反射调用类中普通方法
取得类中指定名称的普通方法:
取得本类以及父类中所有public方法
取得本类中全部普通方法(包含私有方法)
取得类中全部普通方法:
取得本类以及父类中所有public方法
取得本类中全部普通方法(包含私有方法)
Method类中提供调用类中普通方法的API:
4. 反射调用类中属性
取得类中指定属性:
取得本类以及父类中所有public属性
取得本类中全部普通属性(包含私有属性)
取得类中全部属性:
取得本类以及父类中所有public属性
取得本类中全部普通属性(包含私有属性)
Filed类提供设置与取得属性方法:
设置属性:
取得属性:
取得属性类型:
例:
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
class Person{
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
public class Test {
public static void main(String[] args) throws Exception {
//1.拿到Person的Class对象
Class<?> cls = Person.class;
//2.创建Person的实例化对象
Person person = (Person) cls.newInstance();
//3.拿到setName的Method对象
Method setNameMethod = cls.getMethod("setName", String.class);
//4.通过invoke进行调用
setNameMethod.invoke(person,"张三");
System.out.println(person);
}
}
5. 动态设置封装
Constructor、method、Field类都是AccessibleObject子类。
AccessibleObject提供动态设置封装方法(在本次JVM进程中有效,且只能通过反射调用)
public void setAccessible(boolean flag) throws SecurityException
传入true之后就可以使用private权限的属性或者方法
三. ClassLoader类加载器---双亲委派模型
1. 认识ClassLoader
类加载器:通过一个类的全名称来获取类的二进制字节流,实现这个操作的代码模块称为类加载器。
JDK中内置的三大类加载器:
Bootstarp(启动类加载器):
- 使用C++实现,是JVM的一部分,其它所有类加载器均使用Java实现。
- 负责将存放于Java_HOME\lib目录下的能被JVM识别的类库(java.lang, java.util等等)加载到JVM中。
- 启动类加载器无法被Java程序直接引用。
ExtClassLoader(扩展类加载器):
- 使用Java实现,可以被Java程序直接引用。
- 加载Java_HOME\lib\ext目录下能被识别的类库。
AppClassLoader(应用程序类加载器):
- 负责加载用户路径(classpath)上指定的类库。
- 如果应用程序中没有自定义类加载器,则此加载器就是Java程序中默认的类加载器。
2. 类加载器双亲委派模型---JDK1.2引入
定义:JDK内置的三种类加载器与用户自定义的类加载器之间的层次关系称为类加载器的双亲委派模型。
要求除了顶层的父类加载器外,其余的类加载器都应有自己的父类加载器。
执行流程:如果一个类加载器收到了类加载的请求,它首先不会自己去尝试加载此类,而是把类加载器请求委托给父类完成,每一个层次类加载器均是如此。只有当父类加载器没有完成加载请求时(在自己搜索范围内没有找到此类),子加载器才会尝试自己去加载。
双亲委派模型保证了Java程序的稳定运行。Java中基础类库一定由顶层的Bootstarp类加载器加载,因此,诸如Object等核心类在各种加载器环境下都是同一个类。