笔记——类型信息与反射

类型信息与反射

2.1.1 .class文件和.java文件

Java的编译器在编译Java类文件时,会将原有的文本文件翻译成二进制的字节码,并将这些字节码存储在.class文件中。对于只含有一个类或接口的Java类文件,编译后只产生一个.class文件;而对于一个含有多个类或接口的Java类文件,分情况为:①.Java只含一个类或接口,编译后只产生一个.class文件;②.Java存在内部类时,会产生多个.class文件,内部类文件命名为:外部类名+$+内部类名,③.Java文件中存在多个并行类或接口,编译时也会产生多个.class文件,文件命名为类名/接口名。

2.1.2 类型信息的加载

Java提供两种加载方式:①预先装载②按需装载

按需装载类的条件: 在程序运行过程中,当一个类的静态成员被第一次引用时,JVM就会去装载它,静态成员包括:静态方法、静态属性、构造方法。

 

类加载器:三种

1)bootstrap类加载器用于引导JVM,一旦调用Java.exe程序,bootstrap类加载器就开始工作。

2)extension类加载器负责加载标准扩展目录下的类,是编写程序变得简单。

3)system加载器是默认的加载器,它在环境变量CLASSPATH目录下查找相应的类。

 

表2-2 ClassLoader中与加载类相关的方法

方法说明
getParent() 返回该类加载器的父类加载器
loadClass(String name) 加载名称为name的方法,返回java.lang.Class类的实例
findClass(String name) 查找名称为name的类,返回java.lang.Class类的实例
findLoadedClass(String name) 查找名称为name的已经被加载过的类,返回java.lang.Class类的实例
resolveClass(Class<?> c) 链接指定的Java类
   

 

类加载的顺序:当一个类具有继承关系时,装载是从顶级类开始的,以此类推制止加载到这个类本身。

2.2核心类

2.2.1 Class类

获取Class对象的方法有多种:

① xxx.class Class<Person> clazz = Person.class;

②xxx.getClass()方法 Person.getClass()

③xxx.forname()方法 Class<?> clazz = Class.forName(String);

2.2.2获取Constructor对象

Constructor类专门用来描述构造函数

方法说明
getConstructior(Class parameterTypes... ) 用于获取para类的的Constructor对象,获取的构造方法必须为公有
getConstructors() 获取制动类的共有构造函数列表,如果没有则返回长度为0的Constructor数组
getDeclaredConstructor(Class ... parameterTypes) 获取(可公有、保护、私有)指定参数类型的构造函数描述对象
getDeclaredConstructors() 获取(所有)构造函数描述的对象列表

2.2.3获取Method对象

Method类对象用于描述类的单个方法(不含构造方法)。可通过Method类来获取方法的访问权限、参数类型、返回值类型等信息。

Class类提供了4个方法供编程人员获取方法的描述对象

方法说明
getMethod(String name,Class...paramrterTypes) 用于获取指定名称和参数类型的公有方法描述对象(包含继承自父类)
getMethods() 用于获取公有的方法描述对象列表(包含继承自父类)
getDeclaredMethod(String name,Class...paraTypes) 可获取非公有的指定名称和参数类型的方法描述对象
getDeclaredMethods() 用于获取类本身定义的所有方法描述对象

 

2.2.4获取Field对象

Field类的对象用于描述类的单个字段。可通过对Field对象来获取字段的访问权、字段信息等类型,并且可通过Field对象来动态地修改字段值

方法说明
getField(String name) 用于获取指定名称的公有Field对象
getFields() 用于获取指定类的共有属性描述对象Field列表
getDeclaredField(String name) 用于获取(可非公有)的指定名称的Field属性
getDeclaredFields() 获取一份Field数组,该数组记录指定类的所有属性的描述对象

 

2.4类型信息应用——反射

Java反射机制是指运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法,修改它的任意属性;这种动态获取的信息以及动态调用对象成员的功能称为Java语言的反射机制。

