反射2

Class类:

  1. Class也是类,因此也继承Object类
  2. Class类对象不是new出来的,而是系统创建的
  3. 对于某个类的Class类对象,在内存中只有一份,因此类只加载一次
  4. 每个类的实例都会记得自己是由哪个Class实例所产生
  5. 通过Class可以完整地得到一个类的完整结构,通过一系列API
  6. Class对象是存放在堆的
  7. 类的字节码二进制数据,是放在方法区的,有的地方成为类的元数据

​ (包括 方法代码,类变量,方法名,访问权限等等)

常用方法:
  1. static Class forName(String name) 返回指定类名name的Class对象
  2. Object newInstance() 调用缺省构造函数,返回该Class对象的一个实例
  3. getName() 返回此Class对象所表示的实体(类、接口、数组类、基本类型等)名称
  4. Class[] getInterfaces() 获取当前Class对象的接口
  5. ClassLoader getClassLoader() 返回该类的类加载器
  6. Class getSupreclass() 返回表示此Class所表示的实体的超类的Class
  7. Constructor[] getConstryctors() 返回一个包含某些Constructor对象的数组
  8. Field[] getDeclaredFields() 返回Field对象的一个数组
  9. Method getMethod(String name,Class … paramTypes) 返回一个Method对象,此对象的形参类型为paramType
    class Car{//com.hspedu
        public String brand = "bmw";
        public int price = 500000;
        public String color = "白色";
    }
    
    public static void main(String[] args) {
        String classAllPath = "com.hspedu.Car";
        //1、获取到Car类 对应的 Class对象
        //<?>表示不确定的Java类型
        Class<?> cls = Class.forName(classAllPath);
        //2、输出cls
        System.out.print(cls);//显示cls对象,是哪个类的Class对象
        /*
            com.hspedu.Car
        */
        System.out.print(cls.getClass());//输出cls运行类型  java.lang.Class
        //3、得到报名
        System.out.print(cls.getPackage().getName());//包名
        //4、得到全类名
        System.out.print(cls.getName());
        //5、通过cls创建对象实例
        //Object o = cls.newInstance();
        Car car = (Car)cls.newInstance();
        System.out.print(car);//car.toString()
        /*
            Car{brand='bmw',price=500000,color='白色'}
        */
        //6、通过反射获取属性brand
        Field brand = cls.getField("brand");
        System.out.print(brand.get(car));//bmw
        //7、通过反射给属性赋值
        brand.set(car,"奔驰");
        System.out.print(brand.get(car));//奔驰
        //8、遍历得到所有的属性
        System.out.print("=======所有字段属性========");
        Field[] fields = cls.getFields();
        for (Field f : firlds) {
            System.out.print(f.getName());//名称
        }
    }
    
获取Class对象:
  1. 前提:一直一个类的全类名,且该类在类路径下,可通过Class类的静态方法forName()获取,可能抛出ClassNotFoundException,

    实例:Class cls1 = Class.forName(“java.lang.Cat”)

    应用场景:多用于配置文件,读取类全路径,加载类

    String classAllPath = "com.hspedu.Car";//通过读取配置文件获取
    Class<?> cls1 = Class.forName(classAllPath);
    
  2. 前提:若已知具体的类,通过类的class获取,该方式 最为安全可靠,程序性能最高,

    实例:Class cls2 = Cat.class;

    应用场景:多用于参数传递,比如通过反射得到对应构造器对象

    Class cls2 = Car.class;
    System.out.print(cls2);
    
  3. 前提:已知某个类的实例,调用该实例的getClass()方法获取Class对象,

    实例:Class clazz = 对象.getClass();//运行类型

    应用场景:通过创建好的对象,获取Class对象

    Car car = new Car();
    Class cls3 = car.getClass();
    System.out.print(cls3);
    
  4. 其他方式:通过类加载器(有4种)来获取到类的Class对象
      ClassLoader cl = 对象.getClass().getClassLoader();
      Class clazz4 = cl.loadClass("类的全类名")
    
    //1、先得到类加载器car
    ClassLoader classLoader = car.getClass().getClassLoader();
    //2、通过类加载器得到Class对象
    Class cls4 = classLoader.loadClass(classAllPath);
    

cls1、cls2、cls3、cls4 都是同一个对象

  1. 基本数据(int,char,boolean,float,double,byte,long,short)按如下方式得到Class类对象

Class cls = 基本数据类型.class

    Class<Integer> integerClass = int.class;
    Class<Character> characterClass = char.class;
    System.out.print(integerClass);//输出:int,自动装箱、拆箱
  1. 基本数据类型对应的包装类,可以通过.TYPE得到Class对象

