类对象,就是用于描述这种类,都有什么属性,什么方法的
获取类对象获取类对象有3种方式
1. Class.forName(实例化对象)
2. 类.class
3. new 类().getClass()
在一个JVM中,一种类,只会有一个类对象存在。所以以上三种方式取出来的类对象,都是一样的。
package com.relect;
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
String className = "charactor.Test";
try {
Class p1=Class.forName(className);
Class p2=Test.class;
Class p3=new Test().getClass();
}catch(Exception e) {
e.printStackTrace();
}
}
}
静态属性被初始化
static String copyright;
static {
System.out.println("初始化 copyright");
copyright = "版权由Riot Games公司所有";
}
无论什么途径获取类对象,都会导致静态属性被初始化,而且只会执行一次。(除了直接使用 Class c = Hero.class 这种方式,这种方式不会导致静态属性被初始化)
通过反射机制创建一个对象//构造器
Constructor c= pClass.getConstructor();
//通过构造器实例化
Hero h2= (Hero) c.newInstance();
//使用传统方式修改name的值为garen
h.name = "garen"
//获取类Hero的名字叫做name的字段
Field f1= h.getClass().getDeclaredField("name");
//修改这个字段的值
f1.set(h, "teemo");
getField和getDeclaredField的区别
这两个方法都是用于获取字段
getField 只能获取public的,包括从父类继承来的字段。
getDeclaredField 可以获取本类所有的字段,包括private的,但是不能获取继承来的字段。
public class end {
public static void main(String[] args) {
File file = new File("C:/Users/Administrator/Desktop/hero.config");
try (FileReader fr = new FileReader(file)) {
String classname = null;
char[] all = new char[(int) file.length()];
fr.read(all);
String cs = null;
cs = new String(all);
String[] sc = cs.split("rn");
String classname1 = sc[0];
String classname2 = sc[1];
String name1 = sc[2];
String name2 = sc[3];
int HP1 = Integer.parseInt(sc[4]);
int HP2 = Integer.parseInt(sc[5]);
int damage1 = Integer.parseInt(sc[6]);
int damage2 = Integer.parseInt(sc[7]);
//
Class c = Class.forName(classname1);
Constructor con = c.getConstructor();
Object h = con.newInstance();
Field H = h.getClass().getField("HP");
H.set(h, HP1);
Field n = h.getClass().getField("name");
n.set(h, name1);
Field d = h.getClass().getField("damage");
d.set(h, damage1);
Class c1 = Class.forName(classname2);
Constructor con1 = c1.getConstructor();
Object h1 = con1.newInstance();
Field H1 = h1.getClass().getField("HP");
H1.set(h1, HP2);
Field n1 = h1.getClass().getField("name");
n1.set(h1, name2);
Field d1 = h1.getClass().getField("damage");
d1.set(h1, damage2);
Method attackHeroMethod = c.getMethod("attackHero", Hero.class);
attackHeroMethod.invoke(h, h1);
}catch (Exception e){
e.printStackTrace();
}
}
}
反射有什么用
首先准备两个业务类,这两个业务类很简单,就是各自都有一个业务方法,分别打印不同的字符串
public class Service1 {
public void doService1(){
System.out.println("业务方法1");
}
}
public class Service2 {
public void doService2(){
System.out.println("业务方法2");
}
}
当需要从第一个业务方法切换到第二个业务方法的时候,使用非反射方式,必须修改代码,并且重新编译运行,才可以达到效果
public class Test {
public static void main(String[] args) {
// new Service1().doService1();
new Service2().doService2();
}
}
反射可以简化这个过程
使用反射方式,首先准备一个配置文件,就叫做spring.txt吧, 放在src目录下。 里面存放的是类的名称,和要调用的方法名。
在测试类Test中,首先取出类名称和方法名,然后通过反射去调用这个方法。
当需要从调用第一个业务方法,切换到调用第二个业务方法的时候,不需要修改一行代码,也不需要重新编译,只需要修改配置文件spring.txt,再运行即可。
这也是Spring框架的最基本的原理,只是它做的更丰富,安全,健壮。
基本原理:取出配置文件的类名称和方法名,通过反射调用这个方法,这样就不需要修改代码
package com.relect;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Properties;
public class Test {
public static void main(String[] args) throws Exception, IOException {
// TODO 自动生成的方法存根
File SpringConfig=new File("D:\eclipse\eclipse-workspace\反射\src\com\relect\spring.txt");
Properties spring=new Properties();
spring.load(new FileInputStream(SpringConfig));
String className = (String) spring.get("class");
String methodName = (String)spring.get("method");
//根据类名称获取类对象
Class clazz = Class.forName(className);
//根据方法名称,获取方法对象
Method m = clazz.getMethod(methodName);
//获取构造器
Constructor c = clazz.getConstructor();
//根据构造器,实例化出对象
Object service = c.newInstance();
//调用对象的指定方法
m.invoke(service);
}
}



