Java反射基础_SXL
引言
做个俗人,贪财好色,一身正气。
一、反射基本概念
JAVA反射机制是程序在运行状态中,可以构造任意一个类的对象 , 可以了解任意一个对象所属的类,了解任意一个类的属性和成员方法,以及可以调用它们。这就是反射机制,是动态语言的关键。
二、类加载器
Java类加载器(Java Classloader)是Java运行时环境(Java Runtime Environment)的一部分,负责动态加载Java类到Java虚拟机的内存空间中。
java默认有三种类加载器,BootstrapClassLoader、ExtensionClassLoader、AppClassLoader。
BootstrapClassLoader(引导启动类加载器):嵌在JVM内核中的加载器,该加载器是用C++语言写的,主要负载加载JAVA_HOME/lib下的类库,引导启动类加载器无法被应用程序直接使用。
ExtensionClassLoader(扩展类加载器):ExtensionClassLoader是用JAVA编写,且它的父类加载器是Bootstrap。是由sun.misc.Launcher$ExtClassLoader实现的,主要加载JAVA_HOME/lib/ext目录中的类库。
它的父加载器是BootstrapClassLoader。
App ClassLoader(应用类加载器):
App ClassLoader是应用程序类加载器,负责加载应用程序classpath目录下的所有jar和class文件。它的父加载器为ExtClassLoader类通常是按需加载,即第一次使用该类时才加载。
由于有了类加载器,Java运行时系统不需要知道文件与文件系统。学习类加载器时,掌握Java的委派概念很重要。
双亲委派模型:如果一个类加载器收到了一个类加载请求,它不会自己去尝试加载这个类,而是把这个请求转交给父类加载器去完成。
每一个层次的类加载器都是如此。因此所有的类加载请求都应该传递到最顶层的启动类加载器中,只有到父类加载器反馈自己无法完成这个加载请求(在它的搜索范围没有找到这个类)时,子类加载器才会尝试自己去加载。委派的好处就是避免有些类被重复加载。
默认加载的是src路径下的文件,但是当项目存在resource root目录时,就变为了加载resource root下的文件。
源码:
protected Class<?> loadClass(String name, boolean resolve)
throws ClassNotFoundException
{
synchronized (getClassLoadingLock(name)) {
// First, check if the class has already been loaded
Class<?> c = findLoadedClass(name);
if (c == null) {
long t0 = System.nanoTime();
try {
if (parent != null) {
c = parent.loadClass(name, false);
} else {
c = findBootstrapClassOrNull(name);
}
} catch (ClassNotFoundException e) {
// ClassNotFoundException thrown if class not found
// from the non-null parent class loader
}
if (c == null) {
// If still not found, then invoke findClass in order
// to find the class.
long t1 = System.nanoTime();
c = findClass(name);
// this is the defining class loader; record the stats
PerfCounter.getParentDelegationTime().addTime(t1 - t0);
PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);
PerfCounter.getFindClasses().increment();
}
}
if (resolve) {
resolveClass(c);
}
return c;
}
}
加载resource目录下的资源文件
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class Test {
public static void main(String[] args) throws IOException {
// 默认加载的是src路径下的文件,但是当项目存在resource root目录时,就变为了加载resource root下的文件。
InputStream is = test.class.getClassLoader().getResourceAsStream("config.txt");
BufferedReader br = new BufferedReader(new InputStreamReader(is));
String text = br.readLine();
System.out.println(text);
br.close();
}
}
三、反射获取
3.1 Class对象获取
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 第一种方式,通过类名.class 加载类
Class<Test> c1 = Test.class;
System.out.println(c1);
// 第二种方式,通过类对象获取类的信息
Test t = new Test();
Class<Test> c2 = (Class<Test>) t.getClass();
System.out.println(c2);
// 第三种方式 此方法是动态的 合理
Class c3 = Class.forName("Test");
System.out.println();
}
}
3.2 Constructor获取
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<Person> pClass = (Class<Person>) Class.forName("Person");
// 找到无参构造方法
Constructor<Person> c1 = pClass.getConstructor();
// 使用无参构造方法,创建对象
Person p1 = c1.newInstance();
System.out.println(p1);
// 有参构造
Constructor<Person> c2 = pClass.getConstructor(String.class, int.class);
// 使用有参构造方法,创建对象
Person p2 = c2.newInstance("王五", 12);
System.out.println(p2);
// 反射打破封装 外部调用私有 获取所有权限单个构造方法 getDeclaredConstructors 获取数组
Constructor<Person> c3 = pClass.getDeclaredConstructor(String.class);
c3.setAccessible(true);
Person p3 = c3.newInstance("王鲁");
System.out.println(p3);
}
}
class Person {
private String name;
private int age;
public Person() {
}
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = 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 +
'}';
}
}
3.3 获取Method
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 加载类
Class c1 = Class.forName("Person");
// 获取类的构造方法
Constructor c = c1.getConstructor();
Object o = c.newInstance();
// 获取类方法
Method setName = c1.getMethod("setName", String.class);
// getDeclaredMethod可以访问私有的
Method setAge = c1.getDeclaredMethod("setAge", int.class);
setAge.setAccessible(true);
// 参数1:哪个对象执行setName方法
// 参数2:调用方法时传递的参数 0-n
setName.invoke(o, "芝麻");
setAge.invoke(o, 18);
System.out.println(o);
}
}
class Person {
private String name;
private int age;
public Person() {
}
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
private void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.4 获取Field
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
public class Test {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchFieldException {
// 加载类
Class c1 = Class.forName("Person");
// 获取类的构造方法
Constructor ct = c1.getConstructor();
Object o = ct.newInstance();
Field name = c1.getDeclaredField("name");
name.setAccessible(true);
name.set(o, "王五");
System.out.println(o);
}
}
class Person {
private String name;
private int age;
public Person() {
}
private Person(String name) {
this.name = name;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
private void setAge(int age) {
this.age = age;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
3.5 获取注解信息
import java.lang.annotation.*;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws ClassNotFoundException {
// 框架大部分内部原理
Class c = Class.forName("Book");
/*Annotation[] annotations = c.getAnnotations();
for (Annotation a : annotations) {
System.out.println(a);
}*/
TableAnnotation ta = (TableAnnotation) c.getAnnotation(TableAnnotation.class);
String value = ta.value();
System.out.println(value);
Field[] fs = c.getDeclaredFields();
for (Field f : fs) {
ColumnAnnotation ca = f.getAnnotation(ColumnAnnotation.class);
System.out.println(f.getName() + "属性对应数据库的字段:" + ca.columnName() + ",数据类型:" + ca.type() + ",数据长度:" + ca.length());
}
}
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@interface TableAnnotation {
/**
* 用于标注类对应的表名称
* @return
*/
String value();
}
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@interface ColumnAnnotation {
/**
* 描述列名
* @return
*/
String columnName();
/**
* 描述类型
* @return
*/
String type();
/**
* 描述长度
* @return
*/
String length();
}
@TableAnnotation("Test_Book")
class Book {
@ColumnAnnotation(columnName = "id", type = "int", length = "11")
private int id;
@ColumnAnnotation(columnName = "name", type = "varchar", length = "50")
private String name;
@ColumnAnnotation(columnName = "info", type = "varchar", length = "1000")
private String info;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
@Override
public String toString() {
return "Book{" +
"id=" + id +
", name='" + name + '\'' +
", info='" + info + '\'' +
'}';
}
}
四、内省
基于反射 , java所提供的一套应用到JavaBean的API
一个定义在包中的类
拥有无参构造器
所有属性私有
所有属性提供get/set方法
实现了序列化接口
这种类, 我们称其为 bean类。
Java提供了一套java.beans包的api , 对于反射的操作, 进行了封装 。
实现对象的get和set方法
import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.Serializable;
public class Test {
public static void main(String[] args) throws IntrospectionException {
Class c = Express.class;
BeanInfo bi = Introspector.getBeanInfo(c);
PropertyDescriptor[] pds = bi.getPropertyDescriptors();
for (PropertyDescriptor pd : pds) {
System.out.println(pd.getReadMethod());
System.out.println(pd.getWriteMethod());
}
}
}
class Express implements Serializable {
private String number;
private String name;
private String phoneNumber;
private String address;
private Boolean flag;
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
this.phoneNumber = phoneNumber;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Boolean getFlag() {
return flag;
}
public void setFlag(Boolean flag) {
this.flag = flag;
}
}
总结
人生无限,缓缓起航,修正改错,在满足完成任务的条件下,追求完善,全身而退。