Class cls = 包装类.TYPE

    Class<Interger> type1 = Integer.TYPE;
    Class<Character> type2 = Character.TYPE;
    System.out.print(type1);//输出int
哪些类型有Class对象:
  1. 外部类、成员内部类、静态内部类、局部内部类、匿名内部类
  2. intreface:接口
  3. 数组
  4. enum:枚举
  5. annotation:注解
  6. 基本数据类型
  7. void

类加载:

基本说明:

反射机制是Java实现动态语言的关键,也就是通过反射实现类动态加载

  1. 静态加载:编译时加载相关的类,如果没有则报错,依赖性太强
  2. 动态加载:运行时加载需要的类,如果运行时不用该类,即使不存在该类,也不报错,降低了依赖性
加载时机:
  1. 当创建对象时(new) //静态加载
  2. 当子类被加载时,父类也加载 //静态加载
  3. 调用类种的静态成员时 //静态加载
  4. 通过反射 //动态加载

通过反射获取类的结构信息:

第一组:java.lang.Class类
  1. getName:获取全类名
  2. getSimpleName:获取简单类名
  3. getFields:获取所有public修饰的属性,包含本类以及父类的
  4. getDeclaredFields:获取本类中所有属性
  5. geyMethods:获取所有public修饰的方法,包含本类以及父类的
  6. getDeclaredMethods:获取本类种所有方法
  7. getConstructors:获取本类所有public修饰的构造器
  8. getDeclaredConstructors:获取本类中所有构造器
  9. getPackage:以Package形式返回 包信息
  10. getSuperClass:以class形式返回父类信息
  11. getInterfaces:以Class[]形式返回接口信息
  12. getAnnotations:以Annotation[]形式返回注解信息
第二组:java.lang.reflect.Field类
  1. getModifiers:以int形式返回修饰符

    说明:默认修饰符是0,public 是1,private 是2,protected 是4,

    static 是8,final 是16 //如:public(1) + static(8) = 9

  2. getType:以Class形式返回类型

  3. getName:返回属性名

第三组:java.lang.reflect.Method类
  1. getModifiers:以int形式返回修饰符

    说明:默认修饰符是0,public 是1,private 是2,protected 是4,

    static 是8,final 是16

  2. getReturnType:以Class形式获取 返回类型

  3. getName:返回方法名

  4. getParameterType:以Class[]返回参数类型数组

通过反射创建对象:

  1. 方式一:调用类中的public修饰的无参构造器
  2. 方式二:调用类中的指定构造器
  3. Class类相关方法:
    1. newInstance:调用类中的无参构造器,获取对应类的对象
    2. getConstructor(Class … clazz):根据参数列表,获取对应的所有构造器对象
  4. Constructor类相关方法
    1. setAccessible:爆破
    2. newInstance(Object…obj):调用构造器
例:
  1. 测试1:通过反射创建某个类的对象,要求该类中必须要有public的无参构造
  2. 测试2:通过调用某个特定构造器的方式,实现创建某类的对象

    public static void main(String[] args) {
    //1、先获取到User类的Class对象
    Class userClass = Class.forName(“com.hspedu.reflection.User”);
    //2、通过public的无参构造器创建实例
    Object o = userClass.newInstance();
    System.out.print(o); //User [age=10,name=hsp]
    //3、通过public的有参构造器创建实例
    //3.1、先得到对应构造器
    Constructor constructor = userClass.getConstructor(String.class);
    /*
    constructor对象就是 public User(String name){……}
    /
    //3.2、创建实例,并传入实参
    Object hsp = constructor.newInstance(“hsp”);
    System.out.print(“hsp=” + hsp);
    /

    hsp=User [age=10,name=hsp]
    /
    //4、通过非public的有参构造器创建实例
    //4.1得到private的构造器对象
    Constructor<?> constructor1 = userClass.getConstructor(int.class,String.class);
    //4.2创建实例
    //爆破[暴力破解],使用反射可以访问private构造器/方法/属性
    constructor1.setAccessible(true);
    Object user2 = constructor1.newInstance(100,”张三丰”);
    System.out.print(“user2=” + user2);
    /

    user2=User [age=100,name=张三丰]
    */
    }

    class User{
    private int age = 10;
    private String name = “hsp”;
    public User(){}
    public User(String name){……}
    private User(int age,String name){……}
    public String toString(){……}
    }

