Java反射初步理解


文章参考bilibili:动力节点老杜

什么是反射

反射可以操作已经编译的java文件(即class文件),它赋予了我们在运行时分析类以及执行类中方法的能力。通过反射你可以获取任意一个类的所有属性和方法,你还可以调用这些方法和属性。
优点:使代码更灵活,比如可以在运行时分析类以及执行类中方法
缺点:使程序不安全,比如无视编译阶段的泛型参数检测 ,且性能更低

初步了解反射

与反射相关的类

java.lang.Class:代表整个字节码,代表一个类型
java.lang.reflect.Method:代表字节码中的字节方法码
java.lang.reflect.Constructor:代表字节码中的构造方法码
java.lang.reflect.Field:代表字节码中的属性字节码

获取Class的方法

  • Class类的静态方法forName(String className)
    在这里插入图片描述
    参数是一个字符串且必须是带有包名的完整类名

    	Class c1=Class.forName("java.lang.String")
    
  • Object类的方法getClass()
    在这里插入图片描述
    Object(所有类的父类)的方法那么每个对象都可以使用getClass()方法

    		String str="sadsd";
            System.out.println(str.getClass());
    
  • 任何一种类型包括基本类型都有class属性

    class clazz=String.class
    System.out.println(clazz);
    

Field的使用

获取Field的方法

在这里插入图片描述
在这里插入图片描述

声明User类

public class User {
    public int age;
    public int sex;
    private String name;
    }
	Class clazz=Class.forName("com.example.User");
        //获取类的public修饰的Field
        Field[] fields = clazz.getFields();
        System.out.println(fields.length);
        //取出某个属性
        Field field_0=fields[0];
        System.out.println(field_0.getName());

2
age

Class clazz=Class.forName("com.example.User");
        //获取类声明的Field
        Field[] fields = clazz.getDeclaredFields();
        System.out.println(fields.length);
        //取出某个属性
        Field field_0=fields[0];
        System.out.println(field_0.getName());

3
age

Filed的更多方法

Class clazz=Class.forName("com.example.User");
        //获取类声明的Field
        Field[] fields = clazz.getDeclaredFields();
        System.out.println(fields.length);
        System.out.println("====================");
        for(Field field:fields){
            //返回的修饰符是一个数字,每个数字都是修饰符的代号
            System.out.println(field.getModifiers());
            //将修饰符数字转换为字符串
            System.out.println(Modifier.toString(field.getModifiers()));
            //获取属性的类型
            System.out.println(field.getType());
            System.out.println(field.getName());
            System.out.println("----------------");
        }
3
====================
1
public
int
sex
----------------
25
public static final
int
age
----------------
2
private
class java.lang.String
name
----------------

Method

Method方法

public class User {

    public int sex;
    public static final int age=1;
    private String name;

    public boolean login(String username,String password){
        if("asd".equals(username)&&"123".equals(password)){
            return true;
        }
        return false;
    }

    private void logout(){
        System.out.println("退出成功");
    }
    ....
	Class clazz = Class.forName("com.example.User");

        Method[] methods = clazz.getDeclaredMethods();
        for(Method method:methods){
            System.out.println(method.getReturnType());//获取返回值类型

            Class[] parameterTypes = method.getParameterTypes();//获取参数列表
            for(Class parameterType:parameterTypes){
                System.out.println(parameterType);
            }

            System.out.println(method.getName());//获取方法名
            System.out.println("================");
        }
void
class java.lang.String
setName
================
boolean
class java.lang.String
class java.lang.String
login
================
int
getSex
================
int
getAge
================
void
logout
...

Constructor

Constructor[] constructors = clazz.getConstructors();
        for(Constructor constructor:constructors){
            System.out.println(constructor.getName());
            
            ...
        }

反射机制能干什么

Class使用事例

  • 使用Class创建对象

    Class clazz=Class.forName("com.example.User");
    Object obj=clazz.newInstance();
    System.out.println(obj);
    

    结果是

    com.example.User@4ee285c6
    而如果className是一个接口的话

    	Class clazz=Class.forName("java.util.List");
        Object obj = clazz.newInstance();
        System.out.println(obj);
    

    结果报错

    java.lang.InstantiationException: java.util.List
    at java.lang.Class.newInstance(Class.java:427)
    at test.test(test.java:10)
    Caused by: java.lang.NoSuchMethodException: java.util.List.()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.newInstance(Class.java:412)

    所以很明显时调用了类的无参构造方法
    如果我们在User的无参构造方法中使用输出语句

    	public User(){
            System.out.println(1);
        }
    

    就会得到

    1
    com.example.User@4ee285c6

    这种方式创建对象与使用new创建对象相比更加灵活

    比如有一个properties文件,内容是

    className= com.example.User

    
            Reader reader=new FileReader("src/classInfo.properties");
    
            Properties properties=new Properties();
            properties.load(reader);
            reader.close();
            
            String className = properties.getProperty("className");
            Class clazz = Class.forName(className);
            System.out.println(clazz.newInstance());
    

    结果是

    com.example.User@4ee285c6

    当我们只修改properties的内容

    className= java.util.ArrayList

    不修改源代码就得到了

    []

    符合OCP开闭原则:对扩展开放 ,对修改关闭

  • 只执行类中的静态代码块

    有一个类Cat

    	class Cat{
    		static{
    			//静态代码块在类加载的时候执行
    			sout("喵");
    		}
    	}
    
    	Class.forName("com.example.Cat");
    

    输出:

    所以希望只执行类中的静态代码块可以使用Class.forName(类名)

    Field使用

    • 通过反射机制访问一个java对象的属性
    		Class clazz=Class.forName("com.example.User");
            Object obj = clazz.newInstance();
    
            //共有属性
            Field field = clazz.getDeclaredField("sex");
            field.set(obj,1);
            System.out.println(((User) obj).getSex());
    
            //访问私有属性
            field = clazz.getDeclaredField("name");
            field.setAccessible(true);//打破封装
            field.set(obj,"asd");
            System.out.println(((User) obj).getName());
    

通过反射调用方法

		Class clazz = Class.forName("com.example.User");

        //调用方法要素:对象,方法名,实参列表,返回值
        Method method=clazz.getMethod("login",String.class,String.class);
        Object obj = clazz.newInstance();

        Object res = method.invoke(obj,//调用方法的对象
                                "asd", "123"//实参列表
                                    );
        System.out.println(res);

通过反射创建对象

Class clazz = Class.forName("com.example.User");
        //无参构造
        Object obj = clazz.newInstance();

        //有参构造
        Constructor declaredConstructor = clazz.getDeclaredConstructor(int.class, double.class);
        Object o = declaredConstructor.newInstance(110, 12.0);

        System.out.println(o);
        System.out.println(obj);
User{sex=1, name='null'}
User{sex=0, name='null'}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值