[Java基础]反射

 

一、反射概述

反射简介

反射机制是在程序运行状态,对于任意一个类,都可以知道这个类的所有属性和方法,对于任意一个对象,都可以调用其方法和属性。

总而言之,反射是动态获取类信息和调用对象属性方法的一种机制。

 

什么时候使用反射?(反射大大提高了程序的扩展性)

对于一个已经完成的程序,会提供一个Properties配置文件,我们可以通过读取配置文件获得类名字段,通过反射的方式获得这个类并创建实例,

从而扩展功能。

 

JVM类的加载

 .java源文件 .class字节码文件 类加载器 字节码校验器 解释器

JVM把class字节码文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被JVM直接使用的java类型,这就是虚拟机的加载机制。

类的生命周期:loading  -- verification --- preparation -- resolution-- initialization --using - unloading

类的加载分为三个步骤:

A.加载 将.class文件读入内存

B.连接 验证:内部结构是否正确,并和其他类协调一致 准备:为静态成员分配内存  解析:将二进制符号引用替换为直接引用

C.初始化  类的初始化 对类的静态变量,静态代码块执行初始化操作

 

加载时机:创建类的示例,访问修改类的静态属性,调用类的静态方法,反射方式获取Class对象,初始化子类

 

反射的三种方式

 

A.Class clazz = Person.class

B.Class clazz  = new Person().getClass

C.Class clazz = Class.forName("com.fanfan.Person");

 

二、Class类,反射的基石

Class概述:

java类用于描述某一类事物,将其共性向上抽取并封装。而Class类则将java类的共性向上抽取,封装。即:Class类是java类的类。其对象对应字节码文件:Xxx.class

 

 

 

Class类的成员属性:

field(字段)

constructor(构造函数)

method(方法)

 

Class类的方法:

   static Class forName(String className)

        返回与给定字符串名的类或接口的相关联的Class对象。

        Class getClass()

        返回的是Object运行时的类,即返回Class对象即字节码对象

        Constructor getConstructor()

        返回Constructor对象,它反映此Class对象所表示的类的指定公共构造方法。

        Field getField(String name)

        返回一个Field对象,它表示此Class对象所代表的类或接口的指定公共成员字段。

        Field[] getFields()

        返回包含某些Field对象的数组,表示所代表类中的成员字段。

        Method getMethod(String name,Class… parameterTypes)

        返回一个Method对象,它表示的是此Class对象所代表的类的指定公共成员方法。

        Method[] getMehtods()

        返回一个包含某些Method对象的数组,是所代表的的类中的公共成员方法。

        String getName()

        以String形式返回此Class对象所表示的实体名称。

        String getSuperclass()

        返回此Class所表示的类的超类的名称

        boolean isArray()

        判定此Class对象是否表示一个数组

        boolean isPrimitive()

        判断指定的Class对象是否是一个基本类型。

        T newInstance()

        创建此Class对象所表示的类的一个新实例。

 

示例:通过反射获取对象。

package com.fan.testmain;

public class Test2 {

    public static void main(String[] args) throws Exception {
        
        String name = "com.fan.testmain.Test1";
        Class clazz = Class.forName(name);
        
        Test1 test1 = (Test1)clazz.newInstance();
    }

}

 

Constructor类

获取构造方法:

得到这个类的所有构造方法:如得到上面示例中Person类的所有构造方法

Constructor[] cons = Class.forName(“com.fan.Person”).getConstructors();

获取某一个构造方法:

Constructor con=Person.class.getConstructor(String.class,int.class);

创建实例对象:

通常方式:Person p = new Person(“mimi”,30);

反射方式:Person p= (Person)con.newInstance(“mimi”,30);

利用Constructor类来创建类实例的好处是可以指定构造函数,而Class类只能利用无参构造函数创建类实例对象。

 

public class Test2 {

    public static void createPersonClass_2() throws Exception{  
        //获取Person类的Class对象  
        String className="com.fanfan.Person";  
        Class clazz=Class.forName(className);  
        //获取指定构造函数的类实例  
        Constructor con=clazz.getConstructor(String.class,int.class);  
        Person p=(Person) con.newInstance("lisi",30);  
        System.out.println(p.toString());  
    }  

}

 

 

 

Field类

Field类代表某个类中一个成员变量

方法

Field getField(String s);//只能获取公有和父类中公有

Field getDeclaredField(String s);//获取该类中任意成员变量,包括私有

setAccessible(ture);//如果是私有字段,要先将该私有字段进行取消权限检查的能力。暴力访问