通过反射访问类中的成员:

访问属性:ReflecAccessProperty.java
    1、根据属性名获取Field对象
      Field f = clazz对象.getDeclaredField(属性名);
    2、爆破:f.setAccessible(true); //f是Field
    3、访问
        f.set(o,值);
        syso(f.get(o));
    4、如果是静态属性,则set和get中的参数o,可以写成null
例:
public static void main(String[] args) {
    //1、得到Student类对应的Class对象
    Class<?> stuClass = Class.forName("com..hspedu.reflection.Student");
    //2、创建对象
    Object o = stuClass.newInstance();//o的运行类型就是Student
    System.out.print(o.getClass());//Student
    //3、使用反射得到age属性对象
    Field age = stuClass.getField("age");
    age.set(o,88)//通过反射来操作属性
    System.out.print(o);    //Student [age=88,name=null]
    System.out.print(age.get(o));//返回age属性的值    88

    //4、使用反射操作name属性
    Field name = stuClass.getDeclaredField("name");
    //对name进行爆破
    name.setAccessible(true);
    name.set(o,"hsp");
    //或name.set(null,"hsp")
    /*static属性是属于所有对象的,类加载的时候就有了*/
    System.out.print(o);
    /*Student [age=88,name=hsp]*/
    System.out.print(name.get(o));  //获取属性值
    //或 System.out.print(name.get(null));   //获取属性值,要求name是static
}

class Student{
    public int age;
    private static String name;
    public Student(){}
    public String toString(){……}
}
访问方法:
  1. 根据方法名和参数列表获取Method方法对象:

    Method m = clazz.getDeclaredMethod(方法名,XX.class);

  2. 获取对象:Object o = clazz.newInstance();

  3. 爆破:m.setAccessible(true);

  4. 访问:Object returnValue = m.invoke(o,实参列表); //o就是对象

  5. 注意:如果是静态方法,则invoke的参数o,可以写成null

    public static void main(String[] args) {
    //1、得到Boss类对应的Class对象
    Class<?> bossCls = Class.forName(“com.hspedu.reflection.Boss”);
    //2、创建对象
    Object o = bossCls.newInstance();
    //3、调用public 的hi方法
    //3.1、得到hi方法对象
    Method hi = bossCls.getMethod(“hi”,String.class);
    //或者
    //Method hi1 = bossCls.getDeclaredMethod(“hi”,String.class);
    hi.invoke(o,”hsoedu”);

    //4、调用private static对象
    //4.1得到say方法对象
    Method say = bossCls.getDeclaredMethod("say",int.class,String.class,char.class);
    //4.2爆破
    say.setAccessible(true);
    say.invoke(o,100,"张三","男");
    //4.3因为say方法是static的还可以这样调用
    say.invoke(null,200,"李四","女");
    
    //5、在反射中,如果方法有返回值,统一返回Object,但是他运行类型和方法定义的返回类型一致
    Object returnVal = say.invoke(null,300,"王五","男");
    System.out.print();
    

    }

    Class Boss{
    public int age;
    private static String name;

    public Boss(){}
    
    private static String say(int n,String s ,char c){//静态方法
        return n + " " + s + " " + c;
    }
    public void hi(String s){   //普通public方法
        System.out.print("hi" + s);
    }
    

    }

单例模式与反射:

单例模式最根本的在于类只能有一个实例,如果通过反射来构建这个类的实例,单例模式就会被破坏

class GirlFrie{
    private String name;
    //2、在类的内部直接创建对象
    //因为getInstance()是静态方法,静态方法只能访问静态属性
    private static GirlFriend gf = new GirlFriend("小红红");
    //1、将构造器私有化,防止直接new
    private GirlFriend(String name){
            this.name = name;
    //3、提供一个公共的static方法,返回gf对象
    private static GirlFriend getInstance(){
            return gf;
    }
}
public static void main(String[] args) {
    //1、得到GirlFrie类对应的Class对象
    Class<?> girlCls = Class.forName("com.GirlFrie");
    //2、创建对象
    Object o = girlCls.newInstance();
    //4、调用private static对象
    //4.1得到GirlFriend方法对象
    Method GirlFriend = girlCls.getDeclaredMethod("GirlFriend",int.class,String.class,char.class);
    //4.2爆破
    say.setAccessible(true);
    say.invoke(o,"张三");
}
创作不易!转载请注明作者及文章链接或作者博客链接——
- 作者:pidanxia
- 链接:https://pidanxia.ink
(链接可为:**文章链接**或者**作者博客链接**)
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