[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) 编辑 收藏 举报