获取类对象
三种方式
- Class.forName
- Hero.class
- new Hero().getClass()
获取类对象的时候,会导致类属性被初始化(类加载),但是Hero.Class这种方式不会初始化!
package reflect;
/*
* 获取对象的三种方式
* Class.forname(类对象)
* 类.class
* 类对象.getclass()
*/
public class TestreflectA {
public static void main(String[] args) {
Hero hero=new Hero();
Class c1=Hero.class;
Class c2=hero.getClass();
try {
Class c3=Class.forName("reflect.Hero");
System.out.println(c3==c1);
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Hero{
String name;
public Hero() {
}
public Hero(String name) {
this.name=name;
}
}
创建对象
创建方式为:
先获取类c,然后c.newInstance()方法创建一个实例!
.newInstance()调用的是一个无参数的构造器,如果类只有一个有参构造器,将会报错。要么没有构造器,要么就必须的iyou无参构造器!
package reflect;
/*
* 获取对象的三种方式
* Class.forname(类对象)
* 类.class
* 类对象.getclass()
*/
public class TestreflectA {
public static void main(String[] args) {
Hero hero=new Hero("name");
Class c1=Hero.class;
Class c2=hero.getClass();
try {
Class c3=Class.forName("reflect.Hero");
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
try {
Object o1=c2.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Hero{
String name;
public Hero() {
System.out.println("创建了一个实例");
}
public Hero(String name) {
this.name=name;
}
}
访问属性
通过反射机制修改对象的属性
语法:
Field f=类实例.getDeclaredField(属性)
f.set(类对象,修改的值)
package reflect;
import java.lang.reflect.Field;
/*
* 获取对象的三种方式
* Class.forname(类对象)
* 类.class
* 类对象.getclass()
*/
public class TestreflectA {
public static void main(String[] args) {
Hero hero=new Hero("gareen");
System.out.println(hero);
Class c1=hero.getClass();
try {
Field f1 = c1.getDeclaredField("name");
f1.set(hero, "teemo");
} catch (Exception e) {
}
System.out.println(hero);
}
}
class Hero{
public String name;
public float hp;
public int damage;
public int id;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Hero() {
}
public Hero(String string) {
name = string;
}
@Override
public String toString() {
return "Hero [name=" + name + "]";
}
public boolean isDead() {
// TODO Auto-generated method stub
return false;
}
public void attackHero(Hero h2) {
System.out.println(this.name + " 正在攻击 " + h2.getName());
}
}
getField和getDeclaredField的区别
getField和getDeclaredField这两个方法都是用于获取字段;
getField只能获取public的,包括从父类继承的。
getDeclaredField可以获取本类所有的字段,包括private,但是不能获取继承来的字段( 这里只能获取到private的字段,但并不能访问该private字段的值,除非加上setAccessible(true))
//name是private的
public class TestreflectA {
public static void main(String[] args) {
Hero hero=new Hero("gareen");
System.out.println(hero);
Class c1=hero.getClass();
try {
Field f1 = c1.getDeclaredField("name");
// f1.setAccessible(true);没有这一行就会导致出现异常,set函数不执行因为异常处理机制
f1.set(hero, "teemo");//无法访问和获取
} catch (Exception e) {
}
System.out.println(hero);
}
}
调用方法
Hero里面有一个setName(String s)函数!
Method m=类实例.getClass().getMethod("实例方法名字",参数类型)
m.invoke(类实例,参数)
public class TestreflectA {
public static void main(String[] args) {
Hero hero=new Hero();
System.out.println(hero);
Class c1=hero.getClass();
try {
Method m1 = c1.getMethod("setName",String.class);
m1.invoke(hero, "gareen");
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(hero);
}
}
用途
举一个使用反射方式的例子!
通过springtest.txt文本档实现调用函数的功能!
//springtest.txt文本的内容
class=reflect.Service1
method=doservice1
首先写两个类:
public class Service1 {
public void doservice1() {
System.out.println("1");
}
}
public class Service2 {
public void doservice2() {
System.out.println("2");
}
}
package reflect;
import java.io.File;
import java.io.FileInputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
public class TestreflectB {
public static void main(String[] args) {
// TODO Auto-generated method stub
File file=new File("F:/Wangchuang/springreflect.txt");
Properties p=new Properties();//key-value Hashmap!
try {
p.load(new FileInputStream(file));//加载字节流
String classname=(String) p.get("class");//获取类名
String methodname=(String) p.get("method");//获取类方法
Class c=Class.forName(classname);
Method m=c.getMethod(methodname);
Constructor con=c.getConstructor(String.class);//获取构造对象
Object o1=con.newInstance("d");//根据构造器获取实例对象
// Object obj=c.newInstance(); //参考newInstance的使用方法
m.invoke(o1);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
如果想执行另一个类的方法,直接在文本里面修改就行了!
1.先把文件以字节流的形式加载到Properties实例对象中去
2.通过Properties实例对象的方法分别得到类名和方法名字段
3.通过类名构造类对象,由类对象构造实例方法,并将实例方法放到Method中运行
Properties解析
获取文件的绝对路径(可移植),通用!!!!!
文件是放在src文件下面的!
String path2=Thread.currentThread().getContextClassLoader().getResource("com/biji/javja/dab.properties").getPath();
getContextClassLoader()
是线程对象的方法,可以获取到当前线程的类加载器对象
getResource
【获取资源】这是类加载器对象的方法,当前线程的类加载器默认从类的根路径下加载资源。
改进版
直接以流的方式返回
InputStream reader =Thread.currentThread().getContextClassLoader().getResourceAsStream("src下面的文件相对路径")
资源绑定器
java.util包下面有一个资源绑定器,便于获取属性配制文件中的内容,前提条件配置文件xxx.properties必须放到类路径下,文件的属性必须为properties!
ResourceBundle bundle=ResourceBundle.get("classinfo2");
String classname=bundle.getString("className");
类加载器
1、准备负责加载类的命令/工具ClassLoader(类加载器)
2、执行代码比如:String s=“1”;
代码开始前会将所需要类全部加载到JVM当中,通过类加载器加载,看到以上代码类加载器找到String.class文件,找到就加载!
执行步骤
①首先通过“启动类加载器”加载(父)
启动类加载器专门加载:rt.jar,其全部都是JDK的核心类库
②如果启动类加载器加载不到的时候会通过“扩展类加载器”加载(母)
扩展类加载器专门加载ext文件下的类
③如果所有扩展类加载器没有加载到,那么会通过“应用类加载器”加载
应用类加载器专门加载:classpath中类(系统设置的环境变量)
3、 双亲委派机制:保证类加载的安全
优先从启动类加载器中加载,这个称为父,如果父无法加载到,再从扩展类加载器中加载,这个称为母。如果都加载不到才会考虑从应用类加载器中记载。知道加载到为止!
可变长参数
形如:m(类型名…args)
其中args相当于一个数组 ,具有数组属性,参数可以是数组形式,取出的时候能够是一个数组。
可变长参数只能有一个,并且只能放在参数列表的最后一个位置!