反射的应用:

举例:以下是一个继承Person类的Teacher类,教师有职称、薪水属性,能speak和getSalary

package org.ddd.reflect.example29;
​
public abstract class Person{
    public abstract String toString();
}
​
​
package org.ddd.reflect.example29;
​
​
public final class Teacher extends Person{
    
    public String position;
    private int salary;
    public void speak(String message) {
        System.out.println("Speak:" + message);
    }
    
    @Override
    public String toString() {
        return "[Position: "+ position + " Salary: " + salary + "]";
    }
    
    private int getSalary() {
        return this.salary;
    }
}
​
 

使用反射技术实现以下要求:

①显示的将这个类载入内存

②实例化这个类

③执行方法speak(String message)

④修改属性position

⑤修改受保护属性salary,以及执行私有方法getSalary()


1) 使用Class类提供的显示加载方法forName(String name)

public class Bootsrap {
    public static String className = "org.ddd.reflect.example29.Teacher";
    public static void main(String[] args) {
        try {
            System.out.println("开始加载类!");
            Class clazz = Class.forName(className);
            System.out.println("类加载完成!");
            
        }catch(ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
​
}
​
 

运行结果:

2)通过反射实例化类,有两种动态创建对象的方法,如Class类的newInstance方法实例化对象,或Constructor的newInstance方法

//实例1
package org.ddd.reflect.example29;
​
public class Bootsrap {
    public static String className = "org.ddd.reflect.example29.Teacher";
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName(className);
            Person person = (Person)clazz.newInstance();
            System.out.println(person.toString());
            
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
​
}
​
 

//示例二
import java.lang.reflect.Constructor;
​
public class Bootsrap {
    public static String className = "org.ddd.reflect.example29.Teacher";
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName(className);
            Constructor constructor = clazz.getConstructor();
            Person person = (Person)constructor.newInstance();
            System.out.println(person.toString());
            
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
​
}
​
 

 

3)通过反射执行方法

该方法名为“speak”,参数类型为String。class。要动态获取speak方法,首先要获取Method对象,method类拥有invoke方法,如下:

 

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
​
public class Bootsrap {
    public static String className = "org.ddd.reflect.example29.Teacher";
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName(className);
            Constructor constructor = clazz.getConstructor();
            Object teacher = constructor.newInstance();
            Method method = clazz.getMethod("speak", String.class);
            method.invoke(teacher, "Lesson one!");
            
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
​
}
​
 

运行结果:

4)通过反射修改属性,通过Field类的方法set,动态的给属性赋值

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
​
public class Bootsrap {
    public static String className = "org.ddd.reflect.example29.Teacher";
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName(className);
            Constructor constructor = clazz.getConstructor();
            Object teacher = constructor.newInstance();
            Field field = clazz.getField("position");
            System.out.println(teacher.toString());
            field.set(teacher, "Master");
            System.out.println(teacher.toString());
            
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
​
}

 

运行结果:

5)修改访问权限

正常情况下我们无法访问private修饰的salary,但是constructor的父类AccessbleObject提供了setAccessable(boolean flag)

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
​
public class Bootsrap {
    public static String className = "org.ddd.reflect.example29.Teacher";
    public static void main(String[] args) {
        try {
            Class clazz = Class.forName(className);
            Constructor constructor = clazz.getConstructor();
            Object teacher = constructor.newInstance();
            Method method = clazz.getDeclaredMethod("getSalary");
            method.setAccessible(true);
            Integer salary = (Integer)method.invoke(teacher);
            System.out.println("Teacher salary: " + salary);
            
        }catch(Exception e) {
            e.printStackTrace();
        }
    }
​
}

运行结果:

 

动态代理模式可参考以下博客:https://www.cnblogs.com/gonjan-blog/p/6685611.html

 

原文地址:https://www.cnblogs.com/wxx23-IOU/p/14438385.html