Java反射

2017-07-26  本文已影响0人  yzw12138

java通常是先有类再有对象,有对象我就可以调用方法或者属性。反射其实是通过Class对象来调用类里面的方法。通过反射可以调用私有方法和私有属性。大部分框架都是运用反射原理

一、Class类的使用

1.在面向对象的世界中,完事万物都是对象
2.java语言中静态成员和普通数据类型不是对象
3.类也是对象,是java.lang.Class的实例对象

class Foo{
    public void print()
    {
        System.out.println("it is Foo");
    }
}
public class ClassDemo1 {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub

        //Foo类的实例对象
        Foo foo1 = new Foo(); //foo1表示Foo类的实例对象

        /*
         * Foo这个类本身也是一个实例对象,就是Class(java.lang.Class)类的实例对象
         * /任何一个类都是Class类的实例对象, 该实例对象有三种表示方法
         */
        //第一种 --> 任何一个类都有一个隐含的静态成员变量class
        Class c1 = Foo.class; //c1表示Class类的实例对象

        //第二种,已知该类的对象, 通过该类对象的getClass方法表示
        Class c2 = foo1.getClass(); //c2表示Class类的实例对象

        /*
         * 以上c1,c2都表示Class类的实例对象,但是这个实例对象又是说Foo这个类
         * c1,c2表示Foo类的类类型 ( class type ), 因为Foo类可以理解为Class类的实例对象
         * 也就是世界万物皆对象,类也是对象,是Class类的实例对象
         * 这个对象我们称为该类的类类型
         */

        //不管c1 or c2都代表了Foo类的类类型,一个类只可能是Class类的一个实例对象, 所以c1=c2
        System.out.println(c1==c2);//输出: true

