1 - 获取Class的三种方式
1.1 - Class.forName()
默认从src根路径开始获取class实例化对象
//字符串是完整的类名,包括包名
c1 = Class.forName("java.lang.String");
1.2 - getClass()
public static void main(String[] args) {
String s = "abc";
Student student = new Student("小A");
Class c = s.getClass();
Class stu = student.getClass();
System.out.println(c);
System.out.println(stu);
}
1.3 - Class属性
任何类型都有class属性
Class s = String.class;
2 - 实例化对象
Object o = class.newInstance();
newInstance()调用的是无参数构造方法。如果无参被有参构造覆盖,会报错
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class c=null;
try {
c = Class.forName("javase/Student.java");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
Object o = c.newInstance();
}
newInstance()和new 对象有什么区别?
反射机制更加灵活。如果想要创建不同的对象,只需要在配置文件中更改类名就可以创建不同的对象,而不用修改代码
public static void main(String[] args) throws IllegalAccessException, InstantiationException, IOException, ClassNotFoundException {
//注意这里的默认路径是项目根目录,不是src
FileReader reader = new FileReader("src\\javase\\reflect.properties");
Properties pro = new Properties();
//将文件中的数据加载到properties中
pro.load(reader);
reader.close();
String className = pro.getProperty("className");
//通过pro中的value获取类
//className=javase.Student
Class c = Class.forName(className);
//通过类实例化对象
Object o = c.newInstance();
System.out.println(o);
}
如果想创建不同的类,只需要修改配置文件中的className对应的value即可
3 - 反射Field
获取public修饰的属性:getFields()
获取所有属性:getDeclaredFields()
获取名字:class/field.getName() getSimpleName()
获取属性类型名:field.getType().getName()
获取修饰符列表:getModifiers() 修饰符可能不止一个
public static void main(String[] args) {
Class stuclass = Class.forName("javase.reflect.Student");
//获取public修饰的属性
Field[] fields = stuclass.getFields();
for (Field f:fields
) {
System.out.println("共有属性有:"+f.getName());
}
//获取所有属性
Field[] allfields = stuclass.getDeclaredFields();
for (Field f:allfields
) {
//获取修饰符
String modifiers = Modifier.toString(f.getModifiers());
//获取类型
String typeName = f.getType().getSimpleName();
//获取名字
String fName = f.getName();
System.out.println(modifiers+" "+typeName+" "+fName);
}
}
访问属性对象
修改属性值:field.set(obj,vaule)
获取属性值:field.get(obj)
访问私有属性需要打破封装field.setAccessiable(true)
public static void main(String[] args) {
Class stuclass = Class.forName("javase.reflect.Student");
Object obj = stuclass.newInstance();
//获取属性
//这样写的灵活性在于这个属性名可以放在配置文件中
//以后的框架都是采用这种方式
Field noField = stuclass.getDeclaredField("no");
//赋值三要素:对象obj 属性noField 值2
noField.set(obj,2);
//读取属性的值
//以前是对象.属性 现在是属性.get(对象)
System.out.println(noField.get(obj));
}
访问私有属性
Field nameField = stuclass.getDeclaredField("name");
nameField.setAccessible(true);
nameField.set(obj,"小红");
System.out.println(nameField.get(obj));
4 - 反射Method
获取所有方法:Method[] methods=class.getDeclaredMethod()
获取返回值类型:Class class = method.getReturnType()
获取参数列表:Class[] class = method.getParameterTypes()
public static void main(String[] args) throws ClassNotFoundException {
Class stuclass = Class.forName("javase.reflect.Student");
//获取类的所有方法
Method[] methods = stuclass.getDeclaredMethods();
//获取方法返回值类型
for (Method m:methods
) {
System.out.println("返回值类型:"+m.getReturnType().getSimpleName());
Class[] paras =m.getParameterTypes();
System.out.print("参数列表有:");
for (Class c:paras
) {
System.out.print(c.getSimpleName()+"\t");
}
}
}
反射调用方法
确定一个方法需要:方法名和参数列表
因为方法可以重载
class.getDeclaredMethod(className,参数列表)
调用方法的要素:
对象,方法名 参数 返回值
value = method.invoke(对象,实参)
public static void main(String[] args) {
Class stuclass = Class.forName("javase.reflect.Student");
//获取对应的方法
Method method = stuclass.getDeclaredMethod("dohomework", Student.class, String.class);
//创建对象
Object obj = stuclass.newInstance();
Field name = stuclass.getDeclaredField("name");
name.setAccessible(true);
name.set(obj,"张三");
//调方法
method.invoke(obj,obj,"9点");
}
5 - 反射Constructor
调用构造方法创建对象
constructor.newInstance()
区分构造方法靠形参
public static void main(String[] args) {
Class stuclass = Class.forName("javase.reflect.Student");
Constructor con = stuclass.getDeclaredConstructor(Integer.class,String.class);
Object obj = con.newInstance(1,"sam");
System.out.println(obj);
}