此处我会提供代码来说明
以前的正向操作:实例化对象:通过类的构造方法实例化对象。
反射:根据对象来取得对象的来源信息,通过实例化对象获取创建该对象的类。
获得class类对象的三种方法:
(1)在java.lang.Object类中有一个方法:getClass()方法,所有的java对象都可以调用该方法,返回该对象所属类对应的Class对象。
(2)类名.class 调用某个类的class属性来获取该类对应的Class对象。例:Student.class将返回Student类对应的Class对象。
(3)使用Class类的forName(String className)静态方法。public static Class<?> forName(String className) throws ClassNotFoundException。
注:同一个类加载器中,一个类的Class对象只有一个。
public static void main(String[] args) {
Date date=new Date();// 创建对象
//class 关键字 Class 类型
Class class1=date.getClass(); //1.getClass()方法
System.out.println(class1);
System.out.println(date instanceof Date); //若date是Date类,返回true,否则返回false
Class class2=Date.class; //2.通过属性来获取对象.类名.class
System.out.println(class2);
//通过Class.forName 类的全限定名
try{
Class class3=Class.forName("java.util.Date"); //3.forName()
System.out.println(class3);
System.out.println("=====>");
//当前三个Class对象都是描述iava.util.Date
System.out.println(class1==class2);
System.out.println(class2==class3);
}catch(ClassNotFoundException e){
e.printStackTrace();
}
}
三个对象描述的都是同一个
运行结果
工厂模式:
传统工厂模式:每增加⼀个接⼝的⼦类就需要修改⼯⼚类,违背了OCP原则
通过反射处理,就可以解决该问题
在此之前,我们所需要了解到的知识点:
(1)类可以通过构造方法实例化对象
(2)通过反射创建类的实例化对象
a.通过类的Class对象的newInstance()方法获取实例化对象(类具有无参数的构造方法)
b.类的Class对象获取构造方法的Constructor对象,通过Constructor的newInstance(…)实例化对象
工厂的实现:
interface Clothes{
void wear();
}
class Shirt implements Clothes{
@Override
public void wear() {
System.out.println("穿衬衫");
}
}
class Skirt implements Clothes{
@Override
public void wear() {
System.out.println("穿短袖");
}
}
class Pants implements Clothes{
@Override
public void wear() {
System.out.println("穿牛仔裤");
}
}
class ClothesFactory{
private ClothesFactory(){
}
public static Clothes getClothesInstance(String className){ //工厂返回的是接口类型
//new->具体类型耦合
try{
Class class1=Class.forName(className);
return (Clothes)class1.newInstance(); //获取实例化对象
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
throw new RuntimeException("Factory生产不了"+className);
}
}
public class Factory {
public static void main(String[] args) {
Clothes clothes=ClothesFactory.getClothesInstance("com.zh.reflect.Skirt");
clothes.wear();
}
}
引⼊反射后,每当新增接⼝⼦类,⽆需去修改⼯⼚类代码就可以很⽅便的进⾏接⼝⼦类扩容。
反射与类的操作:
1.取得父类信息
getPackage().getName():取得包名
getSuperclass().getName();取得类的全限定名 包名.类名
getSimpleName():只取得类名
getInterfaces():取得接口
代码实现:
public static void main(String[] args) {
Class class1 = Test1.class; //类名.class
System.out.println("包名:" + class1.getPackage().getName());
System.out.println("父类:" + class1.getSuperclass().getName());//类的全限定名 包名.类名
System.out.println("父类:" + class1.getSuperclass().getSimpleName());//只是类名
System.out.println("========>");
System.out.println("接口: ");
Class[] interfaces = class1.getInterfaces();
for (Class cls : interfaces) {
System.out.println(cls.getName());
System.out.println(cls.getSimpleName());
}
}
接口以及实现接口的类和构造方法:
interface Clothes1{}
interface Message1{}
class Test1 implements Clothes1, Message1{
public Test1(Integer a, Integer b) { }
public Test1(Integer a, String b) { }
public Test1(Integer a) { }
public Test1() { }
}
结果:
2.Class类通过反射实例化类对象的时候,只能够调⽤类中的⽆参构造。如果现在类中没有⽆参构造则⽆法使⽤Class类调⽤,只能够通过明确的构造调⽤实例化处理。
通过Constructor的newInstance(…)实例化对象
具体实现如下:
代码实现:
public static void main(String[] args) {
//获取所有的构造方法
Class class1 = Test1.class; //类名.class
Constructor[] constructors=class1.getConstructors();
System.out.println("获取所有的构造方法");
for(Constructor c:constructors){
Class[] parameterCls=c.getParameterTypes();
String parameter= Arrays.toString(parameterCls);
System.out.println(c.getName()+"(" + parameter + ")");
}
System.out.println("获取指定的构造方法");
try{
Constructor constructor=class1.getConstructor(Integer.class,String.class);
System.out.println(constructor);
//通过Constructor实例化对象
//new Test(...)
Object object=constructor.newInstance(20,"zhanghao"); //实例化对象
System.out.println(object.getClass());
}
catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
运行结果:
3.反射调用普通方法:
getMethods():获取包括父类的所有方法
getDeclaredMethods():获取自己的所有方法
获取指定的方法:
步骤:
(1)用newInstance获取对象
(2)获取对象的方法,并且调用
Method method = class1.getMethod(“setName”, String.class);
Object returnVal = method.invoke(person, “zhanghao”);
此时返回的值是null,只是修改了,并没有传入值
(3)获取对象的方法,并且调用
Method getNameMethod = class1.getMethod(“getName”);
Object returnName = getNameMethod.invoke(person);
此时取值了,返回输入的值。
具体代码实现:
(1)父类和子类的属性,构造方法,普通方法实现
class Person {
private int age;
public String name;
public Person() {
}
public Person(int age, String name) {
this.age = age;
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
class Student extends Person {
private String school;
private String skill;
private LocalDateTime birthday;
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
public LocalDateTime getBirthday() {
return birthday;
}
public void setBirthday(LocalDateTime birthday) {
this.birthday = birthday;
}
@Override
public String toString() {
return "Student{" +
"school='" + school + '\'' +
", skill='" + skill + '\'' +
", birthday=" + birthday +
"} " + super.toString();
}
(2)获取方法的具体实现:
public static void main1(String[] args) {
Class class1 = Person.class;
System.out.println("获取包括父类的所有的方法:");
Method[] methods = class1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
System.out.println("=======>");
System.out.println("获取自己的所有的方法: ");
Method[] methods1 = class1.getDeclaredMethods();
for (Method method : methods1) {
System.out.println(method);
}
System.out.println("======>");
System.out.println("获取指定的方法: ");
try {
Person person = (Person) class1.newInstance(); //1.获取对象
System.out.println("before Person :" + person);
System.out.println("=======>");
//2.获取对象的方法,并且调用(修改)
Method method = class1.getMethod("setName", String.class);
Object returnVal = method.invoke(person, "zhanghao");
System.out.println(returnVal);//null
System.out.println("after Person: " + person);
System.out.println("====>");
//3.获取对象的方法,并且调用(取值)
Method getNameMethod = class1.getMethod("getName");
Object returnName = getNameMethod.invoke(person);
System.out.println(returnName);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
}
}
运行结果:
(4)反射调用属性
子类继承父类的所有结构,是否能否访问取决于访问修饰符
类中的所有属性⼀定在类对象实例化之后才会进⾏空间分配,所以此时如果要想调⽤类的属性,必须保证有实例化对象。
1.getFields():返回父类和子类的公开属性
2.getDeclaredFields():返回子类的所有属性
3.public Method getDeclaredMethod(String nameClass<?>… parameterTypes):获取类中名称指定的属性,获得指定属性的具体实现看如下代码
public static void main(String[] args) {
Class class1=Student.class;
System.out.println("获取属性");
System.out.println("1.====>");
System.out.println("父类和子类的公开属性: ");
Field[] fileds=class1.getFields() ;//返回父类和子类的公开属性
for(Field field:fileds){
System.out.println(field.getType() + " " + field.getName());
System.out.println(field);
}
System.out.println("2====>");
System.out.println("子类的所有属性");
Field[] fields1=class1.getDeclaredFields() ;//返回子类的所有属性
for(Field field:fields1){
System.out.println(field.getType() + " " + field.getName());
System.out.println(field);
}
System.out.println("=====>");
System.out.println("获取指定属性");
try {
Field skillField = class1.getDeclaredField("skill");
System.out.println(skillField);
//使用属性
Student student = new Student();
student.setSkill("yuwen,shuxue,english");
student.getSkill();
//true表示可以访问私有的属性
skillField.setAccessible(true);
//get 获取
Object skillValue = skillField.get(student);
System.out.println(skillValue);
//set 修改
skillField.set(student, "pysh"); //修改
System.out.println(student);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
运行结果: