Java——反射机制详解及实操
Java——反射机制详解及实操
作用
通过java语言中的反射机制可以操作(读/改)字节码文件
通过反射机制key操作代码片段(class文件)。
反射机制的相关的重要的类
反射机制的相关类均在 java.lang.reflect.*; 下
- java.lang.class :代表整个字节码文件,代表一个类型
- java.lang.reflect.Method :代表字节码中的方法字节码
- java.lang.reflect.Constructor :代表字节码中的构造方法字节码
- java.lang.reflect.Field :代表字节码中的属性字节码
java.lang.Class:
public class User{
//Field
int no;
//Constructor
public User() {
}
public User(int no) {
this.no = no;
}
//Method
public void setNo(int no) {
this.no = no;
}
public int getNo() {
return no;
}
}
获取java.lang.Class实例的三种方式
注:字节码文件装载到JVM中的时候,只装载一份
方式一:Class c = Class.forName(“完整类名带包名”);
- 静态方法
- 方法的参数是一个字符串
- 字符串需要的是一个完整类名
- 完整类名必须带有包名。java.lang包也不能省略。
public static void main(String[] args) {
try {
Class c1 = Class.forName("java.lang.String");//c1代表String。class文件;或者说c1代表String类型
Class c2 = Class.forName("java.util.Date");//c2代表Date类型
Class c3 = Class.forName("java.lang.Integer");//c3代表Integer类型
Class c4 = Class.forName("java.lang.System");//c4代表System类型
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
方式二:Class c = 引用getClass();
java中任何一个对象都有一个方法:getClass
public static void main(String[] args) {
String s = "abc";
Class x = s.getClass();//x代表String.class字节码文件;x代表String类型
}
方式三:Class c = 任何类型.class;
java语言中任何一种类型,包括基本数据类型,它都有.class属性
public static void main(String[] args) {
Class i = String.class;//i代表String类型
Class j = int.class;//j代表int类型
Class k = Date.class;//k代表Date类型
Class l = double.class;//l代表double类型
}
注:字节码文件装载到JVM中的时候,只装载一份
如:方式一和方式二获得的类型对象的内存是相同的
通过反射实例化对象——newInstance();
注:newInstance()方法内部实际上调用了无参构造方法,必须保证无参构造存在才可以。如果没有这个无参数构造方法会出现“实例化”异常
public static void main(String[] args) {
try {
//通过反射机制,获取Class,通过Class来实例化对象
Class c = Class.forName("com.xiaoli.User");//c代表User类型
Object obj = c.newInstance();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
通过反射实例化对象的优点——更加灵活
java代码写一遍,在不改变java源代码的基础之上,可以做到不同对象的实例化。
非常灵活。(符合OCP开闭原则:对扩张开放,对修改关闭)
例(验证):
创建一个属性配置文件
源码:
public static void main(String[] args) throws IOException {
//通过IO流读取ClassName文件
FileReader reader = new FileReader("D:\\IDEA\\untitled02\\ClassName");
//创建属性类对象Map
Properties pro = new Properties();//key value都是String
//加载
pro.load(reader);
//关闭流
reader.close();
//通过key获取value
String className = pro.getProperty("classname");
//通过反射实例化对象
try {
Class c = Class.forName(className);
Object obj = c.newInstance();
System.out.println(obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
灵活性:代码不需要改动,可以修改配置文件,配置文件修改之后,可以创建出不同的实例对象
forName();——只让静态代码块执行
public static void main(String[] args) {
try {
Class.forName("com.busying.Myclass");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
class Myclass{
//静态代码块在类加载时执行,并且只执行一次
static {
System.out.println("MyClass的静态代码块执行了");
}
}
运行结果:
文件路径
String path = Thread.currentThread().getContextClassLoader().getResource("写相对路径,但是这个相对路径从src出发开始找").getPath();
例:
String path = Thread.currentThread().getContextClassLoader().getResource("com/jintianxuejavalema/xuele").getPath();
//必须保证src下有com目录,com目录下有jintianxuejavalema目录,jintianxuejavalema目录下有xuele文件
这种方式是为了获取一个文件的绝对路径(通用方式,不会受环境移植性影响)
但是该文件要求放在类路径下(即:放在src下面,src下的类是根路径)
//直接以流的方式返回
InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("com/jintianxuejavalema/xuele");
快速绑定属性资源文件——IO + Properties
要求:
- 这个文件必须在类路径下(src下)
- 这个文件必须是以Properties结尾
//com.jintianxuejavalema/xuele.properties
ResourceBundle bundle = ResourceBundle.getBundle("com.jintianxuejavalema/xuele");
String Value = bundle.getString(key);
实操(例子)
编写一个student类,通过反射机制获取其实例对象并将实例对象中的所有数据输出到student.txt文件中,
源码中创建student类对象的时不允许通过new关键字创建对象。
public static void main(String[] args){
try {
FileOutputStream writer = new FileOutputStream("D:\\IDEA\\untitled02\\src\\student.txt");
//获取Class
Class c = Class.forName("com.busying.student");
//构造一个对象
//student student01 =(student) c.newInstance();
//通过构造器创建对象
Constructor constructor = c.getDeclaredConstructor(String.class,int.class,double.class);
student student01 =(student) constructor.newInstance("小李",18,99);
String text = student01.toString();
byte[] bytes = text.getBytes();
writer.write(bytes);
writer.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
class student{
private String name;
private int age;
private double score;
public student() {
}
public student(String name,int age, double score) {
this.name = name;
this.age = age;
this.score = score;
}
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;
}
public double getScore() {
return score;
}
public void setScore(double score) {
this.score = score;
}
@Override
public String toString() {
return "name=" + name+ ", age=" + age + ", score=" + score;
}
}
运行结果: