大家好,又见面了,我是你们的朋友全栈君。
文章目录
一、反射机制
反射机制在java.lang.reflect.*
包下
反射机制相关的重要的类有
java.lang.Class
:代表字节码文件,代表一个类型,代表整个类。java.lang.reflect.Method
:代表字节码中的方法字节码。代表类中的方法。java.lang.reflect.Constructor
:代表字节码中的构造方法字节码。代表类中的构造方法java.lang.reflect.Field
:代表字节码中的属性字节码。代表类中的成员变量(局部变量)
二、反射机制有什么用
通过java语言中的反射机制可以操作字节码文件。有点类似于黑客(可以读和修改字节码文件。)通过反射机制可以操作代码片段。(class文件)让程序更加灵活。
三、获取Class文件的三种方式
1、Class.forName()
public class ReflectTest01 {
public static void main(String[] args) {
/* Class.forName() 1、静态方法 2、方法的参数是一个字符串 3、字符串需要的是一个完整的类名 4、完整类名必须带有包名。java.lang包也不能省略*/
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.forName("完整类名");
这个方法的执行会导致类加载,类加载时,静态代码块执行。
2、getClass()方法
java中任何一个对象都有一个方法:getClass()
public class ReflectTest01 {
public static void main(String[] args) {
/* Class.forName() 1、静态方法 2、方法的参数是一个字符串 3、字符串需要的是一个完整的类名 4、完整类名必须带有包名。java.lang包也不能省略*/
Class c1 = null;
try {
c1 = Class.forName("java.lang.String");//c1代表的是String.class文件,或者说c1代表String类型
}catch (ClassNotFoundException e) {
e.printStackTrace();
}
String s = "abc";
Class x = s.getClass();//x代表String.class字节码文件,x代表String类型
System.out.println(c1 == x); //true(==判断的是对象的内存地址)
}
}
3、java类型的.class属性
java语言中任何一种类型,包括基本数据类型,它都有.class属性
Class z = String.class; //z代表String类型
Class k = Date.class;//k代表Date类型
四、通过反射实例化对象
获取.class能干什么?
通过Class的newInstance()
方法来实例化对象。
注意:newInstance()
方法内部实际上调用了无参数的构造方法,必须保证无参数构造存在才可以。
使用反射机制的方式来创建对象:
public class User {
public User() {
System.out.println("无参数的构造方法");
}
}
public class ReflectTest02 {
public static void main(String[] args) {
try {
//通过反射机制,获取Class,通过Class;来实例化对象
Class c = Class.forName("User");//c代表User类型
//newInstance() 这个方法会调用User这个类的无参数构造方法,完成对象的创建。
//重点是:newInstance()调用的是无参构造,必须保证无参构造是存在的!!!!
Object obj = c.newInstance();
System.out.println(obj);
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
五、通过读属性文件实例化对象
验证反射机制的灵活性。java代码只写一遍,在不改变java源代码的基础之上,可以做到不同对象的实例化。非常之灵活(符合OCP开闭原则:对扩展开放,对修改关闭)
classinfo.properties文件:
className = User
import java.io.FileReader;
import java.util.Properties;
public class ReflectTest03 {
public static void main(String[] args) throws Exception{
//通过IO流读取classinfo.properties文件
FileReader reader = new FileReader("classinfo.properties");
//创建属性类对象Map
Properties pro = new Properties();
//加载
pro.load(reader);
//关闭流
reader.close();
//通过key获取value
String calssName = pro.getProperty("className");
System.out.println(calssName);
//通过反射机制实例化对象
Class c = Class.forName(calssName);
Object obj = c.newInstance();
System.out.println(obj);
}
}
六、资源绑定器
java.util
包下提供了一个资源绑定器,便于获取配置文件中的内容。使用以下方法的时候,属性配置文件×××.properties
必须放到类路径下
import java.util.ResourceBundle;
public class ThreadTest04 {
public static void main(String[] args) {
//资源绑定器,只能绑定×××.properties文件。并且这个文件必须在src/类路径下。文件扩展名必须是properties
//并且在写路径的时候,路径的后面扩展名不能写
ResourceBundle bundle = ResourceBundle.getBundle("classinfo3");
String className = bundle.getString("className");
System.out.println(className);
}
}
七、类加载器
1、什么是加载器
专门负责加载类的命令/工具。ClassLoader
2、JDK中自带的类加载器
- 启动类加载器:
rt.jar
- 扩展类加载器:
ext/*.jar
- 应用类加载器:
classpath
假如执行以下代码:
String s = "abc";
代码在开始执行以前,会将所需要类全部加载到JVM当中。
通过类加载器加载,看到以上代码类加载器会找string. class
文件,找到就加载,那么是怎么进行加载的呢?
-
首先通过 “启动类加载器” 加载。
注意:启动类加载器专门加载:C: \Program Files\Java\jdk1.8.0_ 101\jre\lib\rt.jar
rt. jar中都是JDK最核心的类库。 -
如果通过 “启动类加载器”加载不到 的时候,会通过 “扩展类加载器” 加载。
注意:扩展类加载器专门加载:C: \Program Files\Java\jdk1.8.0_ 101\jre\lib\ext\*.jar
-
如果 “扩展类加载器” 没有加载到,那么会通过 “应用类加载器” 加载。
注意:应用类加载器专门加载:classpath
中的类。
3、双亲委派机制
java中为了保证类加载的安全,使用了双亲委派机制。优先从启动类加载器中加载,这个称为 “父”,”父”无法加载到,再从扩展类加载器中加载,这个称为**“母”。双亲委派。如果都加载不到,才会考虑从应用类加载器**中加载。直到加载到为止。
八、Field
1、获取Field
反射属性Field,Field翻译为字段,其实就是属性/成员。
4个Field,分别采用了不同的访问控制权限修饰符
public class Student {
//4个Field,分别采用了不同的访问控制权限修饰符
public int no;
private String name;
protected int age;
boolean sex;
}
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectTest05 {
public static void main(String[] args) throws Exception{
//获取整个类
Class studentClass = Class.forName("Student");
//获取类中所有的public修饰的Field
Field[] fields = studentClass.getFields();
System.out.println(fields.length);
//取出这个Field的名
Field f = fields[0];
String fieldName = f.getName();
System.out.println(fieldName);
//获取所有的Field
Field[] fields1 = studentClass.getDeclaredFields();
System.out.println(fields1.length);
for (Field field : fields1) {
//获取属性的修饰符
int i = field.getModifiers();//返回的修饰符是一个数字,每个数字都是修饰符的代号
System.out.println(i);
//将代号转化为字符串
String modifiersString = Modifier.toString(i);
System.out.println(modifiersString);
//获取属性的类型
Class fieldType = field.getType();
String fName = fieldType.getName();
System.out.println(fName);
//获取属性的名字
System.out.println(field.getName());
}
}
}
2、反编译Field
通过反射机制,反编译一个类的属性Field
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
public class ReflectTese06 {
public static void main(String[] args) throws Exception{
//创建这个是为为了拼接字符串。
StringBuilder s = new StringBuilder();
Class studentClass = Class.forName("Student");
s.append(Modifier.toString(studentClass.getModifiers())+ " class "+ studentClass.getSimpleName() + "Student{\n");
Field[] fields = studentClass.getDeclaredFields();
for (Field field : fields) {
s.append("\t");
s.append(Modifier.toString(field.getModifiers()));
s.append(" ");
s.append(field.getType().getSimpleName());
s.append(" ");
s.append(field.getName());
s.append(";\n");
}
s.append("}");
System.out.println(s);
}
}
运行结果:
3、通过反射机制访问java对象属性(重点掌握)
给属性赋值set
获取属性的值get
import java.lang.reflect.Field;
public class ReflectTest07 {
public static void main(String[] args) throws Exception {
//不使用反射机制怎样访问一个对象的属性
Student s = new Student();
//给属性赋值
s.no = 1111;
//读属性值
System.out.println(s.no);
//使用反射机制,访问一个对象的属性
Class studentClass = Class.forName("Student");
Object obj = studentClass.newInstance();//obj就是Student对象。(底层调用无参数构造方法)
//获取no属性(根据属性的名称来获取Field)
Field noField = studentClass.getDeclaredField("no");
//给obj对象(student对象)的no属性赋值
/*虽然使用了反射机制,但是三要素还是缺一不可: 要素1:obj对象。 要素2:no属性; 要素3:2222值。 注意:反射机制让代码复杂了,但是为了一个“灵活”,这也是值得的。 */
noField.set(obj,2222);//给obj对象的no属性赋值2222
//读取属性的值
//两个要素:获取obj对象的no属性的值。
System.out.println(noField.get(obj));
}
}
九、Method
1、可变长度参数
int... args
这就是可变长度参数
语法是:类型... (注意:一定是3个点)
- 1、可变长度参数要求的参数个数是:0~N个。
- 2、可变长度参数在参数列表中必须在最后一个位置上,而且可变长度参数只能有一个。
public class ArgsTest {
public static void main(String[] args) {
m();
m(10);
m(10,20);
}
public static void m(int... args){
System.out.println("m方法执行了!");
}
}
运行结果:
2、反射Method
public class User {
public int id;
private String name;
String address;
protected int sno;
public User() {
}
public User(int id, String name, String address, int sno) {
super();
this.id = id;
this.name = name;
this.address = address;
this.sno = sno;
}
public void study() {
System.out.println("study...");
}
public void eat(int a,String b) {
System.out.println("eat...");
}
}
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) throws Exception {
// 获取类
Class usrClass = Class.forName("com.lzj.reflect.pojo.User");
// 获取所有的Method(包括私有)
Method[] methods = usrClass.getDeclaredMethods();
// 遍历Method
for(Method method : methods){
// 获取修饰符列表
System.out.println(Modifier.toString(method.getModifiers()));
// 获取方法的返回值类型
System.out.println(method.getReturnType().getSimpleName());
// 获取方法名
System.out.println(method.getName());
// 方法的修饰符列表(一个方法的参数可能会有多个)
Class[] parameterTypes = method.getParameterTypes();
for(Class parameterType : parameterTypes){
System.out.println(parameterType.getSimpleName());
}
}
}
}
3、反编译Method
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
public class Test {
public static void main(String[] args) throws Exception {
StringBuilder s = new StringBuilder();
Class userClass = Class.forName("com.lzj.reflect.pojo.User");
s.append(Modifier.toString(userClass.getModifiers()) + " class "+userClass.getSimpleName()+" {\n");
Method[] methods = userClass.getDeclaredMethods();
for(Method method : methods){
s.append("\t");
s.append(Modifier.toString(method.getModifiers()));
s.append(" ");
s.append(method.getReturnType().getSimpleName());
s.append(" ");
s.append(method.getName());
s.append("(");
Class[] parameterTypes = method.getParameterTypes();
for(Class parameterType : parameterTypes){
s.append(parameterType.getSimpleName());
s.append(",");
}
if(parameterTypes.length > 0) {
s.deleteCharAt(s.length() - 1);
}
s.append("){}\n");
}
s.append("}");
System.out.println(s);
}
}
4、通过反射机制调用方法(重点掌握)
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) {
try {
Class<?> clazz = Class.forName("com.lgz.Test");
Method method = clazz.getMethod("run");
method.invoke(clazz.newInstance());
Method methodPrivate = clazz.getDeclaredMethod("eat");
methodPrivate.setAccessible(true);//调private方法
methodPrivate.invoke(clazz.newInstance());
Method methodStatic = clazz.getMethod("work");
methodStatic.invoke(null);
Method method1 = clazz.getMethod("speak", int.class, String.class);
method1.invoke(clazz.newInstance(), 22, "小明");
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InstantiationException | InvocationTargetException e) {
e.printStackTrace();
}
}
public static void work() {
System.out.println("work() 方法被调用...");
}
private void eat() {
System.out.println("eat() 方法被调用...");
}
public void run() {
System.out.println("run() 方法被调用...");
}
public void speak(int age, String name) {
System.out.println("speak() 方法被调用.... age = " + age + " name= " + name);
}
}
十、Constructor
1)得到某个类所有的构造方法
Constructor[] constructors = Class.forName("java.lang.String").getConstructors();
2)得到某一个构造方法
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
实例
Constructor constructor = String.class.getConstructor(StringBuffer.class);
String str = (String) constructor.newInstance(new StringBuffer("abc"));
System.out.println(str.charAt(2));
打印结果:c
十一、获取父类和父接口
public class ReflectTest08 {
public static void main(String[] args) throws Exception{
//String举例
Class stringClass = Class.forName("java.lang.String");
//获取String的父类
Class superClass = stringClass.getSuperclass();
System.out.println(superClass);
//获取String类实现的所有接口(一个类可以实现多个接口)
Class[] interfaces = stringClass.getInterfaces();
for (Class anInterface : interfaces) {
System.out.println(anInterface);
}
}
}
发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/157036.html原文链接:https://javaforall.cn
【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛
【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...