反射

反射

1.可变参数
2.反射

第一节:可变参数

从JDK 5开始,Java 允许为方法定义长度可变的参数。

语法:

public void foo(int … args){ //int...表示数组

}

注意事项:

  • 调用可变参数的方法时, 编译器将自动创建一个数组保存传递给方法的可变参数,因此,程序员可以在方法体中以数组的形式访问可变参数
  • 可变参数只能处于参数列表的最后, 所以一个方法最多只能有一个长度可变的参数

案例一:

public static void main(String[] args) {
        int[] nums={10,20,30};
        showNumber(nums);
        //----可变参数调用 好处:调用是可以传递数组元素
        //注意:1 可以必须放在方法参数列表的最后
         //   2 一个只能有一个可变参数
        showNumber(10,20);
        //showNames("zhangsan","lisi","wangwu");
    }
    public static void showNumber(int... nums){ // ...  []
        System.out.println(nums.length);
        for (int i : nums) {
            System.out.println(i);
        }
    }
    public static void showNames(String...names){
        for (String n : names) {
            System.out.println(n);
        }
    }

第二节:反射

2.1 为什么使用反射
需求:
    我公司定义了一组接口,然后第三方公司按照我公司的接口实现了一套功能,然后交给我们,但是我们公司的项目已经结束,如何实现动态加载第三方公司提供的功能。
2.2 什么是反射
反射就是把Java类中的各种成分映射成一个个的java对象。例如,一个类有:成员变量,方法,构造方法,包等等信息,利用反射技术可以对一个类进行解剖,把各个组成部分映射成一个个对象。

2.3 反射常用类
  • Class类—可获取类和类的成员信息
  • Field类—可访问类的属性
  • Method类—可调用类的方法
  • Constructor类—可调用类的构造方法
2.4 使用反射的基本步骤

​ 1.导入java.lang.reflect.*

​ 2.获得需要操作的类的Java.lang.Class对象

​ 3.调用Class的方法获取Field、Method等对象

​ 4.使用反射API进行操作(设置属性﹑调用方法)

第三节:Class类

3.1 Class类是反射机制的起源和入口
  • 每个类都有自己的Class对象
  • 用于获取与类相关的各种信息
  • 提供了获取类信息的相关方法
  • Class类继承自Object类
3.2 Class类存放类的结构信息
  • 类名
  • 父类﹑接口
  • 方法﹑构造方法﹑属性
  • 注释
3.3 获取 Class对象的方式

第一种方式

//方法1:对象.getClass()
Student stu=new Student();
Class clazz=stu.getClass();

第二种方式

//方法2:类.class
clazz= Student.class;
clazz=String.class;

第三种方式

//方法3:Class.forName()
clazz=Class.forName("java.lang.String");
clazz=Class.forName("java.util.Date");
3.4 获取类的其他结构信息
Class clazz = Class.forName("java.lang.Object");
Field fields[ ] = clazz.getDeclaredFields();//获取Field 对象 
Method methods[] = clazz.getDeclaredMethods();//获取Method 对象 
Constructor constructors[ ] = clazz.getDeclaredConstructors();//获取Constructor对象 

3.5 动态创建对象

方法一:使用Class的newInstance()方法,仅适用于无参构造方法

Class clazz=Class.forName("com.qf.reflection.Student");
Object obj=clazz.newInstance(); 

方法二:调用Constructor的newInstance()方法,适用所有构造方法

Constructor cons = clazz.getConstructor(new Class[]{ String.class,  int.class, float.class });
Object obj = cons.newInstance(new Object[ ] {"lkl", 32, 56.5f });

练习一:

1 定义Student类,包含:姓名和年龄等属性,有参和无参构造方法,输出所有信息的方法

2 使用多种方法生成一个Student类的Class对象

3 使用Class类获取Student类的属性并输出

4 通过有参(无参)构造方法动态创建Student类的对象

3.6 动态执行方法

调用方法基本步骤:

1.通过Class对象获取Method 对象

2.调用Method对象的invoke()方法

例如:

Object invoke(Object obj,Object [] args);
//object 返回值
//obj 当前方法所属对象
//args 当前方法的参数列表
3.7 反射动态操作属性值

操作属性的基本步骤

1.通过Class对象获取Field 对象

2.调用Field 对象的方法进行取值或赋值操作