        //第三种
        Class c3 = null;
        try {
            c3 = Class.forName("com.lxf.reflect.Foo");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(c3==c2); //输出:true

        //我们可以通过类的类类型创建该类的实例--->通过c1 or c2 or c3创建Foo的实例
        try {
            Foo foo2 = (Foo)c2.newInstance(); //需要有无参数的构造方法
            foo2.print();
        } catch (InstantiationException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

}

二.静态加载

class Test{
  public static void main(String[] args) {
      People p = new People();
      p.eat();
  }
}

编译Test.java

javac Test.java
这时候People.class字节码文件并没有,所以在编译的时候会报错

创建People.java

class People
{
  public void eat()
  {
        System.out.println("我喜欢美食");
  }
}

此时在编译

先编译People.java
javac People.java //编译后会产生People.class字节码文件
javac Test.java     //编译后会产生Test.class字节码文件

执行Test

java Test  //会输出:我喜欢美食

三、动态加载

通过Class a=Class.forName(arg[0]);此时为动态加载,因为编译时不知道使用哪个类,因此编译没有加载任何类,通过编译。运行时,根据 Javac office.java word (word为arg[0],也是类类型),去确定a是哪个类。这就是动态加载。
实际问题举例:

class offic
{
   public static void main(String[] args)
   {
     if("Word".equals(args[0]))
     {
       Word w=new Word();
       w.start();
     }
     if("Excel".equals(args[0])
     {
       Excel e=new Excel();
       e.start();
     }
   }    
}

编译无法通过,Word类、Excel类和start()方法不存在。

class Word 
{
    public static void start(){
        System.out.println("Word.....start");
    }
}

创建Word类后,进行编译,仍会报错,Excel类不存在。如果我们只想用已经存在的Word类,此类方法也是无法实现的。因为new创建的对象是静态加载类,在编译时刻需要加载所有可能使用的类,不管你是否会用到。

class OfficeBetter 
{
    public static void main(String[] args) 
    {
        
        try
        {
            //动态加载类
            Class c=Class.forName(args[0]);
            //通过类类型创建该类对象
            OfficeAble oa=(OfficeAble)c.newInstance();
            oa.start();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

通过动态加载,编译过程中不会报错。编写借口OfficeAble直接创建对象,Word类和Excel类通过继承方式,实现不同方法。

interface OfficeAble
{
    public void start();
}
class Word implements OfficeAble
{
    public void start(){
        System.out.println("Word.....start");
    }
}

四、获取信息

/**
     * 打印类的信息,包括类的成员函数、成员变量(只获取成员函数)
     * @param obj 该对象所属类的信息
     */
public static void printClassMethodMessage(Object obj){
        //要获取类的信息  首先要获取类的类类型
        Class c = obj.getClass();//传递的是哪个子类的对象  c就是该子类的类类型
        //获取类的名称
        System.out.println("类的名称是:"+c.getName());
        /*
         * Method类,方法对象
         * 一个成员方法就是一个Method对象
         * getMethods()方法获取的是所有的public的函数,包括父类继承而来的
         * getDeclaredMethods()获取的是所有该类自己声明的方法,不问访问权限
         */
        Method[] ms = c.getMethods();//c.getDeclaredMethods()
        for(int i = 0; i < ms.length;i++){
            //得到方法的返回值类型的类类型
            Class returnType = ms[i].getReturnType();
            System.out.print(returnType.getName()+" ");
            //得到方法的名称
            System.out.print(ms[i].getName()+"(");
            //获取参数类型--->得到的是参数列表的类型的类类型
            Class[] paramTypes = ms[i].getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName()+",");
            }
            System.out.println(")");
        }
    }
  /**
     * 获取成员变量的信息
     * @param obj
     */
    public static void printFieldMessage(Object obj) {
        Class c = obj.getClass();
        /*
         * 成员变量也是对象
         * java.lang.reflect.Field
         * Field类封装了关于成员变量的操作
         * getFields()方法获取的是所有的public的成员变量的信息
         * getDeclaredFields获取的是该类自己声明的成员变量的信息
         */
        //Field[] fs = c.getFields();
        Field[] fs = c.getDeclaredFields();
        for (Field field : fs) {
            //得到成员变量的类型的类类型
            Class fieldType = field.getType();
            String typeName = fieldType.getName();
            //得到成员变量的名称
            String fieldName = field.getName();
            System.out.println(typeName+" "+fieldName);
        }
    }
/**
     * 打印对象的构造函数的信息
     * @param obj
     */
    public static void printConMessage(Object obj){
        Class c = obj.getClass();
        /*
         * 构造函数也是对象
         * java.lang. Constructor中封装了构造函数的信息
         * getConstructors获取所有的public的构造函数
         * getDeclaredConstructors得到所有的构造函数
         */
        //Constructor[] cs = c.getConstructors();
        Constructor[] cs = c.getDeclaredConstructors();
        for (Constructor constructor : cs) {
            System.out.print(constructor.getName()+"(");
            //获取构造函数的参数列表--->得到的是参数列表的类类型
            Class[] paramTypes = constructor.getParameterTypes();
            for (Class class1 : paramTypes) {
                System.out.print(class1.getName()+",");
            }
            System.out.println(")");
        }
    }

JAVA中extends 与implements有啥区别?

  1. 在类的声明中,通过关键字extends来创建一个类的子类。一个类通过关键字implements声明自己使用一个或者多个接口。
    extends 是继承某个类, 继承之后可以使用父类的方法, 也可以重写父类的方法; implements 是实现多个接口, 接口的方法一般为空的, 必须重写才能使用
    2.extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,JAVA中不支持多重继承,但是可以用接口 来实现,这样就要用到implements,继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了

五、方法的反射

1、获得类类型 A a1 = new A(); Class c= a1.getclass;
2、获得方法对象 Method getMet=c.getMethod("print",String.class,String.class);//忘了加引号 其中可以用new Class[]{}数组作为参数
3、反射,m.invoke(调用方法的对象,参数); 参数可以 new Object[]{}
4、反射结果和直接对象调用结果一样,本例都是 打印输出

六、Java反射机制

——通过反射了解集合泛型的本质
1:反射的操作都是编译之后的操作;就是运行阶段
2:java中集合的泛型是防止错误输入的;只在编译阶段有效,只要绕过编译就无效啦
1:注解是一个什么东西——一种技术,使用特定语法,能过比较简单的实现一些比较牛逼的功能
2:注解的功能什么?也就是都有什么类型的注解?注解都能干什么?还是说什么都能干?
3:有些注解是人家提供的,如果想自己编写注解,该怎么玩?然后就是什么情况下自己编写注解比较好?怎么才能又快又好的编写自己的注解?
4:想了解一下,框架中注解是怎么使用的比如:Spring框架

七、Java自带的常用注解:

常见第三方注解

Spring:@Autowired @Service @Repository

public class UserManagerImpl implements UserManager {
   @Autowired 
   private UserDao userDao;
}
Paste_Image.png Paste_Image.png Paste_Image.png

如果注解只有一个成员,则成员名必须取名为value(),在使用时可以忽略成员名和赋值号(=),这是一个约定俗成的规则,不这样使用也可以编译通过。
解析注解:

Paste_Image.png Paste_Image.png
上一篇 下一篇

猜你喜欢

热点阅读