• java反射


    一、Class类的使用

    在面向对象的世界里,万事万物皆对象。所以一个具体的类(比如我们创建的User类)也是一个对象,那么类是谁的对象呢?类是java.lang.Class的对象,通过源码我们发现Class是私有的,不能通过new创建。但是可以通过以下三种方法实现。

    我们首先创建一个User类,然后实现创建此类类型的方法:

    package com.ht;
    
    public class User {
        public void print(){
            System.out.println("hello world!");
        }
    }
    View Code
    import com.ht.User;
    
    public class Main {
    
        public static void main(String[] args) {
            User user=new User();
            user.print();
    
            //第一种获取类的方法(通过类的一个实例创建)
            Class u1=user.getClass();
    
            //第二种获取类的方法(通过类的隐藏的静态class属性创建)
            Class u2=User.class;
    
            //第三种获取类的方法 (这里有一个异常的抛出,通过Ctrl+Alt+t,快捷键直接打出代码)
            Class u3=null;
            try {
                u3=Class.forName("com.ht.User");//必须是类的完整路径名
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
    
            //以上u1,u2,u3表示User这个类的类类型
            //通过比较我们知道这三个值是相等的,而且通过类类型也可以实例化出其具体的对象
            System.out.println(u1==u2); //true
            System.out.println(u2==u3); //true
    
            try {
                User xiaoming=(User)u2.newInstance(); //需要有无参的构造函数
                xiaoming.print();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }
    }
    View Code

    二、 动态加载类

    通过Class.forName(“类的全名”)这种情况,我们就可以对类进行动态加载。

    设计出一个公共的接口类,然后让我们需要的类实现这个接口,每次编译我们实现的类,然后运行主程序就可。

    //ioffice作为接口,定义了start()方法,凡是实现了这个方法的类,我们都认为是office程序。

    package com.ht;
    
    public interface Ioffice {
        public void start();
    }
    View Code

    //Word的实现

    package com.ht;
    
    public class Word implements Ioffice{
        public void start() {
            System.out.println("word...start...");
        }
    }
    View Code

    //主程序

    import com.ht.Ioffice;
    
    public class Main {
    
        public static void main(String[] args) {
            try {
                Class c=Class.forName(args[0]);
                Ioffice ioffice=(Ioffice)c.newInstance();
                ioffice.start();
            } catch (Exception e){
            }
    
        }
    }
    View Code

    经过编译后,输入具体的类名,就可以动态的加载了。

     三、获取类的方法信息

    我们通过一个对象,就能够拿到此对象的类类型,然后通过类类型获取此类的内部方法

    //我们实现一个方法,传递一个对象,获取信息

    class ClassUnit{
        public static void getDetails(Object obj){
            System.out.println(obj.getClass()); //打印出传递进来对象的类类型
    
            Class c=obj.getClass(); //通过获取相应的类类型,来获取类名,方法名,参数名等等
            System.out.println(c.getName());
            Method[] methods=c.getDeclaredMethods();//c.getMethods(); //获取所有的方法的集合
            //以下通过循环拿到每个方法的名称
            for (int i=0;i<methods.length;i++){
                Class returnType= methods[i].getReturnType(); //得到一个方法的返回类型
                System.out.print("方法为:"+returnType.getName()+" "); //得到一个方法返回值类型的名称
                System.out.print(methods[i].getName()+" (");//得到一个方法名
                Class[] pataTypes=methods[i].getParameterTypes();//获取参数的类类型
                for (Class patatype:pataTypes) {
                    System.out.print(patatype.getName()+","); //每个方法的类型名
                }
                System.out.println(")");
            }
        }
    }
    View Code

    //此处传递的对象,既可以是系统基础类型,也可以是我们自己创建的类对象

    public class Main {
        public static void main(String[] args) {
            int a=9;
            ClassUnit.getDetails(a);
    
            System.out.println("-------------");
    
            Word word=new Word();
            ClassUnit.getDetails(word);
        }
    }
    View Code

    //获取到的结果如下

    同样我们也可以获取成员变量信息和构造函数的信息

    四、方法的反射

    我们通过Method.invoke(Object obj对象, Object... args参数列表)方法,可以进行方法反射的操作

    比如我们有以下类,类中有不同的方法实现:

    class ClassUnit{
        public void print(){
            System.out.println("hello");
        }
    
        public int print(int a,int b){
            return a+b;
        }
    
        public void printf(String a,String b){
            System.out.println(a+b);
        }
    }
    View Code
     public static void main(String[] args) {
            ClassUnit c=new ClassUnit();//假设我们已经有了这么个对象
    
            Class aClass= c.getClass(); //首先通过对象,获取其类类型
    
            try {
                Method m=aClass.getMethod("print",new Class[]{int.class,int.class});//此方法需要有try操作,万一没有这个方法或者参数不对的情况呢
                Method m2=aClass.getMethod("print");
                Method m3=aClass.getMethod("printf",new Class[]{String.class,String.class});
                try {
                    Object o= m.invoke(c,new Object[]{10,20});
                    Object o2=m2.invoke(c);
                    Object o3=m3.invoke(c,new Object[]{"hello","world"});
    
                    System.out.println(o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    View Code

    五、通过反射了解集合泛型的本质

    java中集合的泛型是防止错误的输入,只在编译阶段有效。验证:我们通过方法的反射,绕过编译,就可以将不同的类型数据插入到集合中。

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    import java.util.ArrayList;
    
    public class Main {
        public static void main(String[] args) {
            ArrayList arrayList1=new ArrayList();
            ArrayList<String> arrayList2=new ArrayList<String>();
            arrayList2.add("hekko");
            //arrayList2.add(200);//错误
    
            Class c1=arrayList1.getClass();
            Class c2=arrayList2.getClass();
            System.out.println(c1==c2);  //true
    
            try {
                Method m2= c2.getMethod("add", Object.class);
                try {
                    m2.invoke(arrayList2,200); //这样就能将200加进String的集合中
                    System.out.println(arrayList2.size());
                    System.out.println(arrayList2);
                        
    
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
        }
    }
    View Code

    以上代码得到的结果如下:

  • 相关阅读:
    【java】浅谈java内部类
    【java】java反射初探 ——“当类也学会照镜子”
    【java】关于java类和对象,你想知道的在这里!
    【javascript】谈谈HTML5: Web-Worker、canvas、indexedDB、拖拽事件
    【Vue】Vue中的父子组件通讯以及使用sync同步父子组件数据
    【javascript】详解变量,值,类型和宿主对象
    【javascript】异步编年史,从“纯回调”到Promise
    [转] golang 字符串比较是否相等
    because its MIME type ('text/html') is not a supported stylesheet MIME type, and strict MIME checkin
    desktoplayer.exe病毒及d:w7rtmasewcpsilmerged tu tsystem.cpp的解决方案
  • 原文地址:https://www.cnblogs.com/hometown/p/9747858.html
Copyright © 2020-2023  润新知