方法 说 明
Xxx getXxx(Object obj) 获取基本类型的属性值
Object get(Object obj) ) 得到引用类型属性值
void setXxx(Object obj,Xxx val) 将obj对象的该属性设置成val值
void set(Object obj,object val) 将obj对象的该属性设置成val值
void setAccessible(bool flag) 对获取到的属性设置访问权限

第四节:反射技术的优点和缺点

优点:

​ 1.提高了Java程序的灵活性和扩展性,降低了耦合性,提高自适应能力

​ 2.允许程序创建和控制任何类的对象,无需提前硬编码目标类

缺点:

​ 1.性能问题

​ 2.代码维护问题

第五节:综合案例


public class Demo2 {
    public static void main(String[] args) throws Exception{
//      getClassObj();
        //getConstructor();
        getMethod();
    }
    /**
     * 获取类对象
     */
    public static void getClassObj() throws Exception{
        //第一种方法:使用类名.class 获取类对象
        Class<?> class1= Person.class;
        System.out.println(class1.hashCode());
        //第二种方法:使用对象来获取类对象
        Person zhangsan=new Person();
        Class<?> class2=zhangsan.getClass();
        System.out.println(class2.hashCode());
        //第三种方式:使用Class.forname()获取类对象
        Class<?> class3=Class.forName("com.qf.day25_2.Person");
        System.out.println(class3.hashCode());
    }
    /**
     * 获取构造方法
     */
    public static void getConstructor() throws Exception{
        //1获取类对象
        Class<?> class1=Class.forName("com.qf.day25_2.Person");
        //2获取构造方法
//      Constructor<?>[] constructor=class1.getConstructors();
//      //3遍历
//      for (Constructor<?> c : constructor) {
//          System.out.println(c);
//      }
        //4获取一个无参构造方法
        Constructor<?> constructor=class1.getConstructor();
        System.out.println(constructor);
        //5获取带参构造方法
        Constructor<?> constructor2=class1.getConstructor(String.class,int.class,String.class);
        System.out.println(constructor2);
        
        //6使用构造方法构造对象
        Object zhangsan=constructor.newInstance();
        Object lisi=constructor2.newInstance("李四",20,"女");
        Object wangwu=class1.newInstance();//调用无参构造
        //Person wangwu=new Person("王五",20, "男");
        System.out.println(zhangsan.toString());
        System.out.println(lisi.toString());
        System.out.println(wangwu);
        //System.out.println(wangwu);
    }
    /**
     * 获取方法
     */
    public static void getMethod() throws Exception{
        //1获取类对象
        Class<?> class1=Class.forName("com.qf.day25_2.Person");
        //2获取方法 (获取所有的公开的方法,包括从父类继承过来的)
        //Method[] methods=class1.getMethods();
        //获取类中所有的方法,包括私有的,不包括继承的方法
//      Method[] methods=class1.getDeclaredMethods();
//      for (Method method : methods) {
//          System.out.println(method);
//      }
        
        Constructor<?> constructor=class1.getConstructor(String.class,int.class,String.class);
        Object zhangsan=constructor.newInstance("zhangsan",20,"男");
        
        //3获取一个无参方法
        Method method=class1.getDeclaredMethod("show");
        //4调用方法
        method.invoke(zhangsan);
        //5获取一个带参方法
        Method method2=class1.getDeclaredMethod("show", String.class);
        method2.invoke(zhangsan, "郑州");
        //6获取带返回值的方法
        Method method3=class1.getDeclaredMethod("getInfo");
        String s=(String) method3.invoke(zhangsan);
        System.out.println(s);
        //7获取静态方法
        Method method4=class1.getDeclaredMethod("showCountry");
        method4.invoke(null);
        //8获取私有方法
        Method method5=class1.getDeclaredMethod("privateMethod");
        //取消访问性检查
        method5.setAccessible(true);
        method5.invoke(zhangsan);
        //9获取属性
        Field field=class1.getDeclaredField("name");
        field.setAccessible(true);
        Object lisi=class1.newInstance();
        field.set(lisi, "李四");
        String name= (String) field.get(lisi);
        System.out.println(name);
        }
}

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,456评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,370评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,337评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,583评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,596评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,572评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,936评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,595评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,850评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,601评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,685评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,371评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,951评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,934评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,167评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,636评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,411评论 2 342