set(Object obj, Object value);//将指定对象变量上此Field对象表示的字段设置为指定的新值。

Object get(Object obj);//返回指定对象上Field表示的字段的值。

示例:

public class Test2 {
    
    public static void main(String[] args) throws Exception {
        
        Class clazz = Class.forName("com.fan.testmain.Person");//获取Person.class
        Constructor cons = clazz.getConstructor(String.class,int.class); //获取Person类的构造方法
        Person p1 = (Person)cons.newInstance("葫芦娃",18); //new Person();
        
        System.out.println(p1);
        
        Field f1 = clazz.getDeclaredField("name");  //new Field对象.描述Person类的String name字段
        f1.setAccessible(true);    //暴力访问
        f1.set(p1, "孙悟空");        //修改对象p1的name值
        
        Field f2 = clazz.getDeclaredField("age");
        f2.setAccessible(true);
        f2.set(p1, 1000);
        
        System.out.println(p1);
    }    
}

 

Method类 

Method

Class.getMethod(String, Class...) 和 Class.getDeclaredMethod(String, Class...)方法可以获取类中的指定方法,

调用invoke(Object, Object...)可以调用该方法,

Class.getMethod("eat")

invoke(obj) Class.getMethod("eat",int.class) invoke(obj,10)

 

示例:

 

class EdisonChen extends Person {

    public EdisonChen(String name, int age) {
        super(name, age);
        // TODO Auto-generated constructor stub
    }
    
    
    //子类speak方法
    public void speak(String line) {
        System.out.println("大家好我叫"+this.name+line);
    }
    
    
    //打印num*num乘法表
    public void printTable(int num) {
        
        for(int i = num; i > 0; i--) {
            for(int j = 1; j <= i; j++) {
                System.out.print(i+"*"+j+"  =  "+i*j+"\t");
                
            }
            System.out.println();
        }
        
    }
    
}

 

public class Test2 {
    
    public static void main(String[] args) throws Exception {
        //获取Class的对象(EdisonChen。class)并获取其构造方法(带参数);
        String personPath = "com.fan.testmain.EdisonChen";
        Class clazz = Class.forName(personPath);
        Constructor cons = clazz.getConstructor(String.class,int.class);
        
        //多态,创建对象
        Person p1 = (EdisonChen)cons.newInstance("陈冠希",10);
        
        
        //获取并执行speak()方法
        Method m1 = clazz.getMethod("speak", String.class);
        m1.invoke(p1, "你记得我吗");
        
        //获取并执行printTable()方法;
        Method m2 = clazz.getMethod("printTable",int.class);
        m2.invoke(p1, 9);
        
    }    
}

 

 

三、Template设计模式

 

A模版设计模式概述

模版方法模式就是定义一个算法的骨架,而将具体的算法延迟到子类中来实现

B:优点和缺点

a:优点使用模版方法模式,在定义算法骨架的同时,可以很灵活的实现具体的算法,满足用户灵活多变的需求

b:缺点

如果算法骨架有修改的话,则需要修改抽象类 

public class Test2 {
    
    public static void main(String[] args) throws Exception {
        
        
        GetII getii = new GetII();
        getii.run();
        
    }    
}

abstract class GetI {
    
    public void run () {   //算法骨架
        
        
        Long startTime = System.currentTimeMillis() ;
        
        code();   //  由子类具体实现
        
        Long EndTime = System.currentTimeMillis();
        
        System.out.println(EndTime - startTime);
        
        
        
    }
    
    public abstract void code();  //抽象方法
}


class GetII extends GetI {
    
    public void code() {
        
        
        for(int  i = 0 ; i<100;i++) {
    
            System.out.println(i);
        }
    }    
    
}

 

 

四、JDK新特性

JDK5.0

泛型

自动拆装箱

互斥锁

可变参数

静态导入

增强for循环

枚举

 

public enum Colour {

    RED("红色"),WHITE("白色"),YELLOW("黄色"),GREEN("绿色");
    
    private String name;
    private Colour(String name) {
        this.name = name;
    }
    
    public String toString()  {
        return name;
    }
}

 

 

 

JDK7.0

二进制字面量 0b0010

数字字面量下划线  1000_000(1000,000)

switch语句可以用字符串

多个异常的catch合并,每个异常用或

try--with--resource语句

JDK8.0

接口中的方法可以拥有方法体,但是非静态方法一定要用default修饰

局部内部类访问类中成员时,不必加final修饰

posted on 2017-10-20 21:19  VinceStarry  阅读(126)  评论(0编辑  收藏  举报

导航